mutant 0.9.3 → 0.9.8

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +121 -0
  3. data/Changelog.md +24 -0
  4. data/Gemfile +0 -15
  5. data/Gemfile.lock +56 -59
  6. data/Gemfile.shared +7 -0
  7. data/LICENSE +1 -1
  8. data/README.md +10 -1
  9. data/config/rubocop.yml +10 -3
  10. data/docs/commercial-support.md +14 -0
  11. data/lib/mutant.rb +4 -2
  12. data/lib/mutant/cli.rb +5 -5
  13. data/lib/mutant/integration.rb +1 -1
  14. data/lib/mutant/license.rb +2 -2
  15. data/lib/mutant/license/subscription/opensource.rb +1 -1
  16. data/lib/mutant/meta.rb +1 -3
  17. data/lib/mutant/meta/example/verification.rb +1 -1
  18. data/lib/mutant/mutator/node/generic.rb +0 -48
  19. data/lib/mutant/mutator/node/send.rb +1 -1
  20. data/lib/mutant/parallel.rb +1 -1
  21. data/lib/mutant/registry.rb +2 -7
  22. data/lib/mutant/reporter/cli/format.rb +1 -1
  23. data/lib/mutant/transform.rb +6 -5
  24. data/lib/mutant/version.rb +1 -1
  25. data/lib/mutant/zombifier.rb +2 -0
  26. data/mutant.gemspec +15 -13
  27. data/spec/integrations.yml +3 -1
  28. data/spec/support/corpus.rb +3 -3
  29. data/spec/support/ruby_vm.rb +1 -2
  30. data/spec/support/shared_context.rb +3 -3
  31. data/spec/support/xspec.rb +2 -2
  32. data/spec/unit/mutant/license_spec.rb +2 -2
  33. data/spec/unit/mutant/parallel/driver_spec.rb +4 -4
  34. data/spec/unit/mutant/parallel/worker_spec.rb +5 -5
  35. data/spec/unit/mutant/parallel_spec.rb +7 -7
  36. data/spec/unit/mutant/registry_spec.rb +52 -25
  37. data/spec/unit/mutant/repository/diff/ranges_spec.rb +2 -2
  38. metadata +44 -23
  39. data/.circleci/config.yml +0 -53
  40. data/lib/mutant/base.rb +0 -192
  41. data/lib/mutant/variable.rb +0 -282
  42. data/spec/unit/mutant/either_spec.rb +0 -247
  43. data/spec/unit/mutant/maybe_spec.rb +0 -60
  44. data/spec/unit/mutant/variable_spec.rb +0 -618
@@ -0,0 +1,14 @@
1
+ # Commercial Support
2
+
3
+ Mutant offers only community support.
4
+
5
+ Commercial license customers are entited to priority support via email.
6
+
7
+ ## Priority Support
8
+
9
+ Covers 1 incident per quarter, with a max response time of 7 days.
10
+ Scope is limited to mutant not the application or infrastructure.
11
+
12
+ For support email [Markus Schirp](mailto:mbj@schirp-dso.com?subject=Mutant%20Support).
13
+ Please email using the same domain as the roiginal license email or explain
14
+ your connection to the license.
@@ -10,6 +10,7 @@ require 'digest/sha1'
10
10
  require 'equalizer'
11
11
  require 'etc'
12
12
  require 'ice_nine'
13
+ require 'mprelude'
13
14
  require 'json'
14
15
  require 'open3'
15
16
  require 'optparse'
@@ -20,6 +21,7 @@ require 'set'
20
21
  require 'singleton'
21
22
  require 'stringio'
22
23
  require 'unparser'
24
+ require 'variable'
23
25
  require 'yaml'
24
26
 
25
27
  # This setting is done to make errors within the parallel
@@ -30,13 +32,14 @@ Thread.abort_on_exception = true
30
32
  #
31
33
  # @api private
32
34
  module Mutant
35
+ Either = MPrelude::Either
36
+
33
37
  EMPTY_STRING = ''
34
38
  EMPTY_ARRAY = [].freeze
35
39
  EMPTY_HASH = {}.freeze
36
40
  SCOPE_OPERATOR = '::'
37
41
  end # Mutant
38
42
 
39
- require 'mutant/base'
40
43
  require 'mutant/bootstrap'
41
44
  require 'mutant/version'
42
45
  require 'mutant/env'
@@ -183,7 +186,6 @@ require 'mutant/reporter/cli/format'
183
186
  require 'mutant/repository'
184
187
  require 'mutant/repository/diff'
185
188
  require 'mutant/repository/diff/ranges'
186
- require 'mutant/variable'
187
189
  require 'mutant/warnings'
188
190
  require 'mutant/zombifier'
189
191
  require 'mutant/range'
@@ -36,10 +36,10 @@ module Mutant
36
36
  def self.run(world, default_config, arguments)
37
37
  License
38
38
  .apply(world)
39
- .apply { Config.load_config_file(world, default_config) }
40
- .apply { |file_config| apply(world, file_config, arguments) }
41
- .apply { |cli_config| Bootstrap.apply(world, cli_config) }
42
- .apply(&Runner.method(:apply))
39
+ .bind { Config.load_config_file(world, default_config) }
40
+ .bind { |file_config| apply(world, file_config, arguments) }
41
+ .bind { |cli_config| Bootstrap.apply(world, cli_config) }
42
+ .bind(&Runner.method(:apply))
43
43
  .from_right { |error| world.stderr.puts(error); return false }
44
44
  .success?
45
45
  end
@@ -105,7 +105,7 @@ module Mutant
105
105
  #
106
106
  # @return [undefined]
107
107
  #
108
- # rubocop:disable MethodLength
108
+ # rubocop:disable Metrics/MethodLength
109
109
  def add_environment_options(opts)
110
110
  opts.separator('Environment:')
111
111
  opts.on('--zombie', 'Run mutant zombified') do
@@ -28,7 +28,7 @@ module Mutant
28
28
  # @return [Either<String, Integration>]
29
29
  def self.setup(env)
30
30
  attempt_require(env)
31
- .apply { attempt_const_get(env) }
31
+ .bind { attempt_const_get(env) }
32
32
  .fmap { |klass| klass.new(env.config).setup }
33
33
  end
34
34
 
@@ -4,7 +4,7 @@ module Mutant
4
4
  module License
5
5
  NAME = 'mutant-license'
6
6
  VERSION = '~> 0.1.0'
7
- SLEEP = 20
7
+ SLEEP = 40
8
8
 
9
9
  UNLICENSED =
10
10
  IceNine.deep_freeze(
@@ -23,7 +23,7 @@ module Mutant
23
23
  load_mutant_license(world)
24
24
  .fmap { license_path(world) }
25
25
  .fmap { |path| Subscription.from_json(world.json.load(path)) }
26
- .apply { |sub| sub.apply(world) }
26
+ .bind { |sub| sub.apply(world) }
27
27
  end
28
28
  private_class_method :license_result
29
29
 
@@ -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
@@ -3,57 +3,9 @@
3
3
  module Mutant
4
4
  class Mutator
5
5
  class Node
6
-
7
6
  # Generic mutator
8
7
  class Generic < self
9
8
 
10
- unsupported_nodes = %i[
11
- __FILE__
12
- __LINE__
13
- alias
14
- arg_expr
15
- back_ref
16
- blockarg
17
- blockarg_expr
18
- complex
19
- eflipflop
20
- empty
21
- ensure
22
- for
23
- ident
24
- iflipflop
25
- kwnilarg
26
- kwrestarg
27
- kwsplat
28
- match_with_lvasgn
29
- meth_ref
30
- module
31
- numargs
32
- numblock
33
- numparam
34
- objc_kwarg
35
- objc_restarg
36
- objc_varargs
37
- postexe
38
- preexe
39
- rational
40
- redo
41
- restarg
42
- restarg_expr
43
- retry
44
- root
45
- sclass
46
- shadowarg
47
- undef
48
- until_post
49
- while_post
50
- xstr
51
- ]
52
-
53
- # These nodes still need a dedicated mutator,
54
- # your contribution is that close!
55
- handle(*unsupported_nodes)
56
-
57
9
  private
58
10
 
59
11
  # Emit mutations
@@ -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)
@@ -32,14 +32,9 @@ module Mutant
32
32
  #
33
33
  # @param [Symbol] type
34
34
  #
35
- # @return [Class]
36
- #
37
- # @raise [ArgumentError]
38
- # raises argument error when class cannot be found
35
+ # @return [Class<Mutator>]
39
36
  def lookup(type)
40
- contents.fetch(type) do
41
- fail RegistryError, "No entry for: #{type.inspect}"
42
- end
37
+ contents.fetch(type, Mutator::Node::Generic)
43
38
  end
44
39
 
45
40
  end # Registry
@@ -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.3'
5
+ VERSION = '0.9.8'
6
6
  end # Mutant
@@ -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
  #
@@ -21,19 +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('parser', '~> 2.6.5')
34
- gem.add_runtime_dependency('procto', '~> 0.0.2')
35
- 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')
36
38
 
37
- gem.add_development_dependency('devtools', '~> 0.1.23')
39
+ gem.add_development_dependency('devtools', '~> 0.1.25')
38
40
  gem.add_development_dependency('parallel', '~> 1.3')
39
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
 
@@ -89,7 +89,7 @@ RSpec.describe Mutant::License do
89
89
 
90
90
  expect(stderr)
91
91
  .to have_received(:puts)
92
- .with('[Mutant-License-Error]: Soft fail, continuing in 20 seconds')
92
+ .with('[Mutant-License-Error]: Soft fail, continuing in 40 seconds')
93
93
  .ordered
94
94
 
95
95
  expect(stderr)
@@ -104,7 +104,7 @@ RSpec.describe Mutant::License do
104
104
 
105
105
  expect(kernel)
106
106
  .to have_received(:sleep)
107
- .with(20)
107
+ .with(40)
108
108
  .ordered
109
109
  end
110
110
  end