mutant 0.7.8 → 0.7.9

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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/Changelog.md +5 -0
  4. data/README.md +11 -29
  5. data/config/flay.yml +1 -1
  6. data/config/reek.yml +1 -0
  7. data/lib/mutant.rb +3 -3
  8. data/lib/mutant/cli.rb +12 -9
  9. data/lib/mutant/integration.rb +13 -0
  10. data/lib/mutant/meta/example.rb +2 -2
  11. data/lib/mutant/reporter/cli.rb +3 -2
  12. data/lib/mutant/reporter/cli/printer.rb +2 -2
  13. data/lib/mutant/reporter/cli/tput.rb +29 -11
  14. data/lib/mutant/result.rb +0 -2
  15. data/lib/mutant/version.rb +1 -1
  16. data/meta/and.rb +0 -2
  17. data/meta/and_asgn.rb +0 -2
  18. data/meta/array.rb +0 -2
  19. data/meta/begin.rb +0 -2
  20. data/meta/block.rb +0 -2
  21. data/meta/block_pass.rb +0 -2
  22. data/meta/blockarg.rb +0 -2
  23. data/meta/boolean.rb +0 -2
  24. data/meta/break.rb +0 -2
  25. data/meta/case.rb +0 -2
  26. data/meta/casgn.rb +0 -2
  27. data/meta/cbase.rb +0 -2
  28. data/meta/const.rb +0 -2
  29. data/meta/cvar.rb +0 -2
  30. data/meta/cvasgn.rb +0 -2
  31. data/meta/def.rb +0 -2
  32. data/meta/defined.rb +0 -2
  33. data/meta/dstr.rb +0 -2
  34. data/meta/dsym.rb +0 -2
  35. data/meta/ensure.rb +0 -2
  36. data/meta/false.rb +0 -2
  37. data/meta/float.rb +0 -2
  38. data/meta/gvar.rb +0 -2
  39. data/meta/gvasgn.rb +0 -2
  40. data/meta/hash.rb +0 -2
  41. data/meta/if.rb +0 -2
  42. data/meta/int.rb +0 -2
  43. data/meta/ivasgn.rb +0 -2
  44. data/meta/kwbegin.rb +0 -2
  45. data/meta/lvar.rb +0 -2
  46. data/meta/lvasgn.rb +0 -2
  47. data/meta/masgn.rb +0 -2
  48. data/meta/match_current_line.rb +0 -2
  49. data/meta/next.rb +0 -2
  50. data/meta/nil.rb +0 -2
  51. data/meta/nthref.rb +0 -2
  52. data/meta/op_assgn.rb +0 -2
  53. data/meta/or.rb +0 -2
  54. data/meta/or_asgn.rb +0 -2
  55. data/meta/range.rb +0 -2
  56. data/meta/redo.rb +0 -2
  57. data/meta/regex.rb +0 -2
  58. data/meta/rescue.rb +0 -2
  59. data/meta/restarg.rb +0 -2
  60. data/meta/return.rb +0 -2
  61. data/meta/self.rb +0 -2
  62. data/meta/send.rb +0 -2
  63. data/meta/str.rb +0 -2
  64. data/meta/super.rb +0 -2
  65. data/meta/symbol.rb +0 -2
  66. data/meta/true.rb +0 -2
  67. data/meta/until.rb +0 -2
  68. data/meta/while.rb +0 -2
  69. data/meta/yield.rb +0 -2
  70. data/mutant-rspec.gemspec +1 -1
  71. data/mutant.gemspec +3 -3
  72. data/spec/integration/mutant/rspec_spec.rb +3 -39
  73. data/spec/shared/framework_integration_behavior.rb +35 -0
  74. data/spec/unit/mutant/cli_spec.rb +34 -1
  75. data/spec/unit/mutant/env_spec.rb +0 -1
  76. data/spec/unit/mutant/integration/rspec_spec.rb +193 -0
  77. data/spec/unit/mutant/loader/eval_spec.rb +1 -1
  78. data/spec/unit/mutant/matcher/methods/instance_spec.rb +22 -21
  79. data/spec/unit/mutant/matcher/methods/singleton_spec.rb +21 -19
  80. data/spec/unit/mutant/parallel/worker_spec.rb +0 -2
  81. data/spec/unit/mutant/reporter/cli/tput_spec.rb +48 -0
  82. data/spec/unit/mutant/reporter/cli_spec.rb +29 -9
  83. data/test_app/Gemfile.rspec3.0 +1 -0
  84. data/test_app/Gemfile.rspec3.1 +1 -0
  85. data/test_app/Gemfile.rspec3.2 +1 -0
  86. data/test_app/lib/test_app.rb +1 -1
  87. data/test_app/lib/test_app/literal.rb +0 -2
  88. data/test_app/spec/spec_helper.rb +0 -2
  89. data/test_app/spec/unit/test_app/literal_spec.rb +22 -0
  90. metadata +15 -5
  91. data/test_app/spec/unit/test_app/literal/command_spec.rb +0 -11
  92. data/test_app/spec/unit/test_app/literal/string_spec.rb +0 -11
@@ -19,7 +19,6 @@ RSpec.describe Mutant::Env do
19
19
  )
20
20
  end
21
21
 
22
- let(:isolation) { Mutant::Isolation::None }
23
22
  let(:integration) { double('Integration') }
24
23
  let(:isolation) { double('Isolation') }
25
24
  let(:mutation) { Mutant::Mutation::Evil.new(mutation_subject, Mutant::AST::Nodes::N_NIL) }
@@ -0,0 +1,193 @@
1
+ require 'mutant/integration/rspec'
2
+
3
+ RSpec.describe Mutant::Integration::Rspec do
4
+ let(:object) { described_class.new }
5
+
6
+ let(:options) { double('options') }
7
+ let(:runner) { double('runner') }
8
+
9
+ let(:example_a) do
10
+ double(
11
+ 'Example A',
12
+ metadata: {
13
+ location: 'example-a-location',
14
+ full_description: 'example-a-full-description'
15
+ }
16
+ )
17
+ end
18
+
19
+ let(:example_b) do
20
+ double(
21
+ 'Example B',
22
+ metadata: {
23
+ location: 'example-b-location',
24
+ full_description: 'example-b-full-description',
25
+ mutant: false
26
+ }
27
+ )
28
+ end
29
+
30
+ let(:example_c) do
31
+ double(
32
+ 'Example C',
33
+ metadata: {
34
+ location: 'example-c-location',
35
+ full_description: 'Example::C blah'
36
+ }
37
+ )
38
+ end
39
+
40
+ let(:example_d) do
41
+ double(
42
+ 'Example D',
43
+ metadata: {
44
+ location: 'example-d-location',
45
+ full_description: "Example::D\nblah"
46
+ }
47
+ )
48
+ end
49
+
50
+ let(:example_e) do
51
+ double(
52
+ 'Example E',
53
+ metadata: {
54
+ location: 'example-e-location',
55
+ full_description: 'Example::E',
56
+ mutant_expression: 'Foo'
57
+ }
58
+ )
59
+ end
60
+
61
+ let(:examples) do
62
+ [
63
+ example_a,
64
+ example_b,
65
+ example_c,
66
+ example_d,
67
+ example_e
68
+ ]
69
+ end
70
+
71
+ let(:example_groups) do
72
+ [
73
+ double(
74
+ 'root example group',
75
+ descendants: [
76
+ double('example group', examples: examples)
77
+ ]
78
+ )
79
+ ]
80
+ end
81
+
82
+ let(:filtered_examples) do
83
+ {
84
+ double('Key') => examples.dup
85
+ }
86
+ end
87
+
88
+ let(:world) do
89
+ double(
90
+ 'world',
91
+ example_groups: example_groups,
92
+ filtered_examples: filtered_examples
93
+ )
94
+ end
95
+
96
+ let(:all_tests) do
97
+ [
98
+ Mutant::Test.new(
99
+ id: 'rspec:0:example-a-location/example-a-full-description',
100
+ expression: Mutant::Expression.parse('*')
101
+ ),
102
+ Mutant::Test.new(
103
+ id: 'rspec:1:example-c-location/Example::C blah',
104
+ expression: Mutant::Expression.parse('Example::C')
105
+ ),
106
+ Mutant::Test.new(
107
+ id: "rspec:2:example-d-location/Example::D\nblah",
108
+ expression: Mutant::Expression.parse('*')
109
+ ),
110
+ Mutant::Test.new(
111
+ id: 'rspec:3:example-e-location/Example::E',
112
+ expression: Mutant::Expression.parse('Foo')
113
+ )
114
+ ]
115
+ end
116
+
117
+ before do
118
+ expect(RSpec::Core::ConfigurationOptions).to receive(:new).with(%w[spec --fail-fast]).and_return(options)
119
+ expect(RSpec::Core::Runner).to receive(:new).with(options).and_return(runner)
120
+ expect(RSpec).to receive(:world).with(no_args).and_return(world)
121
+ allow(Time).to receive(:now).and_return(Time.now)
122
+ end
123
+
124
+ describe '#all_tests' do
125
+ subject { object.all_tests }
126
+
127
+ it { should eql(all_tests) }
128
+ end
129
+
130
+ describe '#setup' do
131
+ subject { object.setup }
132
+
133
+ before do
134
+ expect(runner).to receive(:setup) do |error, output|
135
+ expect(error).to be($stderr)
136
+ output.write('foo')
137
+ end
138
+ end
139
+
140
+ it { should be(object) }
141
+ end
142
+
143
+ describe '#call' do
144
+ subject { object.call(tests) }
145
+
146
+ before do
147
+ expect(runner).to receive(:setup) do |_errors, output|
148
+ output.write('the-test-output')
149
+ end
150
+
151
+ object.setup
152
+ end
153
+
154
+ let(:tests) { [all_tests.fetch(0)] }
155
+
156
+ before do
157
+ expect(world).to receive(:ordered_example_groups) do
158
+ filtered_examples.values.flatten
159
+ end
160
+ expect(runner).to receive(:run_specs).with([example_a]).and_return(exit_status)
161
+ end
162
+
163
+ context 'on unsuccessful exit' do
164
+ let(:exit_status) { 1 }
165
+
166
+ it 'should return failed result' do
167
+ expect(subject).to eql(
168
+ Mutant::Result::Test.new(
169
+ tests: tests,
170
+ output: 'the-test-output',
171
+ passed: false,
172
+ runtime: 0.0
173
+ )
174
+ )
175
+ end
176
+ end
177
+
178
+ context 'on successful exit' do
179
+ let(:exit_status) { 0 }
180
+
181
+ it 'should return passed result' do
182
+ expect(subject).to eql(
183
+ Mutant::Result::Test.new(
184
+ tests: tests,
185
+ output: 'the-test-output',
186
+ passed: true,
187
+ runtime: 0.0
188
+ )
189
+ )
190
+ end
191
+ end
192
+ end
193
+ end
@@ -2,7 +2,7 @@ RSpec.describe Mutant::Loader::Eval, '.call' do
2
2
 
3
3
  subject { object.call(node, mutation_subject) }
4
4
 
5
- let(:object) { described_class }
5
+ let(:object) { Class.new(described_class) }
6
6
  let(:path) { __FILE__ }
7
7
  let(:line) { 1 }
8
8
 
@@ -1,39 +1,40 @@
1
1
  RSpec.describe Mutant::Matcher::Methods::Instance, '#each' do
2
- let(:object) { described_class.new(env, Foo) }
2
+ let(:object) { described_class.new(env, class_under_test) }
3
3
  let(:env) { Fixtures::TEST_ENV }
4
4
 
5
5
  subject { object.each { |matcher| yields << matcher } }
6
6
 
7
7
  let(:yields) { [] }
8
8
 
9
- module Bar
10
- def method_d
11
- end
9
+ let(:class_under_test) do
10
+ parent = Module.new do
11
+ def method_d
12
+ end
12
13
 
13
- def method_e
14
+ def method_e
15
+ end
14
16
  end
15
- end
16
17
 
17
- class Foo
18
- include Bar
18
+ Class.new do
19
+ include parent
19
20
 
20
- private :method_d
21
+ private :method_d
21
22
 
22
- public
23
+ public
23
24
 
24
- def method_a
25
- end
25
+ def method_a
26
+ end
26
27
 
27
- protected
28
+ protected
28
29
 
29
- def method_b
30
- end
30
+ def method_b
31
+ end
31
32
 
32
- private
33
+ private
33
34
 
34
- def method_c
35
+ def method_c
36
+ end
35
37
  end
36
-
37
38
  end
38
39
 
39
40
  let(:subject_a) { double('Subject A') }
@@ -45,11 +46,11 @@ RSpec.describe Mutant::Matcher::Methods::Instance, '#each' do
45
46
  before do
46
47
  matcher = Mutant::Matcher::Method::Instance
47
48
  allow(matcher).to receive(:new)
48
- .with(env, Foo, Foo.instance_method(:method_a)).and_return([subject_a])
49
+ .with(env, class_under_test, class_under_test.instance_method(:method_a)).and_return([subject_a])
49
50
  allow(matcher).to receive(:new)
50
- .with(env, Foo, Foo.instance_method(:method_b)).and_return([subject_b])
51
+ .with(env, class_under_test, class_under_test.instance_method(:method_b)).and_return([subject_b])
51
52
  allow(matcher).to receive(:new)
52
- .with(env, Foo, Foo.instance_method(:method_c)).and_return([subject_c])
53
+ .with(env, class_under_test, class_under_test.instance_method(:method_c)).and_return([subject_c])
53
54
  end
54
55
 
55
56
  it 'should yield expected subjects' do
@@ -1,33 +1,35 @@
1
1
  RSpec.describe Mutant::Matcher::Methods::Singleton, '#each' do
2
- let(:object) { described_class.new(env, Foo) }
2
+ let(:object) { described_class.new(env, class_under_test) }
3
3
  let(:env) { Fixtures::TEST_ENV }
4
4
 
5
5
  subject { object.each { |matcher| yields << matcher } }
6
6
 
7
7
  let(:yields) { [] }
8
8
 
9
- module Bar
10
- def method_d
11
- end
9
+ let(:class_under_test) do
10
+ parent = Module.new do
11
+ def method_d
12
+ end
12
13
 
13
- def method_e
14
+ def method_e
15
+ end
14
16
  end
15
- end
16
17
 
17
- class Foo
18
- extend Bar
18
+ Class.new do
19
+ extend parent
19
20
 
20
- def self.method_a
21
- end
21
+ def self.method_a
22
+ end
22
23
 
23
- def self.method_b
24
- end
25
- class << self; protected :method_b; end
24
+ def self.method_b
25
+ end
26
+ class << self; protected :method_b; end
26
27
 
27
- def self.method_c
28
- end
29
- private_class_method :method_c
28
+ def self.method_c
29
+ end
30
+ private_class_method :method_c
30
31
 
32
+ end
31
33
  end
32
34
 
33
35
  let(:subject_a) { double('Subject A') }
@@ -39,11 +41,11 @@ RSpec.describe Mutant::Matcher::Methods::Singleton, '#each' do
39
41
  before do
40
42
  matcher = Mutant::Matcher::Method::Singleton
41
43
  allow(matcher).to receive(:new)
42
- .with(env, Foo, Foo.method(:method_a)).and_return([subject_a])
44
+ .with(env, class_under_test, class_under_test.method(:method_a)).and_return([subject_a])
43
45
  allow(matcher).to receive(:new)
44
- .with(env, Foo, Foo.method(:method_b)).and_return([subject_b])
46
+ .with(env, class_under_test, class_under_test.method(:method_b)).and_return([subject_b])
45
47
  allow(matcher).to receive(:new)
46
- .with(env, Foo, Foo.method(:method_c)).and_return([subject_c])
48
+ .with(env, class_under_test, class_under_test.method(:method_c)).and_return([subject_c])
47
49
  end
48
50
 
49
51
  it 'should yield expected subjects' do
@@ -29,8 +29,6 @@ RSpec.describe Mutant::Parallel::Worker do
29
29
 
30
30
  context 'when receving :job command' do
31
31
 
32
- let(:test_result) { double('Test Result') }
33
-
34
32
  before do
35
33
  expect(processor).to receive(:call).with(payload).and_return(result_payload)
36
34
 
@@ -0,0 +1,48 @@
1
+ RSpec.describe Mutant::Reporter::CLI::Tput do
2
+ describe '.detect' do
3
+ subject { described_class.detect }
4
+
5
+ def expect_command(command, stdout, success)
6
+ allow(Open3).to receive(:capture3).with(command).ordered.and_return(
7
+ [
8
+ stdout,
9
+ double('Stderr'),
10
+ double('Exitstatus', success?: success)
11
+ ]
12
+ )
13
+ end
14
+
15
+ let(:tput_reset?) { true }
16
+ let(:tput_sc?) { true }
17
+ let(:tput_rc?) { true }
18
+ let(:tput_ed?) { true }
19
+
20
+ before do
21
+ expect_command('tput reset', '[reset]', tput_reset?)
22
+ expect_command('tput sc', '[sc]', tput_sc?)
23
+ expect_command('tput rc', '[rc]', tput_rc?)
24
+ expect_command('tput ed', '[ed]', tput_ed?)
25
+ end
26
+
27
+ context 'when all tput commands are supported' do
28
+ its(:prepare) { should eql('[reset][sc]') }
29
+ its(:restore) { should eql('[rc][ed]') }
30
+ end
31
+
32
+ context 'when tput reset fails' do
33
+ let(:tput_reset?) { false }
34
+
35
+ it { should be(nil) }
36
+ end
37
+
38
+ context 'when ed fails' do
39
+ let(:tput_ed?) { false }
40
+ let(:tput_cd?) { true }
41
+ before do
42
+ expect_command('tput cd', '[cd]', tput_cd?)
43
+ end
44
+ its(:prepare) { should eql('[reset][sc]') }
45
+ its(:restore) { should eql('[rc][cd]') }
46
+ end
47
+ end
48
+ end
@@ -2,12 +2,20 @@ RSpec.describe Mutant::Reporter::CLI do
2
2
  setup_shared_context
3
3
 
4
4
  let(:object) { described_class.new(output, format) }
5
- let(:output) { StringIO.new }
5
+ let(:output) { StringIO.new }
6
+
7
+ let(:tput) do
8
+ double(
9
+ 'tput',
10
+ restore: '[tput-restore]',
11
+ prepare: '[tput-prepare]'
12
+ )
13
+ end
6
14
 
7
15
  let(:framed_format) do
8
16
  described_class::Format::Framed.new(
9
17
  tty: false,
10
- tput: described_class::Tput::UNAVAILABLE
18
+ tput: tput
11
19
  )
12
20
  end
13
21
 
@@ -43,7 +51,7 @@ RSpec.describe Mutant::Reporter::CLI do
43
51
  let(:framed_format) do
44
52
  described_class::Format::Framed.new(
45
53
  tty: true,
46
- tput: described_class::Tput::INSTANCE
54
+ tput: tput
47
55
  )
48
56
  end
49
57
 
@@ -56,7 +64,19 @@ RSpec.describe Mutant::Reporter::CLI do
56
64
  let(:ci?) { false }
57
65
 
58
66
  context 'when not on CI and on a tty' do
59
- it { should eql(described_class.new(output, framed_format)) }
67
+ before do
68
+ expect(described_class::Tput).to receive(:detect).and_return(tput)
69
+ end
70
+
71
+ context 'and tput is available' do
72
+ it { should eql(described_class.new(output, framed_format)) }
73
+ end
74
+
75
+ context 'and tput is not available' do
76
+ let(:tput) { nil }
77
+
78
+ it { should eql(described_class.new(output, progressive_format)) }
79
+ end
60
80
  end
61
81
 
62
82
  context 'when on CI' do
@@ -109,7 +129,7 @@ RSpec.describe Mutant::Reporter::CLI do
109
129
  end
110
130
 
111
131
  context 'on framed format' do
112
- it_reports ''
132
+ it_reports '[tput-prepare]'
113
133
  end
114
134
  end
115
135
 
@@ -144,7 +164,7 @@ RSpec.describe Mutant::Reporter::CLI do
144
164
  update(:env_result) { { subject_results: [] } }
145
165
 
146
166
  it_reports <<-REPORT
147
- Mutant configuration:
167
+ [tput-restore]Mutant configuration:
148
168
  Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
149
169
  Integration: null
150
170
  Expect Coverage: 100.00%
@@ -169,7 +189,7 @@ RSpec.describe Mutant::Reporter::CLI do
169
189
  update(:status) { { active_jobs: [].to_set } }
170
190
 
171
191
  it_reports(<<-REPORT)
172
- Mutant configuration:
192
+ [tput-restore]Mutant configuration:
173
193
  Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
174
194
  Integration: null
175
195
  Expect Coverage: 100.00%
@@ -196,7 +216,7 @@ RSpec.describe Mutant::Reporter::CLI do
196
216
  update(:mutation_a_test_result) { { passed: true } }
197
217
 
198
218
  it_reports(<<-REPORT)
199
- Mutant configuration:
219
+ [tput-restore]Mutant configuration:
200
220
  Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
201
221
  Integration: null
202
222
  Expect Coverage: 100.00%
@@ -224,7 +244,7 @@ RSpec.describe Mutant::Reporter::CLI do
224
244
 
225
245
  context 'on success' do
226
246
  it_reports(<<-REPORT)
227
- Mutant configuration:
247
+ [tput-restore]Mutant configuration:
228
248
  Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
229
249
  Integration: null
230
250
  Expect Coverage: 100.00%