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
@@ -63,6 +63,17 @@ module Mutant
63
63
  failed_mutations.empty?
64
64
  end
65
65
 
66
+ # Return tests used to kill mutations on this subject
67
+ #
68
+ # @return [Enumerable<Test>]
69
+ #
70
+ # @api private
71
+ #
72
+ def tests
73
+ config.strategy.tests(subject)
74
+ end
75
+ memoize :tests
76
+
66
77
  private
67
78
 
68
79
  # Perform operation
@@ -72,10 +83,9 @@ module Mutant
72
83
  # @api private
73
84
  #
74
85
  def run
75
- subject = self.subject
76
- report(subject)
77
- @mutations = dispatch(subject.mutations)
78
- report(self)
86
+ progress(subject)
87
+ @mutations = visit_collection(subject.mutations, tests)
88
+ progress(self)
79
89
  end
80
90
 
81
91
  end # Subject
@@ -54,39 +54,53 @@ module Mutant
54
54
  self
55
55
  end
56
56
 
57
- # Kill mutation
57
+ # Return all available tests by strategy
58
58
  #
59
- # @param [Mutation] mutation
60
- #
61
- # @return [Killer]
59
+ # @return [Enumerable<Test>]
62
60
  #
63
61
  # @api private
64
62
  #
65
- def kill(mutation)
66
- killer.new(self, mutation)
67
- end
63
+ abstract_method :all_tests
68
64
 
69
- private
70
-
71
- # Return killer
65
+ # Return tests for mutation
66
+ #
67
+ # TODO: This logic is now centralized but still fucked.
72
68
  #
73
- # @return [Class:Killer]
69
+ # @param [Mutation] mutation
70
+ #
71
+ # @return [Enumerable<Test>]
74
72
  #
75
73
  # @api private
76
74
  #
77
- def killer
78
- self.class::KILLER
75
+ def tests(subject)
76
+ subject.match_prefixes.map do |match_expression|
77
+ tests = all_tests.select do |test|
78
+ test.subject_identification.start_with?(match_expression)
79
+ end
80
+ return tests if tests.any?
81
+ end
82
+
83
+ []
79
84
  end
80
85
 
86
+ private
87
+
81
88
  # Null strategy that never kills a mutation
82
89
  class Null < self
83
90
 
84
- register 'null'
91
+ register('null')
85
92
 
86
- KILLER = Killer::Null
93
+ # Return all tests
94
+ #
95
+ # @return [Enumerable<Test>]
96
+ #
97
+ # @api private
98
+ #
99
+ def all_tests
100
+ EMPTY_ARRAY
101
+ end
87
102
 
88
103
  end # Null
89
104
 
90
105
  end # Strategy
91
-
92
106
  end # Mutant
@@ -68,7 +68,7 @@ module Mutant
68
68
  #
69
69
  def prepare
70
70
  scope.send(:memoized_methods).instance_variable_get(:@memory).delete(name)
71
- scope.send(:undef_method, name)
71
+ super
72
72
  self
73
73
  end
74
74
 
@@ -0,0 +1,86 @@
1
+ module Mutant
2
+ # Abstract base class for test that might kill a mutation
3
+ class Test
4
+ include AbstractType, Adamantium::Flat
5
+
6
+ # Object to report test status
7
+ class Report
8
+ include Adamantium::Flat, Anima::Update, Anima.new(
9
+ :test,
10
+ :output,
11
+ :success
12
+ )
13
+
14
+ alias_method :success?, :success
15
+
16
+ # Test if test failed
17
+ #
18
+ # @return [Boolean]
19
+ #
20
+ # @api private
21
+ #
22
+ def failed?
23
+ !success?
24
+ end
25
+
26
+ # Return marshallable data
27
+ #
28
+ # NOTE:
29
+ #
30
+ # The test is intentionally NOT part of the mashalled data.
31
+ # In rspec the example group cannot deterministically being marshalled, because
32
+ # they reference a crazy mix of IO objects, global objects etc.
33
+ #
34
+ # @return [Array]
35
+ #
36
+ # @api private
37
+ #
38
+ def marshal_dump
39
+ [@output, @success]
40
+ end
41
+
42
+ # Load marshalled data
43
+ #
44
+ # @param [Array] arry
45
+ #
46
+ # @return [undefined]
47
+ #
48
+ # @api private
49
+ #
50
+ def marshal_load(array)
51
+ @output, @success = array
52
+ end
53
+
54
+ end # Report
55
+
56
+ # Run tests
57
+ #
58
+ # @return [Test::Result]
59
+ #
60
+ # @api private
61
+ #
62
+ abstract_method :run
63
+
64
+ # Return test identification
65
+ #
66
+ # @return [String]
67
+ #
68
+ # @api private
69
+ #
70
+ def identification
71
+ "#{self.class::PREFIX}:#{subject_identification}"
72
+ end
73
+ memoize :identification
74
+
75
+ # Return subject identification
76
+ #
77
+ # This method is used for current mutants primitive test selection.
78
+ #
79
+ # @return [String]
80
+ #
81
+ # @api private
82
+ #
83
+ abstract_method :subject_identification
84
+
85
+ end # Test
86
+ end # Mutant
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Mutant
4
4
  # The current mutant version
5
- VERSION = '0.5.12'.freeze
5
+ VERSION = '0.5.13'.freeze
6
6
  end # Mutant
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'null integration' do
6
+
7
+ let(:base_cmd) { 'bundle exec mutant -I lib --require test_app "::TestApp*"' }
8
+
9
+ around do |example|
10
+ Dir.chdir(TestApp.root) do
11
+ example.run
12
+ end
13
+ end
14
+
15
+ specify 'it allows to kill mutations' do
16
+ expect(Kernel.system(base_cmd)).to be(false)
17
+ end
18
+ end
@@ -10,7 +10,7 @@ describe 'rspec integration' do
10
10
  around do |example|
11
11
  Bundler.with_clean_env do
12
12
  Dir.chdir(TestApp.root) do
13
- Kernel.system("bundle install --gemfile=#{gemfile}")
13
+ Kernel.system("bundle install --gemfile=#{gemfile}") || fail('Bundle install failed!')
14
14
  ENV['BUNDLE_GEMFILE'] = gemfile
15
15
  example.run
16
16
  end
@@ -2,11 +2,9 @@
2
2
 
3
3
  if ENV['COVERAGE'] == 'true'
4
4
  require 'simplecov'
5
- require 'coveralls'
6
5
 
7
6
  SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
8
7
  SimpleCov::Formatter::HTMLFormatter,
9
- Coveralls::SimpleCov::Formatter
10
8
  ]
11
9
 
12
10
  SimpleCov.start do
@@ -0,0 +1,162 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Mutant::Diff do
6
+ let(:object) { described_class }
7
+
8
+ describe '.build' do
9
+
10
+ subject { object.build(old_string, new_string) }
11
+
12
+ let(:old_string) { "foo\nbar" }
13
+ let(:new_string) { "bar\nbaz" }
14
+
15
+ it { should eql(Mutant::Diff.new(%w(foo bar), %w(bar baz))) }
16
+
17
+ end
18
+
19
+ describe '.colorize_line' do
20
+ let(:object) { described_class }
21
+
22
+ subject { object.colorize_line(line) }
23
+
24
+ context 'line beginning with "+"' do
25
+ let(:line) { '+line' }
26
+
27
+ it { should eql(Mutant::Color::GREEN.format(line)) }
28
+ end
29
+
30
+ context 'line beginning with "-"' do
31
+ let(:line) { '-line' }
32
+
33
+ it { should eql(Mutant::Color::RED.format(line)) }
34
+ end
35
+
36
+ context 'line beginning in other char' do
37
+ let(:line) { ' line' }
38
+
39
+ it { should eql(line) }
40
+ end
41
+ end
42
+
43
+ describe '#diff' do
44
+ let(:object) { described_class.new(old, new) }
45
+
46
+ subject { object.diff }
47
+
48
+ context 'when there is a diff at begin of hunk' do
49
+ let(:old) { %w(foo bar) }
50
+ let(:new) { %w(baz bar) }
51
+
52
+ let(:expectation) do
53
+ strip_indent(<<-STR)
54
+ @@ -1,3 +1,3 @@
55
+ -foo
56
+ +baz
57
+ bar
58
+ STR
59
+ end
60
+
61
+ it { should eql(expectation) }
62
+
63
+ it_should_behave_like 'an idempotent method'
64
+ end
65
+
66
+ context 'when there is a diff NOT at begin of hunk' do
67
+ let(:old) { %w(foo bar) }
68
+ let(:new) { %w(foo baz bar) }
69
+
70
+ let(:expectation) do
71
+ strip_indent(<<-STR)
72
+ @@ -1,3 +1,4 @@
73
+ foo
74
+ +baz
75
+ bar
76
+ STR
77
+ end
78
+
79
+ it { should eql(expectation) }
80
+
81
+ it_should_behave_like 'an idempotent method'
82
+ end
83
+
84
+ context 'when the diff has a long context at begin' do
85
+ let(:old) { %w(foo bar baz boz a b c) }
86
+ let(:new) { %w(foo bar baz boz a b c other) }
87
+
88
+ let(:expectation) do
89
+ strip_indent(<<-STR)
90
+ @@ -1,8 +1,9 @@
91
+ foo
92
+ bar
93
+ baz
94
+ boz
95
+ a
96
+ b
97
+ c
98
+ +other
99
+ STR
100
+ end
101
+
102
+ it { should eql(expectation) }
103
+
104
+ it_should_behave_like 'an idempotent method'
105
+ end
106
+
107
+ context 'when the diff has a long context at end, deleting' do
108
+ let(:old) { %w(other foo bar baz boz a b c) }
109
+ let(:new) { %w(foo bar baz boz a b c) }
110
+
111
+ let(:expectation) do
112
+ strip_indent(<<-STR)
113
+ @@ -1,9 +1,8 @@
114
+ -other
115
+ foo
116
+ bar
117
+ baz
118
+ boz
119
+ a
120
+ b
121
+ c
122
+ STR
123
+ end
124
+
125
+ it { should eql(expectation) }
126
+
127
+ it_should_behave_like 'an idempotent method'
128
+ end
129
+
130
+ context 'when the diff has a long context at end, inserting' do
131
+ let(:old) { %w(foo bar baz boz a b c) }
132
+ let(:new) { %w(other foo bar baz boz a b c) }
133
+
134
+ let(:expectation) do
135
+ strip_indent(<<-STR)
136
+ @@ -1,8 +1,9 @@
137
+ +other
138
+ foo
139
+ bar
140
+ baz
141
+ boz
142
+ a
143
+ b
144
+ c
145
+ STR
146
+ end
147
+
148
+ it { should eql(expectation) }
149
+
150
+ it_should_behave_like 'an idempotent method'
151
+ end
152
+
153
+ context 'when there is no diff' do
154
+ let(:old) { '' }
155
+ let(:new) { '' }
156
+
157
+ it { should be(nil) }
158
+
159
+ it_should_behave_like 'an idempotent method'
160
+ end
161
+ end
162
+ end
@@ -4,10 +4,13 @@ require 'spec_helper'
4
4
 
5
5
  describe Mutant::Mutation do
6
6
 
7
- let(:class_under_test) { Class.new(described_class) { memoize :identification } }
8
- let(:object) { class_under_test.new(mutation_subject, Mutant::NodeHelpers::N_NIL) }
9
- let(:mutation_subject) { double('Subject', identification: 'subject', source: 'original') }
10
- let(:node) { double('Node') }
7
+ class TestMutation < Mutant::Mutation
8
+ SYMBOL = 'test'
9
+ end
10
+
11
+ let(:object) { TestMutation.new(mutation_subject, Mutant::NodeHelpers::N_NIL) }
12
+ let(:mutation_subject) { double('Subject', identification: 'subject', source: 'original') }
13
+ let(:node) { double('Node') }
11
14
 
12
15
  describe '#code' do
13
16
  subject { object.code }
@@ -37,7 +40,7 @@ describe Mutant::Mutation do
37
40
 
38
41
  subject { object.identification }
39
42
 
40
- it { should eql('subject:8771a') }
43
+ it { should eql('test:subject:8771a') }
41
44
 
42
45
  it_should_behave_like 'an idempotent method'
43
46
  end
@@ -3,25 +3,17 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Mutant::Mutator::Node::OpAsgn, 'and_asgn' do
6
- let(:random_fixnum) { 5 }
7
- let(:random_string) { 'random' }
8
-
9
6
  let(:source) { 'a &&= 1' }
10
7
 
11
8
  let(:mutations) do
12
9
  mutations = []
13
- mutations << 'srandom &&= 1'
10
+ mutations << 'a__mutant__ &&= 1'
14
11
  mutations << 'a &&= nil'
15
12
  mutations << 'a &&= 0'
16
13
  mutations << 'a &&= -1'
17
14
  mutations << 'a &&= 2'
18
- mutations << 'a &&= 5'
19
15
  mutations << 'nil'
20
16
  end
21
17
 
22
- before do
23
- Mutant::Random.stub(fixnum: random_fixnum, hex_string: random_string)
24
- end
25
-
26
18
  it_should_behave_like 'a mutator'
27
19
  end