mutant 0.11.11 → 0.11.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mutant/ast/find_metaclass_containing.rb +6 -6
  3. data/lib/mutant/ast/meta/const.rb +1 -1
  4. data/lib/mutant/ast/meta/optarg.rb +1 -1
  5. data/lib/mutant/ast/meta/resbody.rb +1 -1
  6. data/lib/mutant/ast/meta/send.rb +1 -1
  7. data/lib/mutant/ast/meta/symbol.rb +1 -1
  8. data/lib/mutant/ast/meta.rb +1 -1
  9. data/lib/mutant/ast/named_children.rb +1 -1
  10. data/lib/mutant/ast/node_predicates.rb +1 -1
  11. data/lib/mutant/ast/nodes.rb +1 -1
  12. data/lib/mutant/ast/pattern/lexer.rb +1 -1
  13. data/lib/mutant/ast/pattern/parser.rb +1 -1
  14. data/lib/mutant/ast/pattern/source.rb +1 -1
  15. data/lib/mutant/ast/pattern/token.rb +1 -1
  16. data/lib/mutant/ast/pattern.rb +1 -1
  17. data/lib/mutant/ast/regexp/transformer/direct.rb +1 -1
  18. data/lib/mutant/ast/regexp/transformer/named_group.rb +1 -1
  19. data/lib/mutant/ast/regexp/transformer/options_group.rb +1 -1
  20. data/lib/mutant/ast/regexp/transformer/quantifier.rb +1 -1
  21. data/lib/mutant/ast/regexp/transformer/recursive.rb +1 -1
  22. data/lib/mutant/ast/regexp/transformer/root.rb +1 -1
  23. data/lib/mutant/ast/regexp/transformer/text.rb +1 -1
  24. data/lib/mutant/ast/regexp/transformer.rb +1 -1
  25. data/lib/mutant/ast/regexp.rb +1 -1
  26. data/lib/mutant/ast/sexp.rb +1 -1
  27. data/lib/mutant/ast/structure.rb +8 -3
  28. data/lib/mutant/ast/types.rb +1 -1
  29. data/lib/mutant/ast.rb +31 -29
  30. data/lib/mutant/bootstrap.rb +8 -7
  31. data/lib/mutant/cli/command/environment.rb +5 -3
  32. data/lib/mutant/cli/command/util.rb +17 -2
  33. data/lib/mutant/config.rb +76 -40
  34. data/lib/mutant/env.rb +1 -1
  35. data/lib/mutant/license/subscription/opensource.rb +13 -3
  36. data/lib/mutant/matcher/method/instance.rb +3 -2
  37. data/lib/mutant/matcher/method/metaclass.rb +4 -3
  38. data/lib/mutant/matcher/method/singleton.rb +3 -2
  39. data/lib/mutant/matcher/method.rb +36 -20
  40. data/lib/mutant/meta/example.rb +4 -1
  41. data/lib/mutant/mutation/config.rb +36 -0
  42. data/lib/mutant/mutator/node/arguments.rb +1 -1
  43. data/lib/mutant/mutator/node/begin.rb +2 -1
  44. data/lib/mutant/mutator/node/block.rb +5 -3
  45. data/lib/mutant/mutator/node/define.rb +5 -2
  46. data/lib/mutant/mutator/node/kwargs.rb +2 -2
  47. data/lib/mutant/mutator/node/literal/regex.rb +1 -1
  48. data/lib/mutant/mutator/node/literal/symbol.rb +2 -2
  49. data/lib/mutant/mutator/node/named_value/constant_assignment.rb +1 -1
  50. data/lib/mutant/mutator/node/named_value/variable_assignment.rb +2 -2
  51. data/lib/mutant/mutator/node/resbody.rb +0 -10
  52. data/lib/mutant/mutator/node.rb +47 -1
  53. data/lib/mutant/mutator/util/array.rb +0 -17
  54. data/lib/mutant/mutator.rb +2 -26
  55. data/lib/mutant/parser.rb +0 -7
  56. data/lib/mutant/reporter/cli/printer/config.rb +1 -1
  57. data/lib/mutant/subject/config.rb +5 -4
  58. data/lib/mutant/subject.rb +4 -1
  59. data/lib/mutant/transform.rb +14 -0
  60. data/lib/mutant/version.rb +1 -1
  61. data/lib/mutant.rb +2 -1
  62. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6aa7e42cfe0d8ed12281745fc607d4d933fbb03af10b2bb41c41e6df3765ef89
4
- data.tar.gz: 2a4a940e72bf2381816cfc0522f236166df7c2f649bd4da6ee8c2f41a6851c33
3
+ metadata.gz: 58b6affbd17beee4a525b5efa35e83b18d3d65316ec5abd2b773c4722377e79b
4
+ data.tar.gz: 10b60ffd99ea8b477537bed09af2c122ffc14152a69c9a020ed09cca73dfa2d8
5
5
  SHA512:
6
- metadata.gz: 9ffa1cf3efbe20ba6ac20d7aee9765cbb8833a2934f2d1b874ec800673582c709e76bcbdb6a026191bd751a9f30726720c5f0f81b09e0999805608e22d775dc7
7
- data.tar.gz: b4a2cf6f0fc16056e8f92b306828c4e5578f0b1408770b0395b4874ff887a3f1cbe5023613694493736bcdede6c906dfaed06c1b73e78f2b8b5821b2fb61457b
6
+ metadata.gz: 39bd2f27290e3e3ba1ec6be8ae515759db5970fe121e9732797819bcb243c1038b0582c49e52fe7c6ab99d9332dfce4eb4fcf62b75558bd79954929bb432a8fd
7
+ data.tar.gz: da7555f1f168b6359163aeb3cd58dd69b5cb553da005830169cabdc9de949317f7ddae0790e6e84cc7990dfcd3d7c0c2c9b85f05c0b7b8de18bf96079d2c58e7
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Given an AST, finds the sclass that directly(-ish) contains the provided
6
6
  # node.
7
7
  # This won't match arbitrarily complex structures - it only searches the
@@ -10,7 +10,7 @@ module Mutant
10
10
  # Descending into 'begin' nodes is supported because these are generated for
11
11
  # the one-line syntax class << self; def foo; end
12
12
  class FindMetaclassContaining
13
- include NodePredicates, Concord.new(:root, :target), Procto
13
+ include NodePredicates, Concord.new(:ast, :target), Procto
14
14
 
15
15
  SCLASS_BODY_INDEX = 1
16
16
 
@@ -22,11 +22,11 @@ module Mutant
22
22
  #
23
23
  # @api private
24
24
  def call
25
- AST.find_last_path(root) do |current|
26
- next unless n_sclass?(current)
25
+ Structure.for(ast.node.type).each_node(ast.node) do |current|
26
+ return current if n_sclass?(current) && metaclass_of?(current)
27
+ end
27
28
 
28
- metaclass_of?(current)
29
- end.last
29
+ nil
30
30
  end
31
31
 
32
32
  private
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
  end # Meta
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
 
6
6
  # Helper methods to define named children
7
7
  module NamedChildren
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Module for node predicates
6
6
  module NodePredicates
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Singleton nodes
6
6
  module Nodes
7
7
  extend Sexp
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  class Pattern
6
6
  # rubocop:disable Metrics/ClassLength
7
7
  class Lexer
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # rubocop:disable Metrics/ClassLength
6
6
  # rubocop:disable Metrics/MethodLength
7
7
  class Pattern
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  class Pattern
6
6
  class Source
7
7
  include Anima.new(:string)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  class Pattern
6
6
  class Token
7
7
  include Anima.new(:type, :value, :location)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  class Pattern
6
6
  include Adamantium
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for nodes which map directly to other domain
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for named groups
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for option groups
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for regexp quantifiers
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for nodes with children
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for root nodes
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Regexp AST transformer for nodes that encode a text value
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  # Regexp bijective mapper
7
7
  #
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Regexp source mapper
6
6
  module Regexp
7
7
  # Parse regex string into expression
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Mixin for node sexp syntax
6
6
  module Sexp
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # AST Structure metadata
6
6
  # rubocop:disable Metrics/ModuleLength
7
7
  module Structure
@@ -26,7 +26,7 @@ module Mutant
26
26
  end
27
27
 
28
28
  def value(node)
29
- node.children.fetch(index)
29
+ node.children.at(index)
30
30
  end
31
31
  end
32
32
 
@@ -246,7 +246,7 @@ module Mutant
246
246
  type: :class,
247
247
  fixed: Node.fixed(
248
248
  [
249
- [Node::Fixed::Descendant, :name],
249
+ [Node::Fixed::Attribute, :name],
250
250
  [Node::Fixed::Descendant, :superclass],
251
251
  [Node::Fixed::Descendant, :body]
252
252
  ]
@@ -386,6 +386,11 @@ module Mutant
386
386
  fixed: Node.fixed([[Node::Fixed::Attribute, :value]]),
387
387
  variable: nil
388
388
  ),
389
+ Node.new(
390
+ type: :forwarded_args,
391
+ fixed: EMPTY_ARRAY,
392
+ variable: nil
393
+ ),
389
394
  Node.new(
390
395
  type: :for,
391
396
  fixed: Node.fixed(
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Groups of node types
6
6
  module Types # rubocop:disable Metrics/ModuleLength
7
7
  ASSIGNABLE_VARIABLES = Set.new(%i[ivasgn lvasgn cvasgn gvasgn]).freeze
data/lib/mutant/ast.rb CHANGED
@@ -1,41 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- # AST helpers
5
- module AST
6
-
7
- # Find last node satisfying predicate (as block)
8
- #
9
- # @return [Parser::AST::Node]
10
- # if satisfying node is found
11
- #
12
- # @yield [Parser::AST::Node]
13
- #
14
- # @yieldreturn [Boolean]
15
- # true in case node satisfies predicate
16
- #
17
- # @return [nil]
18
- # otherwise
19
- def self.find_last_path(node, &predicate)
20
- fail ArgumentError, 'block expected' unless block_given?
21
- path = []
22
- walk(node, [node]) do |candidate, stack|
23
- if predicate.call(candidate)
24
- path = stack.dup
25
- end
4
+ class AST
5
+ include Adamantium, Anima.new(
6
+ :node,
7
+ :comment_associations
8
+ )
9
+
10
+ class View
11
+ include Adamantium, Anima.new(:node, :path)
12
+ end
13
+
14
+ def on_line(line)
15
+ line_map.fetch(line, EMPTY_HASH).map do |node, path|
16
+ View.new(node: node, path: path)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def line_map
23
+ line_map = {}
24
+
25
+ walk_path(node) do |node, path|
26
+ expression = node.location.expression || next
27
+ (line_map[expression.line] ||= []) << [node, path]
26
28
  end
27
- path
29
+
30
+ line_map
28
31
  end
32
+ memoize :line_map
29
33
 
30
- def self.walk(node, stack, &block)
31
- block.call(node, stack)
34
+ def walk_path(node, stack = [node.type], &block)
35
+ block.call(node, stack.dup)
32
36
  node.children.grep(::Parser::AST::Node) do |child|
33
- stack.push(child)
34
- walk(child, stack, &block)
37
+ stack.push(child.type)
38
+ walk_path(child, stack, &block)
35
39
  stack.pop
36
40
  end
37
41
  end
38
- private_class_method :walk
39
-
40
42
  end # AST
41
43
  end # Mutant
@@ -24,16 +24,15 @@ module Mutant
24
24
 
25
25
  # Run Bootstrap
26
26
  #
27
- # @param [World] world
28
- # @param [Config] config
27
+ # @param [Env] env
29
28
  #
30
29
  # @return [Either<String, Env>]
31
30
  #
32
31
  # rubocop:disable Metrics/MethodLength
33
- def self.call(world, config)
34
- env = load_hooks(Env.empty(world, config))
32
+ def self.call(env)
33
+ env = load_hooks(env)
35
34
  .tap(&method(:infect))
36
- .with(matchable_scopes: matchable_scopes(world, config))
35
+ .with(matchable_scopes: matchable_scopes(env))
37
36
 
38
37
  subjects = start_subject(env, Matcher.from_config(env.config.matcher).call(env))
39
38
 
@@ -82,8 +81,10 @@ module Mutant
82
81
  end
83
82
  private_class_method :infect
84
83
 
85
- def self.matchable_scopes(world, config)
86
- scopes = world.object_space.each_object(Module).each_with_object([]) do |scope, aggregate|
84
+ def self.matchable_scopes(env)
85
+ config = env.config
86
+
87
+ scopes = env.world.object_space.each_object(Module).each_with_object([]) do |scope, aggregate|
87
88
  expression = expression(config.reporter, config.expression_parser, scope) || next
88
89
  aggregate << Scope.new(scope, expression)
89
90
  end
@@ -23,9 +23,11 @@ module Mutant
23
23
  end
24
24
 
25
25
  def bootstrap
26
- Config.load_config_file(world)
26
+ env = Env.empty(world, @config)
27
+
28
+ Config.load_config_file(env)
27
29
  .fmap(&method(:expand))
28
- .bind { Bootstrap.call(world, @config) }
30
+ .bind { Bootstrap.call(env.with(config: @config)) }
29
31
  end
30
32
 
31
33
  def expand(file_config)
@@ -121,7 +123,7 @@ module Mutant
121
123
  set(jobs: Integer(number))
122
124
  end
123
125
  parser.on('-t', '--mutation-timeout NUMBER', 'Per mutation analysis timeout') do |number|
124
- set(mutation_timeout: Float(number))
126
+ set(mutation: @config.mutation.with(timeout: Float(number)))
125
127
  end
126
128
  end
127
129
  end # Run
@@ -14,6 +14,12 @@ module Mutant
14
14
  OPTIONS = %i[add_target_options].freeze
15
15
 
16
16
  def action
17
+ @ignore_patterns.map! do |syntax|
18
+ AST::Pattern.parse(syntax).from_right do |message|
19
+ return Either::Left.new(message)
20
+ end
21
+ end
22
+
17
23
  @targets.each(&method(:print_mutations))
18
24
  Either::Right.new(nil)
19
25
  end
@@ -50,18 +56,27 @@ module Mutant
50
56
  def initialize(_arguments)
51
57
  super
52
58
 
53
- @targets = []
59
+ @targets = []
60
+ @ignore_patterns = []
54
61
  end
55
62
 
56
63
  def add_target_options(parser)
57
64
  parser.on('-e', '--evaluate SOURCE') do |source|
58
65
  @targets << Target::Source.new(source)
59
66
  end
67
+
68
+ parser.on('-i', '--ignore-pattern AST_PATTERN') do |pattern|
69
+ @ignore_patterns << pattern
70
+ end
60
71
  end
61
72
 
62
73
  def print_mutations(target)
63
74
  world.stdout.puts(target.identification)
64
- Mutator.mutate(target.node).each do |mutation|
75
+
76
+ Mutator::Node.mutate(
77
+ config: Mutant::Mutation::Config::DEFAULT.with(ignore_patterns: @ignore_patterns),
78
+ node: target.node
79
+ ).each do |mutation|
65
80
  Reporter::CLI::Printer::Mutation.call(
66
81
  world.stdout,
67
82
  Mutant::Mutation::Evil.new(target, mutation)