mutant 0.9.10 → 0.10.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 (254) hide show
  1. checksums.yaml +4 -4
  2. data/bin/mutant +16 -11
  3. data/lib/mutant.rb +8 -4
  4. data/lib/mutant/bootstrap.rb +14 -1
  5. data/lib/mutant/cli.rb +9 -162
  6. data/lib/mutant/cli/command.rb +196 -0
  7. data/lib/mutant/cli/command/root.rb +13 -0
  8. data/lib/mutant/cli/command/run.rb +151 -0
  9. data/lib/mutant/cli/command/subscription.rb +54 -0
  10. data/lib/mutant/expression.rb +0 -1
  11. data/lib/mutant/isolation.rb +1 -1
  12. data/lib/mutant/isolation/fork.rb +2 -2
  13. data/lib/mutant/isolation/none.rb +1 -1
  14. data/lib/mutant/license.rb +9 -35
  15. data/lib/mutant/license/subscription.rb +31 -9
  16. data/lib/mutant/license/subscription/commercial.rb +2 -4
  17. data/lib/mutant/license/subscription/opensource.rb +7 -7
  18. data/lib/mutant/matcher/config.rb +2 -0
  19. data/lib/mutant/meta/example.rb +16 -4
  20. data/lib/mutant/meta/example/dsl.rb +33 -16
  21. data/lib/mutant/meta/example/verification.rb +70 -28
  22. data/lib/mutant/minitest/coverage.rb +53 -0
  23. data/lib/mutant/mutator/node.rb +2 -2
  24. data/lib/mutant/mutator/node/block_pass.rb +29 -0
  25. data/lib/mutant/mutator/node/{dstr.rb → dynamic_literal.rb} +7 -5
  26. data/lib/mutant/mutator/node/index.rb +4 -4
  27. data/lib/mutant/mutator/node/literal/range.rb +5 -2
  28. data/lib/mutant/mutator/node/named_value/variable_assignment.rb +1 -1
  29. data/lib/mutant/mutator/node/noop.rb +1 -1
  30. data/lib/mutant/mutator/node/op_asgn.rb +15 -1
  31. data/lib/mutant/mutator/node/send.rb +25 -1
  32. data/lib/mutant/mutator/node/send/attribute_assignment.rb +1 -0
  33. data/lib/mutant/reporter/cli/printer/isolation_result.rb +9 -3
  34. data/lib/mutant/subject/method/instance.rb +1 -1
  35. data/lib/mutant/version.rb +1 -1
  36. metadata +18 -336
  37. data/.github/workflows/ci.yml +0 -121
  38. data/.gitignore +0 -38
  39. data/.rspec +0 -5
  40. data/.rubocop.yml +0 -210
  41. data/Changelog.md +0 -87
  42. data/Gemfile +0 -7
  43. data/Gemfile.lock +0 -107
  44. data/Gemfile.shared +0 -10
  45. data/README.md +0 -199
  46. data/Rakefile +0 -5
  47. data/config/devtools.yml +0 -2
  48. data/config/reek.yml +0 -139
  49. data/config/yardstick.yml +0 -2
  50. data/docs/commercial-support.md +0 -14
  51. data/docs/concurrency.md +0 -39
  52. data/docs/incremental.md +0 -76
  53. data/docs/known-problems.md +0 -30
  54. data/docs/limitations.md +0 -50
  55. data/docs/mutant-minitest.md +0 -149
  56. data/docs/mutant-rspec.md +0 -130
  57. data/docs/nomenclature.md +0 -82
  58. data/docs/reading-reports.md +0 -74
  59. data/lib/mutant/mutator/node/dsym.rb +0 -22
  60. data/meta/and.rb +0 -13
  61. data/meta/and_asgn.rb +0 -14
  62. data/meta/array.rb +0 -27
  63. data/meta/begin.rb +0 -20
  64. data/meta/block.rb +0 -199
  65. data/meta/block_pass.rb +0 -8
  66. data/meta/blockarg.rb +0 -10
  67. data/meta/break.rb +0 -9
  68. data/meta/case.rb +0 -217
  69. data/meta/casgn.rb +0 -25
  70. data/meta/cbase.rb +0 -8
  71. data/meta/class.rb +0 -12
  72. data/meta/const.rb +0 -17
  73. data/meta/csend.rb +0 -10
  74. data/meta/cvar.rb +0 -7
  75. data/meta/cvasgn.rb +0 -9
  76. data/meta/date.rb +0 -59
  77. data/meta/def.rb +0 -196
  78. data/meta/defined.rb +0 -9
  79. data/meta/dstr.rb +0 -13
  80. data/meta/dsym.rb +0 -14
  81. data/meta/ensure.rb +0 -8
  82. data/meta/false.rb +0 -7
  83. data/meta/file.rb +0 -5
  84. data/meta/float.rb +0 -37
  85. data/meta/gvar.rb +0 -7
  86. data/meta/gvasgn.rb +0 -9
  87. data/meta/hash.rb +0 -20
  88. data/meta/if.rb +0 -72
  89. data/meta/index.rb +0 -133
  90. data/meta/indexasgn.rb +0 -31
  91. data/meta/int.rb +0 -18
  92. data/meta/ivar.rb +0 -8
  93. data/meta/ivasgn.rb +0 -22
  94. data/meta/kwarg.rb +0 -10
  95. data/meta/kwbegin.rb +0 -8
  96. data/meta/kwoptarg.rb +0 -13
  97. data/meta/lambda.rb +0 -23
  98. data/meta/line.rb +0 -5
  99. data/meta/lvar.rb +0 -16
  100. data/meta/lvasgn.rb +0 -24
  101. data/meta/masgn.rb +0 -7
  102. data/meta/match_current_line.rb +0 -14
  103. data/meta/next.rb +0 -10
  104. data/meta/nil.rb +0 -5
  105. data/meta/nthref.rb +0 -14
  106. data/meta/op_assgn.rb +0 -17
  107. data/meta/or.rb +0 -13
  108. data/meta/or_asgn.rb +0 -50
  109. data/meta/range.rb +0 -65
  110. data/meta/redo.rb +0 -5
  111. data/meta/regexp.rb +0 -80
  112. data/meta/regopt.rb +0 -10
  113. data/meta/rescue.rb +0 -84
  114. data/meta/return.rb +0 -16
  115. data/meta/sclass.rb +0 -12
  116. data/meta/self.rb +0 -7
  117. data/meta/send.rb +0 -600
  118. data/meta/str.rb +0 -7
  119. data/meta/super.rb +0 -27
  120. data/meta/sym.rb +0 -8
  121. data/meta/true.rb +0 -7
  122. data/meta/until.rb +0 -16
  123. data/meta/while.rb +0 -24
  124. data/meta/yield.rb +0 -9
  125. data/mutant-minitest.gemspec +0 -22
  126. data/mutant-rspec.gemspec +0 -22
  127. data/mutant.gemspec +0 -44
  128. data/mutant.sh +0 -12
  129. data/mutant.yml +0 -6
  130. data/spec/integration/mutant/corpus_spec.rb +0 -15
  131. data/spec/integration/mutant/isolation/fork_spec.rb +0 -28
  132. data/spec/integration/mutant/minitest_spec.rb +0 -11
  133. data/spec/integration/mutant/null_spec.rb +0 -16
  134. data/spec/integration/mutant/rspec_spec.rb +0 -15
  135. data/spec/integration/mutant/test_mutator_handles_types_spec.rb +0 -9
  136. data/spec/integrations.yml +0 -63
  137. data/spec/shared/framework_integration_behavior.rb +0 -70
  138. data/spec/shared/method_matcher_behavior.rb +0 -47
  139. data/spec/spec_helper.rb +0 -90
  140. data/spec/support/corpus.rb +0 -318
  141. data/spec/support/file_system.rb +0 -62
  142. data/spec/support/ice_nine_config.rb +0 -10
  143. data/spec/support/ruby_vm.rb +0 -84
  144. data/spec/support/shared_context.rb +0 -169
  145. data/spec/support/xspec.rb +0 -183
  146. data/spec/unit/mutant/ast/find_metaclass_containing_spec.rb +0 -64
  147. data/spec/unit/mutant/ast/meta/optarg_spec.rb +0 -24
  148. data/spec/unit/mutant/ast/meta/send/proc_predicate_spec.rb +0 -30
  149. data/spec/unit/mutant/ast/meta/send/receiver_possible_top_level_const_predicate_spec.rb +0 -39
  150. data/spec/unit/mutant/ast/meta/send_spec.rb +0 -42
  151. data/spec/unit/mutant/ast/named_children_spec.rb +0 -89
  152. data/spec/unit/mutant/ast/sexp_spec.rb +0 -38
  153. data/spec/unit/mutant/ast_spec.rb +0 -57
  154. data/spec/unit/mutant/bootstrap_spec.rb +0 -216
  155. data/spec/unit/mutant/cli_spec.rb +0 -305
  156. data/spec/unit/mutant/clock_monotonic_spec.rb +0 -52
  157. data/spec/unit/mutant/config_spec.rb +0 -126
  158. data/spec/unit/mutant/context_spec.rb +0 -111
  159. data/spec/unit/mutant/env_spec.rb +0 -229
  160. data/spec/unit/mutant/expression/method_spec.rb +0 -62
  161. data/spec/unit/mutant/expression/methods_spec.rb +0 -66
  162. data/spec/unit/mutant/expression/namespace/exact_spec.rb +0 -28
  163. data/spec/unit/mutant/expression/namespace/recursive_spec.rb +0 -66
  164. data/spec/unit/mutant/expression/parser_spec.rb +0 -65
  165. data/spec/unit/mutant/expression_spec.rb +0 -45
  166. data/spec/unit/mutant/integration/rspec_spec.rb +0 -201
  167. data/spec/unit/mutant/integration_spec.rb +0 -150
  168. data/spec/unit/mutant/isolation/fork_spec.rb +0 -309
  169. data/spec/unit/mutant/isolation/none_spec.rb +0 -23
  170. data/spec/unit/mutant/isolation/result_spec.rb +0 -73
  171. data/spec/unit/mutant/license_spec.rb +0 -305
  172. data/spec/unit/mutant/loader_spec.rb +0 -79
  173. data/spec/unit/mutant/matcher/chain_spec.rb +0 -26
  174. data/spec/unit/mutant/matcher/compiler_spec.rb +0 -0
  175. data/spec/unit/mutant/matcher/config_spec.rb +0 -47
  176. data/spec/unit/mutant/matcher/filter_spec.rb +0 -22
  177. data/spec/unit/mutant/matcher/method/instance_spec.rb +0 -164
  178. data/spec/unit/mutant/matcher/method/metaclass_spec.rb +0 -108
  179. data/spec/unit/mutant/matcher/method/singleton_spec.rb +0 -90
  180. data/spec/unit/mutant/matcher/methods/instance_spec.rb +0 -54
  181. data/spec/unit/mutant/matcher/methods/metaclass_spec.rb +0 -62
  182. data/spec/unit/mutant/matcher/methods/singleton_spec.rb +0 -51
  183. data/spec/unit/mutant/matcher/namespace_spec.rb +0 -39
  184. data/spec/unit/mutant/matcher/null_spec.rb +0 -12
  185. data/spec/unit/mutant/matcher/scope_spec.rb +0 -45
  186. data/spec/unit/mutant/matcher/static_spec.rb +0 -13
  187. data/spec/unit/mutant/matcher_spec.rb +0 -102
  188. data/spec/unit/mutant/meta/example/dsl_spec.rb +0 -108
  189. data/spec/unit/mutant/meta/example/verification_spec.rb +0 -154
  190. data/spec/unit/mutant/meta/example_spec.rb +0 -34
  191. data/spec/unit/mutant/mutation_spec.rb +0 -140
  192. data/spec/unit/mutant/mutator/node_spec.rb +0 -47
  193. data/spec/unit/mutant/mutator_spec.rb +0 -21
  194. data/spec/unit/mutant/parallel/driver_spec.rb +0 -126
  195. data/spec/unit/mutant/parallel/source/array_spec.rb +0 -57
  196. data/spec/unit/mutant/parallel/worker_spec.rb +0 -206
  197. data/spec/unit/mutant/parallel_spec.rb +0 -115
  198. data/spec/unit/mutant/parser_spec.rb +0 -26
  199. data/spec/unit/mutant/range_spec.rb +0 -141
  200. data/spec/unit/mutant/registry_spec.rb +0 -74
  201. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +0 -17
  202. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +0 -85
  203. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +0 -45
  204. data/spec/unit/mutant/reporter/cli/printer/isolation_result_spec.rb +0 -132
  205. data/spec/unit/mutant/reporter/cli/printer/mutation_progress_result_spec.rb +0 -25
  206. data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +0 -153
  207. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +0 -45
  208. data/spec/unit/mutant/reporter/cli/printer/subject_progress_spec.rb +0 -36
  209. data/spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb +0 -44
  210. data/spec/unit/mutant/reporter/cli/printer/test_result_spec.rb +0 -16
  211. data/spec/unit/mutant/reporter/cli/printer_spec.rb +0 -163
  212. data/spec/unit/mutant/reporter/cli_spec.rb +0 -137
  213. data/spec/unit/mutant/reporter/null_spec.rb +0 -14
  214. data/spec/unit/mutant/reporter/sequence_spec.rb +0 -31
  215. data/spec/unit/mutant/repository/diff/ranges_spec.rb +0 -180
  216. data/spec/unit/mutant/repository/diff_spec.rb +0 -122
  217. data/spec/unit/mutant/repository/subject_filter_spec.rb +0 -30
  218. data/spec/unit/mutant/require_highjack_spec.rb +0 -73
  219. data/spec/unit/mutant/result/class_methods_spec.rb +0 -51
  220. data/spec/unit/mutant/result/env_spec.rb +0 -161
  221. data/spec/unit/mutant/result/mutation_spec.rb +0 -70
  222. data/spec/unit/mutant/result/subject_spec.rb +0 -111
  223. data/spec/unit/mutant/result/test_spec.rb +0 -14
  224. data/spec/unit/mutant/result_spec.rb +0 -33
  225. data/spec/unit/mutant/runner/sink_spec.rb +0 -174
  226. data/spec/unit/mutant/runner_spec.rb +0 -121
  227. data/spec/unit/mutant/selector/expression_spec.rb +0 -62
  228. data/spec/unit/mutant/selector/null_spec.rb +0 -17
  229. data/spec/unit/mutant/subject/method/instance_spec.rb +0 -276
  230. data/spec/unit/mutant/subject/method/metaclass_spec.rb +0 -63
  231. data/spec/unit/mutant/subject/method/singleton_spec.rb +0 -61
  232. data/spec/unit/mutant/subject_spec.rb +0 -93
  233. data/spec/unit/mutant/transform/array_spec.rb +0 -92
  234. data/spec/unit/mutant/transform/bool_spec.rb +0 -63
  235. data/spec/unit/mutant/transform/error_spec.rb +0 -132
  236. data/spec/unit/mutant/transform/exception_spec.rb +0 -44
  237. data/spec/unit/mutant/transform/hash_spec.rb +0 -236
  238. data/spec/unit/mutant/transform/index_spec.rb +0 -92
  239. data/spec/unit/mutant/transform/named_spec.rb +0 -49
  240. data/spec/unit/mutant/transform/primitive_spec.rb +0 -56
  241. data/spec/unit/mutant/transform/sequence_spec.rb +0 -98
  242. data/spec/unit/mutant/util/one_spec.rb +0 -22
  243. data/spec/unit/mutant/warnings_spec.rb +0 -89
  244. data/spec/unit/mutant/world_spec.rb +0 -63
  245. data/spec/unit/mutant/zombifier_spec.rb +0 -122
  246. data/test_app/.rspec +0 -1
  247. data/test_app/Gemfile.minitest +0 -6
  248. data/test_app/Gemfile.rspec3.8 +0 -7
  249. data/test_app/lib/test_app.rb +0 -114
  250. data/test_app/lib/test_app/literal.rb +0 -35
  251. data/test_app/lib/test_app/metaclasses.rb +0 -108
  252. data/test_app/spec/spec_helper.rb +0 -9
  253. data/test_app/spec/unit/test_app/literal_spec.rb +0 -20
  254. data/test_app/test/unit/test_app/literal_test.rb +0 -16
@@ -1,309 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # The fork isolation is all about managing a series of systemcalls with proper error handling
4
- #
5
- # So creating a unit spec for this is challenging. Especially under mutation testing.
6
- # Hence we even have to implement our own message expectation mechanism, as rspec build in
7
- # expectations are not able to correctly specify a sequence of expectations where a specific
8
- # message is send twice.
9
- #
10
- # Also our replacement for rspec-expectations used here allows easier deduplication.
11
- RSpec.describe Mutant::Isolation::Fork do
12
- let(:block_return) { instance_double(Object, :block_return) }
13
- let(:block_return_blob) { instance_double(String, :block_return_blob) }
14
- let(:io) { class_double(IO) }
15
- let(:isolated_block) { -> { block_return } }
16
- let(:log_fragment) { 'log message' }
17
- let(:log_reader) { instance_double(IO, :log_reader) }
18
- let(:log_writer) { instance_double(IO, :log_writer) }
19
- let(:marshal) { class_double(Marshal) }
20
- let(:pid) { class_double(Integer) }
21
- let(:process) { class_double(Process) }
22
- let(:result_fragment) { 'result body' }
23
- let(:result_reader) { instance_double(IO, :result_reader) }
24
- let(:result_writer) { instance_double(IO, :result_writer) }
25
- let(:stderr) { instance_double(IO, :stderr) }
26
- let(:stdout) { instance_double(IO, :stdout) }
27
-
28
- let(:status_success) do
29
- instance_double(Process::Status, success?: true)
30
- end
31
-
32
- let(:world) do
33
- instance_double(
34
- Mutant::World,
35
- io: io,
36
- marshal: marshal,
37
- process: process,
38
- stderr: stderr,
39
- stdout: stdout
40
- )
41
- end
42
-
43
- let(:fork_success) do
44
- {
45
- receiver: process,
46
- selector: :fork,
47
- reaction: {
48
- yields: [],
49
- return: pid
50
- }
51
- }
52
- end
53
-
54
- let(:child_wait) do
55
- {
56
- receiver: process,
57
- selector: :wait2,
58
- arguments: [pid],
59
- reaction: {
60
- return: [pid, status_success]
61
- }
62
- }
63
- end
64
-
65
- def close(descriptor)
66
- {
67
- receiver: descriptor,
68
- selector: :close
69
- }
70
- end
71
-
72
- let(:load_success) do
73
- {
74
- receiver: marshal,
75
- selector: :load,
76
- arguments: [result_fragment],
77
- reaction: {
78
- return: block_return
79
- }
80
- }
81
- end
82
-
83
- let(:read_fragments) do
84
- [
85
- {
86
- receiver: io,
87
- selector: :select,
88
- arguments: [[log_reader, result_reader]],
89
- reaction: { return: [[log_reader, result_reader], []] }
90
- },
91
- {
92
- receiver: log_reader,
93
- selector: :eof?,
94
- reaction: { return: false }
95
- },
96
- {
97
- receiver: log_reader,
98
- selector: :read_nonblock,
99
- arguments: [4096],
100
- reaction: { return: log_fragment }
101
- },
102
- {
103
- receiver: result_reader,
104
- selector: :eof?,
105
- reaction: { return: false }
106
- },
107
- {
108
- receiver: result_reader,
109
- selector: :read_nonblock,
110
- arguments: [4096],
111
- reaction: { return: result_fragment }
112
- },
113
- {
114
- receiver: io,
115
- selector: :select,
116
- arguments: [[log_reader, result_reader]],
117
- reaction: { return: [[log_reader, result_reader], []] }
118
- },
119
- {
120
- receiver: log_reader,
121
- selector: :eof?,
122
- reaction: { return: true }
123
- },
124
- {
125
- receiver: result_reader,
126
- selector: :eof?,
127
- reaction: { return: true }
128
- }
129
- ]
130
- end
131
-
132
- let(:killfork) do
133
- [
134
- # Inside the killfork
135
- {
136
- receiver: log_reader,
137
- selector: :close
138
- },
139
- {
140
- receiver: result_reader,
141
- selector: :close
142
- },
143
- {
144
- receiver: stderr,
145
- selector: :reopen,
146
- arguments: [log_writer]
147
- },
148
- {
149
- receiver: stdout,
150
- selector: :reopen,
151
- arguments: [log_writer]
152
- },
153
- {
154
- receiver: marshal,
155
- selector: :dump,
156
- arguments: [block_return],
157
- reaction: {
158
- return: block_return_blob
159
- }
160
- },
161
- {
162
- receiver: result_writer,
163
- selector: :syswrite,
164
- arguments: [block_return_blob]
165
- },
166
- close(result_writer),
167
- close(log_writer)
168
- ]
169
- end
170
-
171
- describe '#call' do
172
- subject { described_class.new(world) }
173
-
174
- def apply
175
- subject.call(&isolated_block)
176
- end
177
-
178
- let(:prefork_expectations) do
179
- [
180
- {
181
- receiver: io,
182
- selector: :pipe,
183
- arguments: [binmode: true],
184
- reaction: {
185
- yields: [[result_reader, result_writer]]
186
- }
187
- },
188
- {
189
- receiver: io,
190
- selector: :pipe,
191
- arguments: [binmode: true],
192
- reaction: {
193
- yields: [[log_reader, log_writer]]
194
- }
195
- }
196
- ]
197
- end
198
-
199
- context 'when no IO operation fails' do
200
- let(:expectations) do
201
- [
202
- *prefork_expectations,
203
- fork_success,
204
- *killfork,
205
- close(result_writer),
206
- *read_fragments,
207
- load_success,
208
- child_wait
209
- ].map(&XSpec::MessageExpectation.method(:parse))
210
- end
211
-
212
- specify do
213
- XSpec::ExpectationVerifier.verify(self, expectations) do
214
- expect(apply).to eql(Mutant::Isolation::Result::Success.new(block_return, log_fragment))
215
- end
216
- end
217
- end
218
-
219
- context 'when expected exception was raised when loading result' do
220
- let(:exception) { ArgumentError.new }
221
-
222
- let(:expectations) do
223
- [
224
- *prefork_expectations,
225
- fork_success,
226
- *killfork,
227
- close(result_writer),
228
- *read_fragments,
229
- {
230
- receiver: marshal,
231
- selector: :load,
232
- arguments: [result_fragment],
233
- reaction: {
234
- exception: exception
235
- }
236
- },
237
- child_wait
238
- ].map(&XSpec::MessageExpectation.method(:parse))
239
- end
240
-
241
- specify do
242
- XSpec::ExpectationVerifier.verify(self, expectations) do
243
- expect(apply).to eql(Mutant::Isolation::Result::Exception.new(exception))
244
- end
245
- end
246
- end
247
-
248
- context 'when fork fails' do
249
- let(:result_class) { described_class::ForkError }
250
-
251
- let(:expectations) do
252
- [
253
- *prefork_expectations,
254
- {
255
- receiver: process,
256
- selector: :fork,
257
- reaction: {
258
- return: nil
259
- }
260
- }
261
- ].map(&XSpec::MessageExpectation.method(:parse))
262
- end
263
-
264
- specify do
265
- XSpec::ExpectationVerifier.verify(self, expectations) do
266
- expect(apply).to eql(result_class.new)
267
- end
268
- end
269
- end
270
-
271
- context 'when child exits nonzero' do
272
- let(:status_error) do
273
- instance_double(Process::Status, success?: false)
274
- end
275
-
276
- let(:expected_result) do
277
- Mutant::Isolation::Result::ErrorChain.new(
278
- described_class::ChildError.new(status_error, log_fragment),
279
- Mutant::Isolation::Result::Success.new(block_return, log_fragment)
280
- )
281
- end
282
-
283
- let(:expectations) do
284
- [
285
- *prefork_expectations,
286
- fork_success,
287
- *killfork,
288
- close(result_writer),
289
- *read_fragments,
290
- load_success,
291
- {
292
- receiver: process,
293
- selector: :wait2,
294
- arguments: [pid],
295
- reaction: {
296
- return: [pid, status_error]
297
- }
298
- }
299
- ].map(&XSpec::MessageExpectation.method(:parse))
300
- end
301
-
302
- specify do
303
- XSpec::ExpectationVerifier.verify(self, expectations) do
304
- expect(apply).to eql(expected_result)
305
- end
306
- end
307
- end
308
- end
309
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Mutant::Isolation::None do
4
- describe '.call' do
5
- let(:object) { described_class.new }
6
-
7
- context 'without exception' do
8
- it 'returns success result' do
9
- expect(object.call { :foo })
10
- .to eql(Mutant::Isolation::Result::Success.new(:foo))
11
- end
12
- end
13
-
14
- context 'with exception' do
15
- let(:exception) { RuntimeError.new('foo') }
16
-
17
- it 'returns error result' do
18
- expect(object.call { fail exception })
19
- .to eql(Mutant::Isolation::Result::Exception.new(exception))
20
- end
21
- end
22
- end
23
- end
@@ -1,73 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Mutant::Isolation::Result do
4
- describe '#success?' do
5
- let(:value) { double('Object') }
6
-
7
- def apply
8
- effective_class.new(value).success?
9
- end
10
-
11
- context 'on success instance' do
12
- let(:effective_class) { described_class::Success }
13
-
14
- it 'returns true' do
15
- expect(apply).to be(true)
16
- end
17
- end
18
-
19
- context 'on error instance' do
20
- let(:effective_class) { described_class::Exception }
21
-
22
- it 'returns false' do
23
- expect(apply).to be(false)
24
- end
25
- end
26
- end
27
-
28
- describe '#add_error' do
29
- let(:other) { described_class::Success.new(object) }
30
- let(:value) { double('Object') }
31
- let(:object) { described_class::Success.new(value) }
32
-
33
- def apply
34
- object.add_error(other)
35
- end
36
-
37
- it 'returns chain instance' do
38
- expect(apply).to eql(described_class::ErrorChain.new(other, object))
39
- end
40
- end
41
-
42
- describe '#log' do
43
- let(:value) { double('Object') }
44
-
45
- def apply
46
- object.log
47
- end
48
-
49
- context 'on exception result' do
50
- let(:object) { described_class::Exception.new(value) }
51
-
52
- it 'returns the empty string' do
53
- expect(apply).to eql('')
54
- end
55
- end
56
-
57
- context 'on sucess result' do
58
- let(:object) { described_class::Success.new(value) }
59
-
60
- it 'returns the empty string' do
61
- expect(apply).to eql('')
62
- end
63
- end
64
-
65
- context 'on argument' do
66
- let(:object) { described_class::Success.new(value, 'foo') }
67
-
68
- it 'returns the empty string' do
69
- expect(apply).to eql('foo')
70
- end
71
- end
72
- end
73
- end
@@ -1,305 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Mutant::License do
4
- def apply
5
- described_class.apply(world)
6
- end
7
-
8
- let(:gem) { class_double(Gem, loaded_specs: loaded_specs) }
9
- let(:gem_method) { instance_double(Method) }
10
- let(:gem_path) { '/path/to/mutant-license' }
11
- let(:gem_pathname) { instance_double(Pathname) }
12
- let(:json) { class_double(JSON) }
13
- let(:kernel) { class_double(Kernel) }
14
- let(:license_pathname) { instance_double(Pathname) }
15
- let(:load_json) { true }
16
- let(:loaded_specs) { { 'mutant-license' => spec } }
17
- let(:path) { instance_double(Pathname) }
18
- let(:pathname) { class_double(Pathname) }
19
- let(:stderr) { instance_double(IO) }
20
-
21
- let(:spec) do
22
- instance_double(
23
- Gem::Specification,
24
- full_gem_path: gem_path
25
- )
26
- end
27
-
28
- let(:world) do
29
- instance_double(
30
- Mutant::World,
31
- gem: gem,
32
- gem_method: gem_method,
33
- json: json,
34
- kernel: kernel,
35
- pathname: pathname,
36
- stderr: stderr
37
- )
38
- end
39
-
40
- before do
41
- allow(gem_method).to receive_messages(call: undefined)
42
- allow(gem_pathname).to receive_messages(join: license_pathname)
43
- allow(json).to receive_messages(load: license_json)
44
- allow(kernel).to receive_messages(sleep: undefined)
45
- allow(pathname).to receive_messages(new: gem_pathname)
46
- allow(world).to receive(:capture_stdout, &commands.method(:fetch))
47
- end
48
-
49
- def self.it_fails(expected)
50
- it 'failse with exception' do
51
- expect { apply }.to raise_error(expected)
52
- end
53
- end
54
-
55
- def self.it_is_successful
56
- include_examples 'license.json lookup'
57
-
58
- it 'allows usage' do
59
- expect(apply).to eql(Mutant::Either::Right.new(true))
60
- end
61
- end
62
-
63
- # rubocop:disable Metrics/AbcSize
64
- # rubocop:disable Metrics/MethodLength
65
- def self.it_fails_with_message(expected)
66
- before do
67
- allow(stderr).to receive(:puts)
68
- end
69
-
70
- it 'performs IO in expected sequence' do
71
- expect(apply).to eql(Mutant::Either::Right.new(true))
72
-
73
- expect(gem_method)
74
- .to have_received(:call)
75
- .with('mutant-license', '~> 0.1.0')
76
- .ordered
77
-
78
- if load_json
79
- expect(json)
80
- .to have_received(:load)
81
- .with(license_pathname)
82
- .ordered
83
- end
84
-
85
- expect(stderr)
86
- .to have_received(:puts)
87
- .with(expected)
88
- .ordered
89
-
90
- expect(stderr)
91
- .to have_received(:puts)
92
- .with('[Mutant-License-Error]: Soft fail, continuing in 40 seconds')
93
- .ordered
94
-
95
- expect(stderr)
96
- .to have_received(:puts)
97
- .with('[Mutant-License-Error]: Next major version will enforce the license')
98
- .ordered
99
-
100
- expect(stderr)
101
- .to have_received(:puts)
102
- .with('[Mutant-License-Error]: See https://github.com/mbj/mutant#licensing')
103
- .ordered
104
-
105
- expect(kernel)
106
- .to have_received(:sleep)
107
- .with(40)
108
- .ordered
109
- end
110
- end
111
-
112
- shared_examples 'license.json lookup' do
113
- it 'builds correct license.json path' do
114
- apply
115
-
116
- expect(pathname).to have_received(:new).with(gem_path)
117
- expect(gem_pathname).to have_received(:join).with('license.json')
118
- end
119
- end
120
-
121
- describe 'on opensource license' do
122
- let(:repository) { 'github.com/mbj/mutant' }
123
-
124
- let(:git_remote) do
125
- <<~REMOTE
126
- origin\tgit@github.com:mbj/mutant (fetch)
127
- origin\tgit@github.com:mbj/mutant (push)
128
- REMOTE
129
- end
130
-
131
- let(:license_json) do
132
- {
133
- 'type' => 'oss',
134
- 'contents' => {
135
- 'repositories' => [repository]
136
- }
137
- }
138
- end
139
-
140
- let(:git_remote_result) { Mutant::Either::Right.new(git_remote) }
141
-
142
- let(:commands) do
143
- {
144
- %w[git remote --verbose] => git_remote_result
145
- }
146
- end
147
-
148
- context 'when repository is whitelisted' do
149
- context 'on ssh url without protocol and without suffx' do
150
- it_is_successful
151
- end
152
-
153
- context 'on ssh url with protocol and without suffx' do
154
- let(:git_remote) do
155
- <<~REMOTE
156
- origin\tssh://git@github.com/mbj/mutant (fetch)
157
- origin\tssh://git@github.com/mbj/mutant (push)
158
- REMOTE
159
- end
160
-
161
- it_is_successful
162
- end
163
-
164
- context 'on ssh url with protocol and suffx' do
165
- let(:git_remote) do
166
- <<~REMOTE
167
- origin\tssh://git@github.com/mbj/mutant.git (fetch)
168
- origin\tssh://git@github.com/mbj/mutant.git (push)
169
- REMOTE
170
- end
171
-
172
- it_is_successful
173
- end
174
-
175
- context 'on https url without suffix' do
176
- let(:git_remote) do
177
- <<~REMOTE
178
- origin\thttps://github.com/mbj/mutant (fetch)
179
- origin\thttps://github.com/mbj/mutant (push)
180
- REMOTE
181
- end
182
-
183
- it_is_successful
184
- end
185
-
186
- context 'on https url with .git suffix' do
187
- let(:git_remote) do
188
- <<~REMOTE
189
- origin\thttps://github.com/mbj/mutant.git (fetch)
190
- origin\thttps://github.com/mbj/mutant.git (push)
191
- REMOTE
192
- end
193
-
194
- it_is_successful
195
- end
196
- end
197
-
198
- context 'when repository is not whitelisted' do
199
- let(:repository) { 'github.com/mbj/unparser' }
200
-
201
- it_fails_with_message(<<~'MESSAGE')
202
- Can not validate opensource license.
203
- Licensed:
204
- github.com/mbj/unparser
205
- Present:
206
- github.com/mbj/mutant
207
- MESSAGE
208
- end
209
-
210
- context 'when git remote line cannot be parsed' do
211
- let(:git_remote) { "some-bad-remote-line\n" }
212
-
213
- it_fails 'Unmatched remote line: "some-bad-remote-line\n"'
214
- end
215
-
216
- context 'when git remote url cannot be parsed' do
217
- let(:git_remote) { "some-unknown\thttp://github.com/mbj/mutant (fetch)\n" }
218
-
219
- it_fails 'Unmatched git remote URL: "http://github.com/mbj/mutant"'
220
- end
221
- end
222
-
223
- describe 'on commercial license' do
224
- let(:licensed_authors) do
225
- %w[
226
- customer-a@example.com
227
- customer-b@example.com
228
- ]
229
- end
230
-
231
- let(:license_json) do
232
- {
233
- 'type' => 'com',
234
- 'contents' => {
235
- 'authors' => licensed_authors
236
- }
237
- }
238
- end
239
-
240
- let(:git_config_author) { "customer-a@example.com\n" }
241
- let(:git_config_result) { Mutant::Either::Right.new(git_config_author) }
242
- let(:git_show_author) { "customer-b@example.com\n" }
243
- let(:git_show_result) { Mutant::Either::Right.new(git_show_author) }
244
-
245
- let(:commands) do
246
- {
247
- %w[git config --get user.email] => git_config_result,
248
- %w[git show --quiet --pretty=format:%ae] => git_show_result
249
- }
250
- end
251
-
252
- context 'when author is whitelisted' do
253
- it_is_successful
254
- end
255
-
256
- context 'when author is not whitelisted' do
257
- let(:licensed_authors) { %w[customer-c@example.com] }
258
-
259
- it_fails_with_message(<<~'MESSAGE')
260
- Can not validate commercial license.
261
- Licensed:
262
- customer-c@example.com
263
- Present:
264
- customer-a@example.com
265
- customer-b@example.com
266
- MESSAGE
267
- end
268
-
269
- context 'when author cannot be found in commit or config' do
270
- let(:git_config_result) { Mutant::Either::Left.new('fatal: error') }
271
- let(:git_show_result) { Mutant::Either::Left.new('fatal: error') }
272
-
273
- it_fails_with_message(<<~'MESSAGE')
274
- Can not validate commercial license.
275
- Licensed:
276
- customer-a@example.com
277
- customer-b@example.com
278
- Present:
279
- [none]
280
- MESSAGE
281
- end
282
-
283
- context 'when mutant-license gem cannot be loaded' do
284
- let(:load_json) { false }
285
-
286
- def self.setup_error(message)
287
- before do
288
- allow(gem_method).to receive(:call).and_raise(Gem::LoadError, message)
289
- end
290
- end
291
-
292
- context 'while the mutant license gem from rubygems is present' do
293
- setup_error %{can't activate mutant-license (~> 0.1.0), already activated mutant-license-0.0.0.}
294
-
295
- it_fails_with_message '[Mutant-License-Error]: mutant-license gem from rubygems.org is a dummy'
296
- end
297
-
298
- context 'with other error message' do
299
- setup_error 'test-error'
300
-
301
- it_fails_with_message '[Mutant-License-Error]: test-error'
302
- end
303
- end
304
- end
305
- end