mutant 0.5.12 → 0.5.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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