mutant 0.7.4 → 0.7.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -2
  3. data/Changelog.md +6 -2
  4. data/Gemfile +1 -0
  5. data/config/flay.yml +1 -1
  6. data/config/reek.yml +1 -1
  7. data/lib/mutant.rb +4 -3
  8. data/lib/mutant/cli.rb +2 -2
  9. data/lib/mutant/config.rb +2 -3
  10. data/lib/mutant/env.rb +29 -132
  11. data/lib/mutant/env/bootstrap.rb +155 -0
  12. data/lib/mutant/expression.rb +27 -0
  13. data/lib/mutant/expression/namespace.rb +2 -2
  14. data/lib/mutant/matcher/method.rb +1 -1
  15. data/lib/mutant/matcher/method/instance.rb +1 -1
  16. data/lib/mutant/mutation.rb +2 -30
  17. data/lib/mutant/mutator/node/begin.rb +1 -3
  18. data/lib/mutant/mutator/node/if.rb +2 -2
  19. data/lib/mutant/reporter/cli/printer.rb +5 -4
  20. data/lib/mutant/result.rb +1 -1
  21. data/lib/mutant/runner.rb +3 -3
  22. data/lib/mutant/runner/sink.rb +86 -53
  23. data/lib/mutant/selector.rb +17 -0
  24. data/lib/mutant/selector/expression.rb +28 -0
  25. data/lib/mutant/subject.rb +1 -19
  26. data/lib/mutant/version.rb +1 -1
  27. data/mutant.gemspec +3 -3
  28. data/spec/spec_helper.rb +1 -1
  29. data/spec/support/corpus.rb +5 -5
  30. data/spec/support/shared_context.rb +1 -6
  31. data/spec/unit/mutant/cli_spec.rb +2 -2
  32. data/spec/unit/mutant/env/boostrap_spec.rb +130 -0
  33. data/spec/unit/mutant/env_spec.rb +61 -49
  34. data/spec/unit/mutant/expression_spec.rb +13 -0
  35. data/spec/unit/mutant/matcher/filter_spec.rb +1 -1
  36. data/spec/unit/mutant/matcher/method/instance_spec.rb +1 -1
  37. data/spec/unit/mutant/matcher/method/singleton_spec.rb +1 -1
  38. data/spec/unit/mutant/mutation_spec.rb +0 -36
  39. data/spec/unit/mutant/reporter/trace_spec.rb +1 -1
  40. data/spec/unit/mutant/require_highjack_spec.rb +2 -4
  41. data/spec/unit/mutant/result/subject_spec.rb +2 -1
  42. data/spec/unit/mutant/runner/{sink_spec.rb → sink/mutation_spec.rb} +1 -3
  43. data/spec/unit/mutant/runner_spec.rb +4 -3
  44. data/spec/unit/mutant/selector/expression_spec.rb +60 -0
  45. data/spec/unit/mutant/subject/method/instance_spec.rb +3 -5
  46. data/spec/unit/mutant/subject/method/singleton_spec.rb +2 -3
  47. data/spec/unit/mutant/subject_spec.rb +1 -53
  48. data/spec/unit/mutant/warning_filter_spec.rb +2 -4
  49. metadata +18 -15
  50. data/lib/mutant/line_trace.rb +0 -34
  51. data/spec/unit/mutant/line_trace_spec.rb +0 -38
  52. data/spec/unit/mutant/subject/context_spec.rb +0 -16
@@ -37,6 +37,33 @@ module Mutant
37
37
  @inspect = format(INSPECT_FORMAT, syntax)
38
38
  end
39
39
 
40
+ # Return marshallable representation
41
+ #
42
+ # FIXME: Remove the need for this.
43
+ #
44
+ # Refactoring Expression objects not to reference a MatchData instance.
45
+ # This will make this hack unneeded.
46
+ #
47
+ # @return [String]
48
+ #
49
+ # @api private
50
+ #
51
+ def _dump(_level)
52
+ syntax
53
+ end
54
+
55
+ # Load serializable representation
56
+ #
57
+ # @return [String]
58
+ #
59
+ # @return [Expression]
60
+ #
61
+ # @api private
62
+ #
63
+ def self._load(syntax)
64
+ parse(syntax)
65
+ end
66
+
40
67
  # Return inspection
41
68
  #
42
69
  # @return [String]
@@ -37,7 +37,7 @@ module Mutant
37
37
 
38
38
  # Return matcher
39
39
  #
40
- # @param [Env] env
40
+ # @param [Env::Bootstrap] env
41
41
  #
42
42
  # @return [Matcher]
43
43
  #
@@ -74,7 +74,7 @@ module Mutant
74
74
 
75
75
  # Return matcher
76
76
  #
77
- # @param [Cache] env
77
+ # @param [Env::Bootstrap] env
78
78
  #
79
79
  # @return [Matcher]
80
80
  #
@@ -123,7 +123,7 @@ module Mutant
123
123
  def subject
124
124
  node = matched_node_path.last
125
125
  return unless node
126
- self.class::SUBJECT_CLASS.new(env.config, context, node)
126
+ self.class::SUBJECT_CLASS.new(context, node)
127
127
  end
128
128
  memoize :subject
129
129
 
@@ -7,7 +7,7 @@ module Mutant
7
7
 
8
8
  # Dispatching builder, detects memoizable case
9
9
  #
10
- # @param [Env] env
10
+ # @param [Env::Boostrap] env
11
11
  # @param [Class, Module] scope
12
12
  # @param [UnboundMethod] method
13
13
  #
@@ -7,34 +7,6 @@ module Mutant
7
7
  CODE_DELIMITER = "\0".freeze
8
8
  CODE_RANGE = (0..4).freeze
9
9
 
10
- # Kill mutation under isolation with integration
11
- #
12
- # @param [Isolation] isolation
13
- # @param [Integration] integration
14
- #
15
- # @return [Result::Test]
16
- #
17
- # @api private
18
- #
19
- # rubocop:disable MethodLength
20
- #
21
- def kill(isolation, integration)
22
- start = Time.now
23
- tests = subject.tests
24
-
25
- isolation.call do
26
- insert
27
- integration.call(tests)
28
- end.update(tests: tests)
29
- rescue Isolation::Error => error
30
- Result::Test.new(
31
- tests: tests,
32
- output: error.message,
33
- runtime: Time.now - start,
34
- passed: false
35
- )
36
- end
37
-
38
10
  # Return identification
39
11
  #
40
12
  # @return [String]
@@ -90,8 +62,6 @@ module Mutant
90
62
  self::TEST_PASS_SUCCESS.equal?(test_result.passed)
91
63
  end
92
64
 
93
- private
94
-
95
65
  # Insert mutated node
96
66
  #
97
67
  # FIXME: Cache subject visibility in a better way! Ideally dont mutate it
@@ -109,6 +79,8 @@ module Mutant
109
79
  self
110
80
  end
111
81
 
82
+ private
83
+
112
84
  # Return sha1 sum of source and subject identification
113
85
  #
114
86
  # @return [String]
@@ -16,9 +16,7 @@ module Mutant
16
16
  # @api private
17
17
  #
18
18
  def dispatch
19
- Util::Array.each(children, self) do |children|
20
- emit_child_subset(children)
21
- end
19
+ Util::Array.each(children, self, &method(:emit_child_subset))
22
20
  children.each_with_index do |child, index|
23
21
  mutate_child(index)
24
22
  emit(child) unless children.eql?([child])
@@ -30,8 +30,8 @@ module Mutant
30
30
  # @api private
31
31
  #
32
32
  def mutate_condition
33
- emit_condition_mutations do |condition|
34
- !n_self?(condition)
33
+ emit_condition_mutations do |node|
34
+ !n_self?(node)
35
35
  end
36
36
  emit_type(n_not(condition), if_branch, else_branch) unless n_match_current_line?(condition)
37
37
  emit_type(N_TRUE, if_branch, else_branch)
@@ -201,7 +201,7 @@ module Mutant
201
201
  #
202
202
  def run
203
203
  info 'Mutant configuration:'
204
- info 'Matcher: %s', object.matcher_config.inspect
204
+ info 'Matcher: %s', object.matcher.inspect
205
205
  info 'Integration: %s', object.integration.name
206
206
  info 'Expect Coverage: %0.2f%%', object.expected_coverage.inspect
207
207
  info 'Jobs: %d', object.jobs
@@ -295,7 +295,7 @@ module Mutant
295
295
  # Subject report printer
296
296
  class SubjectResult < self
297
297
 
298
- delegate :subject, :failed_mutations
298
+ delegate :subject, :failed_mutations, :tests
299
299
 
300
300
  # Run report printer
301
301
  #
@@ -305,7 +305,7 @@ module Mutant
305
305
  #
306
306
  def run
307
307
  status(subject.identification)
308
- subject.tests.each do |test|
308
+ tests.each do |test|
309
309
  puts("- #{test.identification}")
310
310
  end
311
311
  visit_collection(MutationResult, object.alive_mutation_results)
@@ -400,6 +400,7 @@ module Mutant
400
400
  FORMAT = '(%02d/%02d) %3d%% - killtime: %0.02fs runtime: %0.02fs overhead: %0.02fs'.freeze
401
401
 
402
402
  delegate(
403
+ :tests,
403
404
  :subject,
404
405
  :coverage,
405
406
  :runtime,
@@ -452,7 +453,7 @@ module Mutant
452
453
  # @api private
453
454
  #
454
455
  def print_tests
455
- subject.tests.each do |test|
456
+ tests.each do |test|
456
457
  puts "- #{test.identification}"
457
458
  end
458
459
  end
@@ -147,7 +147,7 @@ module Mutant
147
147
 
148
148
  # Subject result
149
149
  class Subject
150
- include Coverage, Result, Anima.new(:subject, :mutation_results)
150
+ include Coverage, Result, Anima.new(:subject, :tests, :mutation_results)
151
151
 
152
152
  sum :killtime, :mutation_results
153
153
  sum :runtime, :mutation_results
@@ -72,11 +72,11 @@ module Mutant
72
72
  #
73
73
  def mutation_test_config
74
74
  Parallel::Config.new(
75
- env: config.actor_env,
75
+ env: env.actor_env,
76
76
  jobs: config.jobs,
77
77
  source: Parallel::Source::Array.new(env.mutations),
78
- sink: Sink.new(env),
79
- processor: env.method(:kill_mutation)
78
+ sink: Sink::Mutation.new(env),
79
+ processor: env.method(:kill)
80
80
  )
81
81
  end
82
82
 
@@ -1,82 +1,115 @@
1
1
  module Mutant
2
2
  class Runner
3
- # Mutation result sink
3
+ # Abstract base class for computation sinks
4
4
  class Sink
5
- include Concord.new(:env)
5
+ include AbstractType
6
6
 
7
- # Initialize object
7
+ # Return sink status
8
8
  #
9
- # @return [undefined]
9
+ # @return [Object]
10
10
  #
11
11
  # @api private
12
12
  #
13
- def initialize(*)
14
- super
15
- @start = Time.now
16
- @subject_results = Hash.new do |_hash, subject|
17
- Result::Subject.new(
18
- subject: subject,
19
- mutation_results: []
20
- )
21
- end
22
- end
23
-
24
- # Return runner status
25
- #
26
- # @return [Status]
27
- #
28
- # @api private
29
- #
30
- def status
31
- env_result
32
- end
13
+ abstract_method :status
33
14
 
34
- # Test if scheduling stopped
15
+ # Test if computation should be stopped
35
16
  #
36
17
  # @return [Boolean]
37
18
  #
38
19
  # @api private
39
20
  #
40
- def stop?
41
- env.config.fail_fast && !env_result.subject_results.all?(&:success?)
42
- end
21
+ abstract_method :stop?
43
22
 
44
- # Handle mutation finish
23
+ # Consume result
45
24
  #
46
- # @param [Result::Mutation] mutation_result
25
+ # @param [Object] result
47
26
  #
48
27
  # @return [self]
49
28
  #
50
29
  # @api private
51
30
  #
52
- def result(mutation_result)
53
- mutation = mutation_result.mutation
31
+ abstract_method :result
54
32
 
55
- original = @subject_results[mutation.subject]
33
+ # Mutation result sink
34
+ class Mutation < self
35
+ include Concord.new(:env)
56
36
 
57
- @subject_results[mutation.subject] = original.update(
58
- mutation_results: (original.mutation_results.dup << mutation_result)
59
- )
37
+ # Initialize object
38
+ #
39
+ # @return [undefined]
40
+ #
41
+ # @api private
42
+ #
43
+ def initialize(*)
44
+ super
45
+ @start = Time.now
46
+ @subject_results = Hash.new do |_hash, subject|
47
+ Result::Subject.new(
48
+ subject: subject,
49
+ tests: [],
50
+ mutation_results: []
51
+ )
52
+ end
53
+ end
60
54
 
61
- self
62
- end
55
+ # Return runner status
56
+ #
57
+ # @return [Status]
58
+ #
59
+ # @api private
60
+ #
61
+ def status
62
+ env_result
63
+ end
63
64
 
64
- private
65
+ # Test if scheduling stopped
66
+ #
67
+ # @return [Boolean]
68
+ #
69
+ # @api private
70
+ #
71
+ def stop?
72
+ env.config.fail_fast && !env_result.subject_results.all?(&:success?)
73
+ end
65
74
 
66
- # Return current result
67
- #
68
- # @return [Result::Env]
69
- #
70
- # @api private
71
- #
72
- def env_result
73
- Result::Env.new(
74
- env: env,
75
- runtime: Time.now - @start,
76
- subject_results: @subject_results.values
77
- )
78
- end
75
+ # Handle mutation finish
76
+ #
77
+ # @param [Result::Mutation] mutation_result
78
+ #
79
+ # @return [self]
80
+ #
81
+ # @api private
82
+ #
83
+ def result(mutation_result)
84
+ mutation = mutation_result.mutation
85
+
86
+ original = @subject_results[mutation.subject]
87
+
88
+ @subject_results[mutation.subject] = original.update(
89
+ mutation_results: (original.mutation_results.dup << mutation_result),
90
+ tests: mutation_result.test_result.tests
91
+ )
92
+
93
+ self
94
+ end
95
+
96
+ private
97
+
98
+ # Return current result
99
+ #
100
+ # @return [Result::Env]
101
+ #
102
+ # @api private
103
+ #
104
+ def env_result
105
+ Result::Env.new(
106
+ env: env,
107
+ runtime: Time.now - @start,
108
+ subject_results: @subject_results.values
109
+ )
110
+ end
79
111
 
80
- end # Scheduler
112
+ end # Mutation
113
+ end # Sink
81
114
  end # Runner
82
115
  end # Mutant
@@ -0,0 +1,17 @@
1
+ module Mutant
2
+ # Abstract base class for test selectors
3
+ class Selector
4
+ include AbstractType, Adamantium::Flat
5
+
6
+ # Return tests for subject
7
+ #
8
+ # @param [Subject] subjecto
9
+ #
10
+ # @return [Enumerable<Test>]
11
+ #
12
+ # @api private
13
+ #
14
+ abstract_method :call
15
+
16
+ end # Selector
17
+ end # Mutant
@@ -0,0 +1,28 @@
1
+ module Mutant
2
+ class Selector
3
+ # Expression based test selector
4
+ class Expression < self
5
+ include Concord.new(:integration)
6
+
7
+ # Return tests for subject
8
+ #
9
+ # @param [Subject] subject
10
+ #
11
+ # @return [Enumerable<Test>]
12
+ #
13
+ # @api private
14
+ #
15
+ def call(subject)
16
+ subject.match_expressions.each do |match_expression|
17
+ subject_tests = integration.all_tests.select do |test|
18
+ match_expression.prefix?(test.expression)
19
+ end
20
+ return subject_tests if subject_tests.any?
21
+ end
22
+
23
+ EMPTY_ARRAY
24
+ end
25
+
26
+ end # Expression
27
+ end # Selector
28
+ end # Mutant
@@ -2,7 +2,7 @@ module Mutant
2
2
  # Subject of a mutation
3
3
  class Subject
4
4
  include AbstractType, Adamantium::Flat, Enumerable
5
- include Concord::Public.new(:config, :context, :node)
5
+ include Concord::Public.new(:context, :node)
6
6
 
7
7
  # Return mutations
8
8
  #
@@ -30,24 +30,6 @@ module Mutant
30
30
  context.source_path
31
31
  end
32
32
 
33
- # Return tests for mutation
34
- #
35
- # @return [Array<Test>]
36
- #
37
- # @api private
38
- #
39
- def tests
40
- match_expressions.each do |match_expression|
41
- tests = config.integration.all_tests.select do |test|
42
- match_expression.prefix?(test.expression)
43
- end
44
- return tests if tests.any?
45
- end
46
-
47
- EMPTY_ARRAY
48
- end
49
- memoize :tests
50
-
51
33
  # Prepare the subject for the insertion of mutation
52
34
  #
53
35
  # @return [self]