mutant 0.9.2 → 0.9.7

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +26 -0
  3. data/Gemfile +0 -8
  4. data/Gemfile.lock +55 -59
  5. data/LICENSE +1 -1
  6. data/README.md +9 -0
  7. data/config/rubocop.yml +10 -3
  8. data/docs/commercial-support.md +14 -0
  9. data/lib/mutant.rb +5 -4
  10. data/lib/mutant/cli.rb +5 -5
  11. data/lib/mutant/config.rb +1 -0
  12. data/lib/mutant/integration.rb +1 -1
  13. data/lib/mutant/license.rb +33 -6
  14. data/lib/mutant/license/subscription/opensource.rb +1 -1
  15. data/lib/mutant/meta.rb +1 -3
  16. data/lib/mutant/meta/example/verification.rb +1 -1
  17. data/lib/mutant/mutator/node/generic.rb +25 -2
  18. data/lib/mutant/mutator/node/send.rb +1 -1
  19. data/lib/mutant/parallel.rb +1 -1
  20. data/lib/mutant/reporter/cli/format.rb +1 -1
  21. data/lib/mutant/transform.rb +6 -5
  22. data/lib/mutant/version.rb +1 -1
  23. data/lib/mutant/warnings.rb +1 -1
  24. data/lib/mutant/zombifier.rb +2 -0
  25. data/mutant.gemspec +17 -16
  26. data/spec/integrations.yml +3 -1
  27. data/spec/support/corpus.rb +3 -3
  28. data/spec/support/ruby_vm.rb +1 -2
  29. data/spec/support/shared_context.rb +3 -3
  30. data/spec/support/xspec.rb +2 -2
  31. data/spec/unit/mutant/license_spec.rb +43 -7
  32. data/spec/unit/mutant/parallel/driver_spec.rb +4 -4
  33. data/spec/unit/mutant/parallel/worker_spec.rb +5 -5
  34. data/spec/unit/mutant/parallel_spec.rb +7 -7
  35. data/spec/unit/mutant/repository/diff/ranges_spec.rb +2 -2
  36. metadata +31 -24
  37. data/lib/mutant/base.rb +0 -192
  38. data/lib/mutant/variable.rb +0 -282
  39. data/spec/unit/mutant/either_spec.rb +0 -247
  40. data/spec/unit/mutant/maybe_spec.rb +0 -60
  41. data/spec/unit/mutant/variable_spec.rb +0 -618
@@ -53,7 +53,7 @@ module Mutant
53
53
  world
54
54
  .capture_stdout(%w[git remote --verbose])
55
55
  .fmap(&method(:parse_remotes))
56
- .apply(&method(:check_subscription))
56
+ .bind(&method(:check_subscription))
57
57
  end
58
58
 
59
59
  private
@@ -10,14 +10,12 @@ module Mutant
10
10
  # Mutation example
11
11
  class Example
12
12
 
13
- # rubocop:disable MutableConstant
13
+ # rubocop:disable Style/MutableConstant
14
14
  ALL = []
15
15
 
16
16
  # Add example
17
17
  #
18
18
  # @return [undefined]
19
- #
20
- # rubocop:disable Performance/Caller
21
19
  def self.add(*types, &block)
22
20
  file = caller.first.split(':in', 2).first
23
21
  ALL << DSL.call(file, Set.new(types), block)
@@ -61,7 +61,7 @@ module Mutant
61
61
  def invalid_syntax
62
62
  mutations.reject do |mutation|
63
63
  ::Parser::CurrentRuby.parse(mutation.source)
64
- rescue ::Parser::SyntaxError # rubocop:disable Lint/HandleExceptions
64
+ rescue ::Parser::SyntaxError # rubocop:disable Lint/SuppressedException
65
65
  end
66
66
  end
67
67
  memoize :invalid_syntax
@@ -12,30 +12,52 @@ module Mutant
12
12
  __LINE__
13
13
  alias
14
14
  arg_expr
15
+ array_pattern
16
+ array_pattern_with_tail
15
17
  back_ref
16
18
  blockarg
17
19
  blockarg_expr
20
+ case_match
18
21
  complex
22
+ const_pattern
23
+ def_e
24
+ defs_e
19
25
  eflipflop
20
26
  empty
27
+ empty_else
21
28
  ensure
29
+ find_pattern
22
30
  for
31
+ forward_arg
32
+ forward_args
33
+ forwarded_args
34
+ hash_pattern
23
35
  ident
36
+ if_guard
24
37
  iflipflop
38
+ in_match
39
+ in_pattern
25
40
  kwnilarg
26
41
  kwrestarg
27
42
  kwsplat
43
+ match_alt
44
+ match_as
45
+ match_nil_pattern
46
+ match_rest
47
+ match_var
28
48
  match_with_lvasgn
29
- meth_ref
49
+ match_with_trailing_comma
30
50
  module
51
+ mrasgn
31
52
  numargs
32
53
  numblock
33
- numparam
34
54
  objc_kwarg
35
55
  objc_restarg
36
56
  objc_varargs
57
+ pin
37
58
  postexe
38
59
  preexe
60
+ rasgn
39
61
  rational
40
62
  redo
41
63
  restarg
@@ -45,6 +67,7 @@ module Mutant
45
67
  sclass
46
68
  shadowarg
47
69
  undef
70
+ unless_guard
48
71
  until_post
49
72
  while_post
50
73
  xstr
@@ -5,7 +5,7 @@ module Mutant
5
5
  class Node
6
6
 
7
7
  # Namespace for send mutators
8
- # rubocop:disable ClassLength
8
+ # rubocop:disable Metrics/ClassLength
9
9
  class Send < self
10
10
  include AST::Types
11
11
 
@@ -52,7 +52,7 @@ module Mutant
52
52
  # @param [Class] klass
53
53
  # @param [Config] config
54
54
  #
55
- # @return [Mutant::Variable]
55
+ # @return [Variable]
56
56
  #
57
57
  # ignore :reek:LongParameterList
58
58
  def self.shared(klass, config, **attributes)
@@ -5,7 +5,7 @@ module Mutant
5
5
  class CLI
6
6
  # CLI output format
7
7
  #
8
- # rubocop:disable FormatString
8
+ # rubocop:disable Style/FormatString
9
9
  class Format
10
10
  include AbstractType, Concord.new(:tty)
11
11
 
@@ -263,7 +263,7 @@ module Mutant
263
263
  PRIMITIVE
264
264
  .apply(input)
265
265
  .lmap(&method(:lift_error))
266
- .apply(&method(:run))
266
+ .bind(&method(:run))
267
267
  end
268
268
 
269
269
  private
@@ -351,8 +351,8 @@ module Mutant
351
351
  PRIMITIVE
352
352
  .apply(input)
353
353
  .lmap(&method(:lift_error))
354
- .apply(&method(:reject_keys))
355
- .apply(&method(:transform))
354
+ .bind(&method(:reject_keys))
355
+ .bind(&method(:transform))
356
356
  end
357
357
 
358
358
  private
@@ -363,7 +363,7 @@ module Mutant
363
363
  #
364
364
  # @return [Either<Error, Hash>]
365
365
  def transform(input)
366
- transform_required(input).apply do |required|
366
+ transform_required(input).bind do |required|
367
367
  transform_optional(input).fmap(&required.method(:merge))
368
368
  end
369
369
  end
@@ -503,7 +503,8 @@ module Mutant
503
503
  #
504
504
  # @return [Either<Error, Object>]
505
505
  def apply(input)
506
- Either.wrap_error(error_class) { block.call(input) }
506
+ Either
507
+ .wrap_error(error_class) { block.call(input) }
507
508
  .lmap { |exception| error(input: input, message: exception.to_s) }
508
509
  end
509
510
  end # Exception
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Mutant
4
4
  # Current mutant version
5
- VERSION = '0.9.2'
5
+ VERSION = '0.9.7'
6
6
  end # Mutant
@@ -55,7 +55,7 @@ module Mutant
55
55
  # For that reason we do have to use the original method capture to dispatch
56
56
  # in disabled state.
57
57
  #
58
- # :reek:ignore RepeatedConditional
58
+ # ignore :reek:RepeatedConditional
59
59
  class Warnings
60
60
  # Error raised when warning capture is used recursively
61
61
  class RecursiveUseError < RuntimeError; end
@@ -17,7 +17,9 @@ module Mutant
17
17
 
18
18
  include AST::Sexp
19
19
 
20
+ # rubocop:disable Lint/InheritException
20
21
  LoadError = Class.new(::LoadError)
22
+ # rubocop:enable Lint/InheritException
21
23
 
22
24
  # Initialize object
23
25
  #
@@ -7,8 +7,8 @@ Gem::Specification.new do |gem|
7
7
  gem.version = Mutant::VERSION.dup
8
8
  gem.authors = ['Markus Schirp']
9
9
  gem.email = ['mbj@schirp-dso.com']
10
- gem.description = 'Mutation testing for ruby'
11
- gem.summary = 'Mutation testing tool for ruby under MRI and Rubinius'
10
+ gem.description = 'Mutation Testing for Ruby.'
11
+ gem.summary = ''
12
12
  gem.homepage = 'https://github.com/mbj/mutant'
13
13
  gem.license = 'Nonstandard'
14
14
 
@@ -21,20 +21,21 @@ Gem::Specification.new do |gem|
21
21
  gem.extra_rdoc_files = %w[LICENSE]
22
22
  gem.executables = %w[mutant]
23
23
 
24
- gem.add_runtime_dependency('abstract_type', '~> 0.0.7')
25
- gem.add_runtime_dependency('adamantium', '~> 0.2.0')
26
- gem.add_runtime_dependency('anima', '~> 0.3.1')
27
- gem.add_runtime_dependency('ast', '~> 2.2')
28
- gem.add_runtime_dependency('concord', '~> 0.1.5')
29
- gem.add_runtime_dependency('diff-lcs', '~> 1.3')
30
- gem.add_runtime_dependency('equalizer', '~> 0.0.9')
31
- gem.add_runtime_dependency('ice_nine', '~> 0.11.1')
32
- gem.add_runtime_dependency('memoizable', '~> 0.4.2')
33
- gem.add_runtime_dependency('mutant-license', '~> 0.1.0')
34
- gem.add_runtime_dependency('parser', '~> 2.6.5')
35
- gem.add_runtime_dependency('procto', '~> 0.0.2')
36
- gem.add_runtime_dependency('unparser', '~> 0.4.5')
24
+ gem.add_runtime_dependency('abstract_type', '~> 0.0.7')
25
+ gem.add_runtime_dependency('adamantium', '~> 0.2.0')
26
+ gem.add_runtime_dependency('anima', '~> 0.3.1')
27
+ gem.add_runtime_dependency('ast', '~> 2.2')
28
+ gem.add_runtime_dependency('concord', '~> 0.1.5')
29
+ gem.add_runtime_dependency('diff-lcs', '= 1.3')
30
+ gem.add_runtime_dependency('equalizer', '~> 0.0.9')
31
+ gem.add_runtime_dependency('ice_nine', '~> 0.11.1')
32
+ gem.add_runtime_dependency('memoizable', '~> 0.4.2')
33
+ gem.add_runtime_dependency('mprelude', '~> 0.1.0')
34
+ gem.add_runtime_dependency('parser', '~> 2.7.1')
35
+ gem.add_runtime_dependency('procto', '~> 0.0.2')
36
+ gem.add_runtime_dependency('unparser', '~> 0.4.6')
37
+ gem.add_runtime_dependency('variable', '~> 0.0.1')
37
38
 
38
- gem.add_development_dependency('devtools', '~> 0.1.23')
39
+ gem.add_development_dependency('devtools', '~> 0.1.25')
39
40
  gem.add_development_dependency('parallel', '~> 1.3')
40
41
  end
@@ -2,13 +2,14 @@
2
2
  - name: rubyspec
3
3
  namespace: Rubyspec
4
4
  repo_uri: 'https://github.com/ruby/rubyspec.git'
5
- repo_ref: 'origin/master'
5
+ repo_ref: 249a36c2e9fcddbb208a0d618d05f6bd9a64fd17
6
6
  integration: mspec
7
7
  mutation_coverage: false
8
8
  mutation_generation: true
9
9
  exclude:
10
10
  - command_line/fixtures/bad_syntax.rb
11
11
  - command_line/fixtures/freeze_flag_required_diff_enc.rb
12
+ - core/file/stat_spec.rb
12
13
  - core/kernel/shared/sprintf_encoding.rb
13
14
  - core/module/fixtures/autoload_empty.rb
14
15
  - core/module/fixtures/autoload_never_set.rb
@@ -26,6 +27,7 @@
26
27
  - language/predefined/fixtures/data_only.rb
27
28
  - language/source_encoding_spec.rb
28
29
  - library/base64/decode64_spec.rb
30
+ - library/cgi/escapeHTML_spec.rb
29
31
  - security/cve_2010_1330_spec.rb
30
32
  - name: regexp_parser
31
33
  namespace: Regexp
@@ -10,7 +10,7 @@ module MutantSpec
10
10
 
11
11
  # Namespace module for corpus testing
12
12
  #
13
- # rubocop:disable MethodLength
13
+ # rubocop:disable Metrics/MethodLength
14
14
  module Corpus
15
15
  TMP = ROOT.join('tmp').freeze
16
16
  EXCLUDE_GLOB_FORMAT = '{%s}'
@@ -22,7 +22,7 @@ module MutantSpec
22
22
  private_constant(*constants(false))
23
23
 
24
24
  # Project under corpus test
25
- # rubocop:disable ClassLength
25
+ # rubocop:disable Metrics/ClassLength
26
26
  class Project
27
27
  MUTEX = Mutex.new
28
28
 
@@ -259,7 +259,7 @@ module MutantSpec
259
259
  #
260
260
  # @param [Array<String>] arguments
261
261
  #
262
- # rubocop:disable GuardClause - guard clause without else does not make sense
262
+ # rubocop:disable Style/GuardClause - guard clause without else does not make sense
263
263
  def system(arguments)
264
264
  return if Kernel.system(*arguments)
265
265
 
@@ -26,8 +26,7 @@ module MutantSpec
26
26
  super(DEFAULTS.merge(attributes))
27
27
  end
28
28
 
29
- # rubocop:disable Naming/UncommunicativeMethodParamName
30
- def handle(vm, observation)
29
+ def handle(vm, observation) # rubocop:disable Naming/MethodParameterName
31
30
  unless match?(observation)
32
31
  fail "Unexpected event observation: #{observation.inspect}, expected #{inspect}"
33
32
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rubocop:disable ModuleLength
3
+ # rubocop:disable Metrics/ModuleLength
4
4
  module SharedContext
5
5
  # Prepend an anonymous module with the new `with` method
6
6
  #
@@ -25,8 +25,8 @@ module SharedContext
25
25
  end
26
26
  end
27
27
 
28
- # rubocop:disable MethodLength
29
- # rubocop:disable AbcSize
28
+ # rubocop:disable Metrics/MethodLength
29
+ # rubocop:disable Metrics/AbcSize
30
30
  def setup_shared_context
31
31
  let(:mutation_a) { Mutant::Mutation::Evil.new(subject_a, mutation_a_node) }
32
32
  let(:mutation_a_node) { s(:false) }
@@ -93,7 +93,7 @@ module XSpec
93
93
  class MessageExpectation
94
94
  include Anima.new(:receiver, :selector, :arguments, :reaction)
95
95
 
96
- # rubocop:disable ParameterLists
96
+ # rubocop:disable Metrics/ParameterLists
97
97
  def self.parse(receiver:, selector:, arguments: [], reaction: nil)
98
98
  new(
99
99
  receiver: receiver,
@@ -152,7 +152,7 @@ module XSpec
152
152
  expectations.empty? or fail "unconsumed expectations:\n#{expectations.map(&:inspect).join("\n")}"
153
153
  end
154
154
 
155
- # rubocop:disable MethodLength
155
+ # rubocop:disable Metrics/MethodLength
156
156
  def self.verify(rspec_context, expectations)
157
157
  verifier = new(expectations)
158
158
 
@@ -6,11 +6,13 @@ RSpec.describe Mutant::License do
6
6
  end
7
7
 
8
8
  let(:gem) { class_double(Gem, loaded_specs: loaded_specs) }
9
+ let(:gem_method) { instance_double(Method) }
9
10
  let(:gem_path) { '/path/to/mutant-license' }
10
11
  let(:gem_pathname) { instance_double(Pathname) }
11
12
  let(:json) { class_double(JSON) }
12
13
  let(:kernel) { class_double(Kernel) }
13
14
  let(:license_pathname) { instance_double(Pathname) }
15
+ let(:load_json) { true }
14
16
  let(:loaded_specs) { { 'mutant-license' => spec } }
15
17
  let(:path) { instance_double(Pathname) }
16
18
  let(:pathname) { class_double(Pathname) }
@@ -26,15 +28,17 @@ RSpec.describe Mutant::License do
26
28
  let(:world) do
27
29
  instance_double(
28
30
  Mutant::World,
29
- gem: gem,
30
- json: json,
31
- kernel: kernel,
32
- pathname: pathname,
33
- stderr: stderr
31
+ gem: gem,
32
+ gem_method: gem_method,
33
+ json: json,
34
+ kernel: kernel,
35
+ pathname: pathname,
36
+ stderr: stderr
34
37
  )
35
38
  end
36
39
 
37
40
  before do
41
+ allow(gem_method).to receive_messages(call: undefined)
38
42
  allow(gem_pathname).to receive_messages(join: license_pathname)
39
43
  allow(json).to receive_messages(load: license_json)
40
44
  allow(kernel).to receive_messages(sleep: undefined)
@@ -66,6 +70,18 @@ RSpec.describe Mutant::License do
66
70
  it 'performs IO in expected sequence' do
67
71
  expect(apply).to eql(Mutant::Either::Right.new(true))
68
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
+
69
85
  expect(stderr)
70
86
  .to have_received(:puts)
71
87
  .with(expected)
@@ -73,12 +89,22 @@ RSpec.describe Mutant::License do
73
89
 
74
90
  expect(stderr)
75
91
  .to have_received(:puts)
76
- .with('Soft fail, continuing in 10 seconds')
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')
77
103
  .ordered
78
104
 
79
105
  expect(kernel)
80
106
  .to have_received(:sleep)
81
- .with(10)
107
+ .with(40)
82
108
  .ordered
83
109
  end
84
110
  end
@@ -253,5 +279,15 @@ RSpec.describe Mutant::License do
253
279
  [none]
254
280
  MESSAGE
255
281
  end
282
+
283
+ context 'when mutant-license gem cannot be loaded' do
284
+ let(:load_json) { false }
285
+
286
+ before do
287
+ allow(gem_method).to receive(:call).and_raise(Gem::LoadError, 'test-error')
288
+ end
289
+
290
+ it_fails_with_message '[Mutant-License-Error]: test-error'
291
+ end
256
292
  end
257
293
  end
@@ -16,15 +16,15 @@ RSpec.describe Mutant::Parallel::Driver do
16
16
  end
17
17
 
18
18
  let(:var_active_jobs) do
19
- instance_double(Mutant::Variable::IVar, 'active jobs')
19
+ instance_double(Variable::IVar, 'active jobs')
20
20
  end
21
21
 
22
22
  let(:var_final) do
23
- instance_double(Mutant::Variable::IVar, 'final')
23
+ instance_double(Variable::IVar, 'final')
24
24
  end
25
25
 
26
26
  let(:var_sink) do
27
- instance_double(Mutant::Variable::IVar, 'sink')
27
+ instance_double(Variable::IVar, 'sink')
28
28
  end
29
29
 
30
30
  subject do
@@ -64,7 +64,7 @@ RSpec.describe Mutant::Parallel::Driver do
64
64
  receiver: var_final,
65
65
  selector: :take_timeout,
66
66
  arguments: [timeout],
67
- reaction: { return: Mutant::Variable.const_get(:Result)::Timeout.new }
67
+ reaction: { return: Variable.const_get(:Result)::Timeout.new }
68
68
  },
69
69
  {
70
70
  receiver: var_active_jobs,