mutant 0.5.12 → 0.5.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +10 -0
  3. data/circle.yml +1 -1
  4. data/config/flay.yml +1 -1
  5. data/config/flog.yml +1 -1
  6. data/config/mutant.yml +1 -2
  7. data/config/reek.yml +12 -3
  8. data/config/rubocop.yml +4 -0
  9. data/lib/mutant.rb +45 -16
  10. data/lib/mutant/constants.rb +11 -11
  11. data/lib/mutant/delegator.rb +50 -0
  12. data/lib/mutant/{differ.rb → diff.rb} +5 -5
  13. data/lib/mutant/killer.rb +29 -106
  14. data/lib/mutant/matcher/method.rb +2 -11
  15. data/lib/mutant/mutation.rb +17 -3
  16. data/lib/mutant/mutation/evil.rb +2 -10
  17. data/lib/mutant/mutation/neutral.rb +4 -30
  18. data/lib/mutant/mutator/node/literal/fixnum.rb +0 -1
  19. data/lib/mutant/mutator/node/literal/float.rb +0 -1
  20. data/lib/mutant/mutator/node/literal/string.rb +0 -1
  21. data/lib/mutant/mutator/node/literal/symbol.rb +6 -2
  22. data/lib/mutant/mutator/node/named_value/variable_assignment.rb +8 -3
  23. data/lib/mutant/mutator/util/symbol.rb +3 -1
  24. data/lib/mutant/node_helpers.rb +1 -3
  25. data/lib/mutant/reporter.rb +10 -0
  26. data/lib/mutant/reporter/cli.rb +15 -2
  27. data/lib/mutant/reporter/cli/printer.rb +12 -105
  28. data/lib/mutant/reporter/cli/progress.rb +12 -0
  29. data/lib/mutant/reporter/cli/progress/config.rb +32 -0
  30. data/lib/mutant/reporter/cli/{printer/killer.rb → progress/mutation.rb} +9 -16
  31. data/lib/mutant/reporter/cli/progress/noop.rb +22 -0
  32. data/lib/mutant/reporter/cli/progress/subject.rb +118 -0
  33. data/lib/mutant/reporter/cli/registry.rb +77 -0
  34. data/lib/mutant/reporter/cli/report.rb +12 -0
  35. data/lib/mutant/reporter/cli/report/config.rb +118 -0
  36. data/lib/mutant/reporter/cli/report/mutation.rb +112 -0
  37. data/lib/mutant/reporter/cli/report/subject.rb +33 -0
  38. data/lib/mutant/reporter/null.rb +13 -0
  39. data/lib/mutant/reporter/trace.rb +41 -0
  40. data/lib/mutant/runner.rb +22 -20
  41. data/lib/mutant/runner/config.rb +6 -5
  42. data/lib/mutant/runner/killer.rb +59 -0
  43. data/lib/mutant/runner/mutation.rb +17 -10
  44. data/lib/mutant/runner/subject.rb +14 -4
  45. data/lib/mutant/strategy.rb +30 -16
  46. data/lib/mutant/subject/method/instance.rb +1 -1
  47. data/lib/mutant/test.rb +86 -0
  48. data/lib/mutant/version.rb +1 -1
  49. data/spec/integration/mutant/null_spec.rb +18 -0
  50. data/spec/integration/mutant/rspec_spec.rb +1 -1
  51. data/spec/spec_helper.rb +0 -2
  52. data/spec/unit/mutant/diff_spec.rb +162 -0
  53. data/spec/unit/mutant/mutation_spec.rb +8 -5
  54. data/spec/unit/mutant/mutator/node/and_asgn_spec.rb +1 -9
  55. data/spec/unit/mutant/mutator/node/block_spec.rb +6 -18
  56. data/spec/unit/mutant/mutator/node/case_spec.rb +10 -16
  57. data/spec/unit/mutant/mutator/node/define_spec.rb +5 -17
  58. data/spec/unit/mutant/mutator/node/dstr_spec.rb +0 -6
  59. data/spec/unit/mutant/mutator/node/dsym_spec.rb +0 -5
  60. data/spec/unit/mutant/mutator/node/if_spec.rb +13 -17
  61. data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +1 -7
  62. data/spec/unit/mutant/mutator/node/literal/float_spec.rb +0 -9
  63. data/spec/unit/mutant/mutator/node/literal/range_spec.rb +0 -10
  64. data/spec/unit/mutant/mutator/node/literal/string_spec.rb +1 -5
  65. data/spec/unit/mutant/mutator/node/literal/symbol_spec.rb +1 -5
  66. data/spec/unit/mutant/mutator/node/named_value/access_spec.rb +4 -7
  67. data/spec/unit/mutant/mutator/node/named_value/constant_assignment_spec.rb +1 -5
  68. data/spec/unit/mutant/mutator/node/named_value/variable_assignment_spec.rb +4 -8
  69. data/spec/unit/mutant/mutator/node/op_assgn_spec.rb +0 -7
  70. data/spec/unit/mutant/mutator/node/or_asgn_spec.rb +1 -9
  71. data/spec/unit/mutant/mutator/node/rescue_spec.rb +0 -4
  72. data/spec/unit/mutant/reporter/null_spec.rb +11 -0
  73. data/spec/unit/mutant/runner/config_spec.rb +6 -7
  74. data/spec/unit/mutant/runner/mutation_spec.rb +101 -0
  75. data/spec/unit/mutant/runner/subject_spec.rb +10 -7
  76. data/spec/unit/mutant_spec.rb +53 -0
  77. metadata +65 -62
  78. data/lib/mutant/killer/forked.rb +0 -46
  79. data/lib/mutant/killer/forking.rb +0 -46
  80. data/lib/mutant/killer/static.rb +0 -34
  81. data/lib/mutant/mutator/node/literal/dynamic.rb +0 -27
  82. data/lib/mutant/random.rb +0 -38
  83. data/lib/mutant/reporter/cli/printer/config.rb +0 -154
  84. data/lib/mutant/reporter/cli/printer/mutation.rb +0 -103
  85. data/lib/mutant/reporter/cli/printer/subject.rb +0 -150
  86. data/spec/unit/mutant/differ/diff_spec.rb +0 -123
  87. data/spec/unit/mutant/differ_spec.rb +0 -42
  88. data/spec/unit/mutant/killer/success_predicate_spec.rb +0 -30
  89. data/spec/unit/mutant/rspec/killer_spec.rb +0 -57
  90. data/spec/unit/mutant/runner/mutation/killer_spec.rb +0 -44
@@ -24,17 +24,8 @@ module Mutant
24
24
  def each
25
25
  return to_enum unless block_given?
26
26
 
27
- unless skip?
28
- if subject
29
- yield subject
30
- else
31
- message = sprintf(
32
- 'Cannot find definition of: %s in %s',
33
- identification,
34
- source_location.join(':')
35
- )
36
- $stderr.puts(message)
37
- end
27
+ if !skip? && subject
28
+ yield subject
38
29
  end
39
30
 
40
31
  self
@@ -6,6 +6,9 @@ module Mutant
6
6
  include AbstractType, Adamantium::Flat
7
7
  include Concord::Public.new(:subject, :node)
8
8
 
9
+ CODE_DELIMITER = "\0".freeze
10
+ CODE_RANGE = (0..4).freeze
11
+
9
12
  # Return mutated root node
10
13
  #
11
14
  # @return [Parser::AST::Node]
@@ -54,8 +57,9 @@ module Mutant
54
57
  # @api private
55
58
  #
56
59
  def identification
57
- "#{subject.identification}:#{code}"
60
+ "#{self.class::SYMBOL}:#{subject.identification}:#{code}"
58
61
  end
62
+ memoize :identification
59
63
 
60
64
  # Return mutation code
61
65
  #
@@ -64,7 +68,7 @@ module Mutant
64
68
  # @api private
65
69
  #
66
70
  def code
67
- sha1[0..4]
71
+ sha1[CODE_RANGE]
68
72
  end
69
73
  memoize :code
70
74
 
@@ -89,6 +93,16 @@ module Mutant
89
93
  subject.source
90
94
  end
91
95
 
96
+ # Test if test should fail under mutation
97
+ #
98
+ # @return [Boolean]
99
+ #
100
+ # @api private
101
+ #
102
+ def should_fail?
103
+ self.class::SHOULD_FAIL
104
+ end
105
+
92
106
  private
93
107
 
94
108
  # Return sha1 sum of source and subject identification
@@ -98,7 +112,7 @@ module Mutant
98
112
  # @api private
99
113
  #
100
114
  def sha1
101
- Digest::SHA1.hexdigest(subject.identification + 0.chr + source)
115
+ Digest::SHA1.hexdigest(subject.identification + CODE_DELIMITER + source)
102
116
  end
103
117
  memoize :sha1
104
118
 
@@ -5,16 +5,8 @@ module Mutant
5
5
  # Evul mutation
6
6
  class Evil < self
7
7
 
8
- # Return identification
9
- #
10
- # @return [String]
11
- #
12
- # @api private
13
- #
14
- def identification
15
- "evil:#{super}"
16
- end
17
- memoize :identification
8
+ SHOULD_FAIL = true
9
+ SYMBOL = 'evil'.freeze
18
10
 
19
11
  # Test if killer is successful
20
12
  #
@@ -5,41 +5,15 @@ module Mutant
5
5
  # Neutral mutation
6
6
  class Neutral < self
7
7
 
8
- SYMBOL = 'neutral'
8
+ SYMBOL = 'neutral'.freeze
9
+ SHOULD_FAIL = false
9
10
 
10
11
  # Noop mutation, special case of neutral
11
12
  class Noop < self
12
13
 
13
- SYMBOL = 'noop'
14
+ SYMBOL = 'noop'.freeze
14
15
 
15
- end
16
-
17
- # Return identification
18
- #
19
- # @return [String]
20
- #
21
- # @api private
22
- #
23
- def identification
24
- "#{self.class::SYMBOL}:#{super}"
25
- end
26
- memoize :identification
27
-
28
- # Test if killer is successful
29
- #
30
- # @param [Killer] killer
31
- #
32
- # @return [true]
33
- # if killer did NOT killed mutation
34
- #
35
- # @return [false]
36
- # otherwise
37
- #
38
- # @api private
39
- #
40
- def success?(killer)
41
- !killer.killed?
42
- end
16
+ end # Noop
43
17
 
44
18
  end # Neutral
45
19
  end # Mutation
@@ -20,7 +20,6 @@ module Mutant
20
20
  def dispatch
21
21
  emit_nil
22
22
  emit_values(values)
23
- emit_new { new_self(Random.fixnum) }
24
23
  end
25
24
 
26
25
  # Return values to mutate against
@@ -21,7 +21,6 @@ module Mutant
21
21
  emit_nil
22
22
  emit_values(values)
23
23
  emit_special_cases
24
- emit_new { new_self(Random.float) }
25
24
  end
26
25
 
27
26
  SPECIAL = [
@@ -19,7 +19,6 @@ module Mutant
19
19
  #
20
20
  def dispatch
21
21
  emit_nil
22
- emit_new { new_self(Random.hex_string) }
23
22
  end
24
23
 
25
24
  end # String
@@ -9,7 +9,9 @@ module Mutant
9
9
 
10
10
  handle(:sym)
11
11
 
12
- PREFIX = 's'
12
+ children :value
13
+
14
+ PREFIX = '__mutant__'.freeze
13
15
 
14
16
  private
15
17
 
@@ -21,7 +23,9 @@ module Mutant
21
23
  #
22
24
  def dispatch
23
25
  emit_nil
24
- emit_new { new_self((PREFIX + Random.hex_string).to_sym) }
26
+ Mutator::Util::Symbol.each(value, self) do |value|
27
+ emit_self(value)
28
+ end
25
29
  end
26
30
 
27
31
  end # Symbol
@@ -10,11 +10,15 @@ module Mutant
10
10
 
11
11
  children :name, :value
12
12
 
13
- MAP = IceNine.deep_freeze(
13
+ map = {
14
14
  gvasgn: '$',
15
15
  cvasgn: '@@',
16
16
  ivasgn: '@',
17
17
  lvasgn: ''
18
+ }
19
+
20
+ MAP = IceNine.deep_freeze(
21
+ Hash[map.map { |type, prefix| [type, [prefix, /^#{Regexp.escape(prefix)}/]] }]
18
22
  )
19
23
 
20
24
  handle(*MAP.keys)
@@ -40,8 +44,9 @@ module Mutant
40
44
  # @api private
41
45
  #
42
46
  def mutate_name
43
- prefix = MAP.fetch(node.type)
44
- Mutator::Util::Symbol.each(name, self) do |name|
47
+ prefix, regexp = MAP.fetch(node.type)
48
+ stripped = name.to_s.sub(regexp, EMPTY_STRING)
49
+ Mutator::Util::Symbol.each(stripped, self) do |name|
45
50
  emit_name(:"#{prefix}#{name}")
46
51
  end
47
52
  end
@@ -9,6 +9,8 @@ module Mutant
9
9
 
10
10
  handle(::Symbol)
11
11
 
12
+ POSTFIX = '__mutant__'.freeze
13
+
12
14
  private
13
15
 
14
16
  # Emit mutations
@@ -18,7 +20,7 @@ module Mutant
18
20
  # @api private
19
21
  #
20
22
  def dispatch
21
- emit_new { :"s#{Random.hex_string}" }
23
+ emit((input.to_s + POSTFIX).to_sym)
22
24
  end
23
25
 
24
26
  end # Symbol
@@ -13,7 +13,7 @@ module Mutant
13
13
  # @api private
14
14
  #
15
15
  def s(type, *children)
16
- ::Parser::AST::Node.new(type, children)
16
+ Parser::AST::Node.new(type, children)
17
17
  end
18
18
  module_function :s
19
19
 
@@ -21,8 +21,6 @@ module Mutant
21
21
  s(:send, s(:float, 0.0), :/, s(:float, 0.0))
22
22
  INFINITY =
23
23
  s(:send, s(:float, 1.0), :/, s(:float, 0.0))
24
- NEW_OBJECT =
25
- s(:send, s(:const, s(:cbase), :Object), :new)
26
24
  NEGATIVE_INFINITY =
27
25
  s(:send, s(:float, -1.0), :/, s(:float, 0.0))
28
26
 
@@ -15,5 +15,15 @@ module Mutant
15
15
  #
16
16
  abstract_method :report
17
17
 
18
+ # Report progress on object
19
+ #
20
+ # @param [Object] object
21
+ #
22
+ # @return [self]
23
+ #
24
+ # @api private
25
+ #
26
+ abstract_method :progress
27
+
18
28
  end # Reporter
19
29
  end # Mutant
@@ -4,10 +4,23 @@ module Mutant
4
4
  class Reporter
5
5
  # Reporter that reports in human readable format
6
6
  class CLI < self
7
- include Concord::Public.new(:output)
7
+ include Concord.new(:output)
8
8
 
9
9
  NL = "\n".freeze
10
10
 
11
+ # Report progress object
12
+ #
13
+ # @param [Object] object
14
+ #
15
+ # @return [self]
16
+ #
17
+ # @api private
18
+ #
19
+ def progress(object)
20
+ Progress.run(output, object)
21
+ self
22
+ end
23
+
11
24
  # Report object
12
25
  #
13
26
  # @param [Object] object
@@ -17,7 +30,7 @@ module Mutant
17
30
  # @api private
18
31
  #
19
32
  def report(object)
20
- Printer.visit(object, output)
33
+ Report.run(output, object)
21
34
  self
22
35
  end
23
36
 
@@ -6,120 +6,27 @@ module Mutant
6
6
 
7
7
  # CLI runner status printer base class
8
8
  class Printer
9
- include AbstractType, Adamantium::Flat, Concord.new(:object, :output)
9
+ include AbstractType, Delegator, Adamantium::Flat, Concord.new(:output, :object)
10
10
 
11
- REGISTRY = {}
12
-
13
- # Create delegators to object
14
- #
15
- # @return [undefined]
16
- #
17
- # @api private
18
- #
19
- def self.delegate(*names)
20
- names.each do |name|
21
- define_delegator(name)
22
- end
23
- end
24
- private_class_method :delegate
25
-
26
- # Create delegator to object
27
- #
28
- # @param [Symbol] name
29
- #
30
- # @return [undefined]
31
- #
32
- # @api private
33
- #
34
- def self.define_delegator(name)
35
- define_method(name) do
36
- object.public_send(name)
37
- end
38
- private name
39
- end
40
- private_class_method :define_delegator
41
-
42
- # Registre handler for class
43
- #
44
- # @param [Class] klass
45
- #
46
- # @return [undefined]
11
+ # Run printer on object to output
47
12
  #
48
- # @api private
49
- #
50
- def self.handle(klass)
51
- REGISTRY[klass] = self
52
- end
53
-
54
- # Finalize CLI reporter
55
- #
56
- # @return [undefined]
57
- #
58
- # @api private
59
- #
60
- def self.finalize
61
- REGISTRY.freeze
62
- end
63
-
64
- # Build printer
65
- #
66
- # @return [Printer]
67
- #
68
- # @api private
69
- #
70
- def self.build(*args)
71
- new(*args)
72
- end
73
-
74
- # Run printer
13
+ # @param [IO] output
14
+ # @param [Object] object
75
15
  #
76
16
  # @return [self]
77
17
  #
78
- # @api private
79
- #
80
- def self.run(*args)
81
- build(*args).run
18
+ def self.run(output, object)
19
+ handler = lookup(object.class)
20
+ handler.new(output, object).run
82
21
  self
83
22
  end
84
23
 
85
- # Visit object
86
- #
87
- # @param [Object] object
88
- # @param [IO] output
89
- #
90
- # @return [undefined]
91
- #
92
- # @api private
93
- #
94
- def self.visit(object, output)
95
- printer = lookup(object.class)
96
- printer.run(object, output)
97
- end
98
-
99
- # Lookup printer class
100
- #
101
- # @param [Class] klass
102
- #
103
- # @return [Class:Printer]
104
- # if found
24
+ # Run printer
105
25
  #
106
- # @raise [RuntimeError]
107
- # otherwise
26
+ # @return [self]
108
27
  #
109
28
  # @api private
110
29
  #
111
- def self.lookup(klass)
112
- current = klass
113
- until current == Object
114
- if REGISTRY.key?(current)
115
- return REGISTRY.fetch(current)
116
- end
117
- current = current.superclass
118
- end
119
- raise "No printer for: #{klass}"
120
- end
121
- private_class_method :lookup
122
-
123
30
  abstract_method :run
124
31
 
125
32
  private
@@ -130,7 +37,7 @@ module Mutant
130
37
  #
131
38
  # @api private
132
39
  #
133
- def color
40
+ def status_color
134
41
  success? ? Color::GREEN : Color::RED
135
42
  end
136
43
 
@@ -143,7 +50,7 @@ module Mutant
143
50
  # @api private
144
51
  #
145
52
  def visit(object)
146
- self.class.visit(object, output)
53
+ self.class.run(output, object)
147
54
  end
148
55
 
149
56
  # Print an info line to output
@@ -163,7 +70,7 @@ module Mutant
163
70
  # @api private
164
71
  #
165
72
  def status(string, *arguments)
166
- puts(colorize(color, sprintf(string, *arguments)))
73
+ puts(colorize(status_color, sprintf(string, *arguments)))
167
74
  end
168
75
 
169
76
  # Print a line to output