mutant 0.6.7 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +10 -0
  3. data/README.md +1 -1
  4. data/config/flay.yml +1 -1
  5. data/config/reek.yml +11 -40
  6. data/config/rubocop.yml +1 -1
  7. data/lib/mutant.rb +10 -2
  8. data/lib/mutant/actor.rb +64 -0
  9. data/lib/mutant/actor/actor.rb +50 -0
  10. data/lib/mutant/actor/env.rb +35 -0
  11. data/lib/mutant/actor/mailbox.rb +53 -0
  12. data/lib/mutant/actor/receiver.rb +48 -0
  13. data/lib/mutant/actor/sender.rb +27 -0
  14. data/lib/mutant/ast/types.rb +1 -1
  15. data/lib/mutant/cli.rb +2 -0
  16. data/lib/mutant/config.rb +2 -1
  17. data/lib/mutant/env.rb +6 -2
  18. data/lib/mutant/expression/methods.rb +1 -1
  19. data/lib/mutant/integration.rb +11 -1
  20. data/lib/mutant/isolation.rb +1 -2
  21. data/lib/mutant/meta/example.rb +1 -1
  22. data/lib/mutant/mutation.rb +47 -21
  23. data/lib/mutant/mutator/node.rb +1 -1
  24. data/lib/mutant/mutator/node/literal/symbol.rb +1 -1
  25. data/lib/mutant/mutator/node/send.rb +4 -3
  26. data/lib/mutant/reporter/cli.rb +2 -0
  27. data/lib/mutant/reporter/cli/format.rb +23 -36
  28. data/lib/mutant/reporter/cli/printer.rb +66 -27
  29. data/lib/mutant/result.rb +45 -58
  30. data/lib/mutant/runner.rb +47 -154
  31. data/lib/mutant/runner/master.rb +174 -0
  32. data/lib/mutant/runner/scheduler.rb +141 -0
  33. data/lib/mutant/runner/worker.rb +93 -0
  34. data/lib/mutant/subject/method/instance.rb +1 -15
  35. data/lib/mutant/test.rb +2 -15
  36. data/lib/mutant/version.rb +1 -1
  37. data/meta/send.rb +16 -0
  38. data/mutant-rspec.gemspec +1 -1
  39. data/mutant.gemspec +1 -1
  40. data/spec/integration/mutant/rspec_spec.rb +0 -6
  41. data/spec/spec_helper.rb +9 -1
  42. data/spec/support/fake_actor.rb +93 -0
  43. data/spec/support/shared_context.rb +135 -0
  44. data/spec/unit/mutant/actor/actor_spec.rb +35 -0
  45. data/spec/unit/mutant/actor/binding_spec.rb +32 -0
  46. data/spec/unit/mutant/actor/env_spec.rb +49 -0
  47. data/spec/unit/mutant/actor/message_spec.rb +23 -0
  48. data/spec/unit/mutant/actor/receiver_spec.rb +60 -0
  49. data/spec/unit/mutant/actor/sender_spec.rb +22 -0
  50. data/spec/unit/mutant/cli_spec.rb +17 -4
  51. data/spec/unit/mutant/env_spec.rb +2 -2
  52. data/spec/unit/mutant/mailbox_spec.rb +33 -0
  53. data/spec/unit/mutant/mutation_spec.rb +52 -18
  54. data/spec/unit/mutant/mutator/registry_spec.rb +4 -4
  55. data/spec/unit/mutant/reporter/cli_spec.rb +131 -249
  56. data/spec/unit/mutant/result/env_spec.rb +55 -0
  57. data/spec/unit/mutant/result/subject_spec.rb +43 -0
  58. data/spec/unit/mutant/runner/master_spec.rb +199 -0
  59. data/spec/unit/mutant/runner/scheduler_spec.rb +161 -0
  60. data/spec/unit/mutant/runner/worker_spec.rb +73 -0
  61. data/spec/unit/mutant/runner_spec.rb +60 -118
  62. data/spec/unit/mutant/subject/method/instance_spec.rb +18 -31
  63. data/spec/unit/mutant/warning_filter_spec.rb +1 -1
  64. metadata +39 -14
  65. data/lib/mutant/runner/collector.rb +0 -133
  66. data/lib/mutant/warning_expectation.rb +0 -47
  67. data/spec/unit/mutant/runner/collector_spec.rb +0 -198
  68. data/spec/unit/mutant/test_spec.rb +0 -23
  69. data/spec/unit/mutant/warning_expectation_spec.rb +0 -80
  70. data/test_app/Gemfile.rspec2 +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 11e3b674e08512b58bd258c3ab1434bdf684d71a
4
- data.tar.gz: f1c0559335e982f5348d6fb71c4ed2f7ae01b5b4
3
+ metadata.gz: 607569850361ac4088176c89f75ac7f7d732d8f0
4
+ data.tar.gz: 3247e38171198bf00c53341447881cb76fa44a3f
5
5
  SHA512:
6
- metadata.gz: d7decc3ff8888ea325265bfaf8ea098ee4656a9254978c72b0561997944cdf287d003a724ff9511ec2d15355e708b070f10c7d5561a107bfdfb5eec21bcd3263
7
- data.tar.gz: 9e229f14f8b9b808ab72293ac15855627cd821cdf151413aa38dfd5fd3815c64c11eb37665cca847652c98db90c51f50ec53c2afa1c6e27ae2f9bf3185fd3094
6
+ metadata.gz: 888a9f29aa202635ece333e17c514ca52c7a28660e0ab8cd7f4397f4f108be3a8d91477812ad48ae970f2808b1516de084f44ff02f743b21174ad2504fb4cdae
7
+ data.tar.gz: 5e3faa4096046383aa51274b6f201fb3f1eb416d7f8ca8049505fcf823fd994f051c34dd159256a6926e56401f5270d859b0bad0f13b645101442bfff5e80ef6
data/Changelog.md CHANGED
@@ -1,3 +1,13 @@
1
+ # v0.7.1 2014-12-04
2
+
3
+ * Fix invalid dependencies on rspec for mutant-rspec
4
+
5
+ # v0.7.0 2014-12-04
6
+
7
+ * Use homegrown actor based parallelization
8
+ * Fix redundant spec execution in rspec integration
9
+ * Add mutation from #send to #__send__ (the canonical form).
10
+
1
11
  # v0.6.7 2014-11-17
2
12
 
3
13
  * Fix duplicate neutral emit for memoized instance method subjects
data/README.md CHANGED
@@ -97,7 +97,7 @@ This can have the following unintended effects:
97
97
  counts the mutation as killed.
98
98
 
99
99
  * MRI crashes with a segfault and gets stuck when handling the segfault.
100
- Depending on the number of active kill jobs mutant might appear to continue normally untill
100
+ Depending on the number of active kill jobs mutant might appear to continue normally until
101
101
  all workers are stuck into this state when it begins to hang.
102
102
  Currently mutant must assume that your test suite simply not terminated yet as from the outside
103
103
  (parent process) the difference between a long running test and a stuck MRI is not observable.
data/config/flay.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 18
3
- total_score: 1132
3
+ total_score: 1141
data/config/reek.yml CHANGED
@@ -12,7 +12,6 @@ ControlParameter:
12
12
  enabled: true
13
13
  exclude:
14
14
  - Mutant::Expression#match_length
15
- - Mutant::Reporter::CLI::Printer::SubjectProgress#print_mutation_result
16
15
  DataClump:
17
16
  enabled: true
18
17
  exclude: []
@@ -26,24 +25,18 @@ DuplicateMethodCall:
26
25
  FeatureEnvy:
27
26
  enabled: true
28
27
  exclude:
29
- # Nature of OptionParser :(
30
- - Mutant::CLI#add_environment_options
31
28
  - Mutant::Env#scope_name
32
29
  - Mutant::Diff#minimized_hunks
33
- - Mutant::Integration::Rspec#run
34
- - Mutant::Integration::Rspec::Rspec2#full_description
35
- - Mutant::Integration::Rspec::Rspec3#full_description
30
+ - Mutant::Integration::Rspec#parse_example
36
31
  - Mutant::Matcher::Method::Instance#match?
37
32
  - Mutant::Matcher::Method::Singleton#receiver?
38
- - Mutant::Mutation::Evil#success?
39
- - Mutant::Mutation::Neutral#success?
40
33
  - Mutant::Mutator::Node#children_indices
41
- # False positive, its a utility
42
- - Mutant::Meta::Example::Verification#format_mutation
34
+ - Mutant::Meta::Example::Verification#format_mutation # False positive, its a utility
43
35
  - Mutant::Reporter::CLI#subject_results
44
- - Mutant::Runner#run_mutation_test
45
- - Mutant::Runner#kill_mutation
46
36
  - Mutant::Runner#finish
37
+ - Mutant::Runner::Master#stop_worker
38
+ - Mutant::Runner::Worker#run_mutation
39
+ - Mutant::Runner::Worker#handle
47
40
  IrresponsibleModule:
48
41
  enabled: true
49
42
  exclude: []
@@ -51,8 +44,6 @@ LongParameterList:
51
44
  enabled: true
52
45
  exclude:
53
46
  - Mutant::Matcher::Method::Instance#self.build?
54
- - Mutant::Runner#finish # API client of parallel, one gets _ignored.
55
- - Mutant::Runner#self.run
56
47
  max_params: 2
57
48
  LongYieldList:
58
49
  enabled: true
@@ -63,7 +54,6 @@ NestedIterators:
63
54
  exclude:
64
55
  - Mutant#self.singleton_subclass_instance
65
56
  - Mutant::CLI#parse
66
- - Mutant::Integration::Rspec#run
67
57
  - Mutant::Isolation::Fork#self.call
68
58
  - Mutant::Mutator::Util::Array::Element#dispatch
69
59
  - Mutant::Mutator::Node::Resbody#mutate_captures
@@ -80,41 +70,31 @@ RepeatedConditional:
80
70
  enabled: true
81
71
  exclude:
82
72
  - Mutant::Mutator
83
- - Mutant::Reporter::CLI
84
73
  - Mutant::Meta::Example::DSL
74
+ - Mutant::Runner::Master
85
75
  max_ifs: 1
86
76
  TooManyInstanceVariables:
87
77
  enabled: true
88
78
  exclude:
89
79
  - Mutant::Mutator # 4 vars
90
- - Mutant::Runner # 4 vars
80
+ - Mutant::Runner::Master # 4 vars
81
+ - Mutant::Runner::Scheduler # 4 vars
91
82
  max_instance_variables: 3
92
83
  TooManyMethods:
93
84
  enabled: true
94
85
  exclude:
95
86
  - Mutant::CLI
96
- - Mutant::Subject
97
87
  - Mutant::Mutator::Node
98
- - Mutant::Reporter::CLI
99
- - Mutant::Runner
100
88
  - Mutant::Meta::Example::Verification
101
89
  max_methods: 10
102
90
  TooManyStatements:
103
91
  enabled: true
104
92
  exclude:
105
- - Mutant#self.singleton_subclass_instance
106
- - Mutant::Integration::Rspec#run
107
93
  - Mutant::Isolation::Fork#self.call
108
- - Mutant::Reporter::CLI#colorized_diff
109
94
  - Mutant::Reporter::CLI::Printer::EnvProgress#run
110
95
  - Mutant::Reporter::CLI::Printer::Config#run
111
- - Mutant::RequireHighjack#infect
112
- - Mutant::Rspec::Killer#run
113
- - Mutant::Runner#visit_collection
114
96
  - Mutant::Runner#initialize
115
- - Mutant::Runner::Mutation#run
116
97
  - Mutant::Zombifier::File#self.find
117
- - Mutant::CLI#add_debug_options
118
98
  - Mutant::CLI#add_environment_options
119
99
  max_statements: 7
120
100
  UncommunicativeMethodName:
@@ -129,9 +109,7 @@ UncommunicativeMethodName:
129
109
  accept: []
130
110
  UncommunicativeModuleName:
131
111
  enabled: true
132
- exclude:
133
- - Rspec2
134
- - Rspec3
112
+ exclude: []
135
113
  reject:
136
114
  - !ruby/regexp /^.$/
137
115
  - !ruby/regexp /[0-9]$/
@@ -160,14 +138,7 @@ UtilityFunction:
160
138
  exclude:
161
139
  - Mutant::AST::Sexp#s
162
140
  - Mutant::CLI#reporter
163
- - Mutant::Integration::Rspec#configuration
164
- - Mutant::Integration::Rspec#options
165
- - Mutant::Integration::Rspec::Rspec2#full_description
166
- - Mutant::Integration::Rspec::Rspec2#new_reporter
167
- - Mutant::Integration::Rspec::Rspec3#full_description
168
- - Mutant::Meta::Example::Verification#format_mutation
169
- - Mutant::Mutation::Evil#success?
170
- - Mutant::Mutation::Neutral#success?
141
+ - Mutant::Integration::Rspec#parse_example
142
+ - Mutant::Meta::Example::Verification#format_mutation # False positive, its a utility
171
143
  - Mutant::Reporter::CLI::Format::Progressive#new_buffer
172
- - Mutant::Runner#run_mutation_test
173
144
  max_helper_calls: 0
data/config/rubocop.yml CHANGED
@@ -3,7 +3,7 @@ inherit_from: ../.rubocop.yml
3
3
  # General note about rubocop.
4
4
  # It does NOT allow to silence a specific rule violation.
5
5
  # For that reason I sometimes have to disable a whole cop where
6
- # I just tried to whitelist a specific occurence.
6
+ # I just tried to whitelist a specific occurrence.
7
7
 
8
8
 
9
9
  AllCops:
data/lib/mutant.rb CHANGED
@@ -100,10 +100,15 @@ require 'mutant/ast/nodes'
100
100
  require 'mutant/ast/named_children'
101
101
  require 'mutant/ast/node_predicates'
102
102
  require 'mutant/ast/meta'
103
+ require 'mutant/actor'
104
+ require 'mutant/actor/receiver'
105
+ require 'mutant/actor/sender'
106
+ require 'mutant/actor/mailbox'
107
+ require 'mutant/actor/actor'
108
+ require 'mutant/actor/env'
103
109
  require 'mutant/cache'
104
110
  require 'mutant/delegator'
105
111
  require 'mutant/warning_filter'
106
- require 'mutant/warning_expectation'
107
112
  require 'mutant/require_highjack'
108
113
  require 'mutant/isolation'
109
114
  require 'mutant/mutator'
@@ -196,7 +201,9 @@ require 'mutant/cli'
196
201
  require 'mutant/color'
197
202
  require 'mutant/diff'
198
203
  require 'mutant/runner'
199
- require 'mutant/runner/collector'
204
+ require 'mutant/runner/scheduler'
205
+ require 'mutant/runner/master'
206
+ require 'mutant/runner/worker'
200
207
  require 'mutant/result'
201
208
  require 'mutant/reporter'
202
209
  require 'mutant/reporter/null'
@@ -224,6 +231,7 @@ module Mutant
224
231
  reporter: Reporter::CLI.build($stdout),
225
232
  zombie: false,
226
233
  jobs: Mutant.ci? ? CI_DEFAULT_PROCESSOR_COUNT : Parallel.processor_count,
234
+ actor_env: Mutant::Actor::Env.new(Thread),
227
235
  expected_coverage: 100.0
228
236
  )
229
237
  end # Config
@@ -0,0 +1,64 @@
1
+ module Mutant
2
+ # A minimal actor implementation
3
+ module Actor
4
+
5
+ # Error raised when actor signalling protocol is violated
6
+ class ProtocolError < RuntimeError
7
+ end # ProtocolError
8
+
9
+ # Undefined message payload
10
+ Undefined = Class.new do
11
+ INSPECT = 'Mutant::Actor::Undefined'.freeze
12
+
13
+ # Return object inspection
14
+ #
15
+ # @return [String]
16
+ #
17
+ # @api private
18
+ #
19
+ def inspect
20
+ INSPECT
21
+ end
22
+ end.new
23
+
24
+ # Message being exchanged between actors
25
+ class Message
26
+ include Concord::Public.new(:type, :payload)
27
+
28
+ # Return new message
29
+ #
30
+ # @param [Symbol] type
31
+ # @param [Object] payload
32
+ #
33
+ # @return [Message]
34
+ #
35
+ # @api private
36
+ #
37
+ def self.new(_type, _payload = Undefined)
38
+ super
39
+ end
40
+
41
+ end # Message
42
+
43
+ # Bindin to others actors sender for simple RPC
44
+ class Binding
45
+ include Concord.new(:actor, :other)
46
+
47
+ # Send message and wait for reply
48
+ #
49
+ # @param [Symbol] type
50
+ #
51
+ # @return [Object]
52
+ #
53
+ # @api private
54
+ #
55
+ def call(type)
56
+ other.call(Message.new(type, actor.sender))
57
+ message = actor.receiver.call
58
+ fail ProtocolError, "Expected #{type} but got #{message.type}" unless type.equal?(message.type)
59
+ message.payload
60
+ end
61
+
62
+ end # Binding
63
+ end # Actor
64
+ end # Mutant
@@ -0,0 +1,50 @@
1
+ module Mutant
2
+ module Actor
3
+ # Actor object available to acting threads
4
+ class Actor
5
+ include Concord.new(:thread, :mailbox)
6
+
7
+ # Initialize object
8
+ #
9
+ # @return [undefined]
10
+ #
11
+ # @api private
12
+ #
13
+ def initialize(*)
14
+ super
15
+ @sender = mailbox.sender(thread)
16
+ end
17
+
18
+ # Return sender to this actor
19
+ #
20
+ # @return [Sender]
21
+ #
22
+ # @api private
23
+ #
24
+ attr_reader :sender
25
+
26
+ # Return receiver for messages to this actor
27
+ #
28
+ # @return [Receiver]
29
+ #
30
+ # @api private
31
+ #
32
+ def receiver
33
+ mailbox.receiver
34
+ end
35
+
36
+ # Return binding for RPC to other actors
37
+ #
38
+ # @param [Actor::Sender] other
39
+ #
40
+ # @return [Binding]
41
+ #
42
+ # @api private
43
+ #
44
+ def bind(other)
45
+ Binding.new(self, other)
46
+ end
47
+
48
+ end # Actor
49
+ end # Actor
50
+ end # Mutant
@@ -0,0 +1,35 @@
1
+ module Mutant
2
+ module Actor
3
+ # Actor root environment
4
+ class Env
5
+ include Concord.new(:thread_root)
6
+
7
+ # Spawn a new actor executing block
8
+ #
9
+ # @return [Actor::Sender]
10
+ #
11
+ # @api private
12
+ #
13
+ def spawn
14
+ mailbox = Mailbox.new
15
+
16
+ thread = thread_root.new do
17
+ yield mailbox.actor(thread_root.current)
18
+ end
19
+
20
+ mailbox.sender(thread)
21
+ end
22
+
23
+ # Return an private actor for current thread
24
+ #
25
+ # @return [Actor::Private]
26
+ #
27
+ # @api private
28
+ #
29
+ def current
30
+ Mailbox.new.actor(thread_root.current)
31
+ end
32
+
33
+ end # Env
34
+ end # Actor
35
+ end # Mutant
@@ -0,0 +1,53 @@
1
+ module Mutant
2
+ module Actor
3
+ # Unbound mailbox
4
+ class Mailbox
5
+
6
+ # Initialize new unbound mailbox
7
+ #
8
+ # @return [undefined]
9
+ #
10
+ # @api private
11
+ #
12
+ def initialize
13
+ @mutex = Mutex.new
14
+ @messages = []
15
+ @receiver = Receiver.new(@mutex, @messages)
16
+ freeze
17
+ end
18
+
19
+ # Return receiver
20
+ #
21
+ # @return [Receiver]
22
+ #
23
+ # @api private
24
+ #
25
+ attr_reader :receiver
26
+
27
+ # Return actor that is able to read mailbox
28
+ #
29
+ # @param [Thread] thread
30
+ #
31
+ # @return [Actor]
32
+ #
33
+ # @api private
34
+ #
35
+ def actor(thread)
36
+ Actor.new(thread, self)
37
+ end
38
+
39
+ # Return sender to mailbox
40
+ #
41
+ # @param [Thread] thread
42
+ #
43
+ # @return [Sender]
44
+ #
45
+ # @api private
46
+ #
47
+ def sender(thread)
48
+ Sender.new(thread, @mutex, @messages)
49
+ end
50
+
51
+ end # Mailbox
52
+ end # Actor
53
+ end # Mutant
@@ -0,0 +1,48 @@
1
+ module Mutant
2
+ module Actor
3
+ # Receiver side of an actor
4
+ class Receiver
5
+ include Concord.new(:mutex, :mailbox)
6
+
7
+ # Receives a message, blocking
8
+ #
9
+ # @return [Object]
10
+ #
11
+ # @api private
12
+ #
13
+ def call
14
+ 2.times do
15
+ message = try_blocking_receive
16
+ return message unless message.equal?(Undefined)
17
+ end
18
+ fail ProtocolError
19
+ end
20
+
21
+ private
22
+
23
+ # Try a blocking receive
24
+ #
25
+ # @return [Undefined]
26
+ # if there is no message yet
27
+ #
28
+ # @return [Object]
29
+ # if there is a message
30
+ #
31
+ # @api private
32
+ #
33
+ def try_blocking_receive
34
+ mutex.lock
35
+ if mailbox.empty?
36
+ mutex.unlock
37
+ Thread.stop
38
+ Undefined
39
+ else
40
+ mailbox.shift.tap do
41
+ mutex.unlock
42
+ end
43
+ end
44
+ end
45
+
46
+ end # Receiver
47
+ end # Actor
48
+ end # Mutant