mutant 0.7.9 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +11 -1
  3. data/README.md +5 -12
  4. data/bin/mutant +17 -1
  5. data/config/flay.yml +1 -1
  6. data/config/flog.yml +1 -1
  7. data/config/reek.yml +4 -4
  8. data/config/rubocop.yml +21 -3
  9. data/lib/mutant.rb +15 -61
  10. data/lib/mutant/cli.rb +1 -7
  11. data/lib/mutant/color.rb +2 -2
  12. data/lib/mutant/config.rb +1 -1
  13. data/lib/mutant/expression/method.rb +1 -1
  14. data/lib/mutant/expression/methods.rb +1 -1
  15. data/lib/mutant/expression/namespace.rb +1 -1
  16. data/lib/mutant/mutator/node/send.rb +18 -18
  17. data/lib/mutant/reporter/cli.rb +1 -6
  18. data/lib/mutant/reporter/cli/format.rb +2 -2
  19. data/lib/mutant/reporter/cli/printer.rb +5 -500
  20. data/lib/mutant/reporter/cli/printer/config.rb +32 -0
  21. data/lib/mutant/reporter/cli/printer/env_progress.rb +66 -0
  22. data/lib/mutant/reporter/cli/printer/env_result.rb +23 -0
  23. data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +37 -0
  24. data/lib/mutant/reporter/cli/printer/mutation_result.rb +151 -0
  25. data/lib/mutant/reporter/cli/printer/status.rb +60 -0
  26. data/lib/mutant/reporter/cli/printer/status_progressive.rb +52 -0
  27. data/lib/mutant/reporter/cli/printer/subject_progress.rb +90 -0
  28. data/lib/mutant/reporter/cli/printer/subject_result.rb +28 -0
  29. data/lib/mutant/reporter/cli/printer/test_result.rb +33 -0
  30. data/lib/mutant/require_highjack.rb +11 -50
  31. data/lib/mutant/version.rb +1 -1
  32. data/lib/mutant/zombifier.rb +79 -37
  33. data/meta/send.rb +1 -1
  34. data/mutant-rspec.gemspec +1 -1
  35. data/mutant.gemspec +3 -3
  36. data/spec/integration/mutant/corpus_spec.rb +2 -2
  37. data/spec/integration/mutant/rspec_spec.rb +5 -15
  38. data/spec/integrations.yml +3 -3
  39. data/spec/spec_helper.rb +1 -0
  40. data/spec/support/corpus.rb +233 -220
  41. data/spec/support/file_system.rb +60 -0
  42. data/spec/support/rb_bug.rb +1 -1
  43. data/spec/support/ruby_vm.rb +82 -0
  44. data/spec/support/shared_context.rb +19 -10
  45. data/spec/unit/mutant/ast_spec.rb +2 -2
  46. data/spec/unit/mutant/cache_spec.rb +22 -0
  47. data/spec/unit/mutant/cli_spec.rb +1 -30
  48. data/spec/unit/mutant/context_spec.rb +1 -0
  49. data/spec/unit/mutant/expression/method_spec.rb +6 -4
  50. data/spec/unit/mutant/parallel/master_spec.rb +1 -1
  51. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +33 -0
  52. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +76 -0
  53. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +35 -0
  54. data/spec/unit/mutant/reporter/cli/printer/mutation_progress_result_spec.rb +23 -0
  55. data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +110 -0
  56. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +51 -0
  57. data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +145 -0
  58. data/spec/unit/mutant/reporter/cli/printer/subject_progress_spec.rb +37 -0
  59. data/spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb +37 -0
  60. data/spec/unit/mutant/reporter/cli/printer/test_result_spec.rb +14 -0
  61. data/spec/unit/mutant/reporter/cli/printer_spec.rb +140 -0
  62. data/spec/unit/mutant/reporter/cli_spec.rb +69 -313
  63. data/spec/unit/mutant/reporter/trace_spec.rb +12 -0
  64. data/spec/unit/mutant/require_highjack_spec.rb +25 -28
  65. data/spec/unit/mutant/warning_filter_spec.rb +7 -0
  66. data/spec/unit/mutant/zombifier_spec.rb +120 -0
  67. data/spec/unit/mutant_spec.rb +0 -43
  68. data/test_app/Gemfile.rspec3.3 +6 -0
  69. metadata +46 -17
  70. data/.travis.yml +0 -20
  71. data/lib/mutant/zombifier/file.rb +0 -100
  72. data/spec/integration/mutant/zombie_spec.rb +0 -6
@@ -0,0 +1,35 @@
1
+ RSpec.describe Mutant::Reporter::CLI::Printer::EnvResult do
2
+ setup_shared_context
3
+
4
+ update(:mutation_a_test_result) { { passed: true } }
5
+
6
+ let(:reportable) { env_result }
7
+
8
+ describe '.call' do
9
+ it_reports <<-'STR'
10
+ subject-a
11
+ - test-a
12
+ evil:subject-a:d27d2
13
+ @@ -1,2 +1,2 @@
14
+ -true
15
+ +false
16
+ -----------------------
17
+ Mutant configuration:
18
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
19
+ Integration: null
20
+ Expect Coverage: 100.00%
21
+ Jobs: 1
22
+ Includes: []
23
+ Requires: []
24
+ Subjects: 1
25
+ Mutations: 2
26
+ Kills: 1
27
+ Alive: 1
28
+ Runtime: 4.00s
29
+ Killtime: 2.00s
30
+ Overhead: 100.00%
31
+ Coverage: 50.00%
32
+ Expected: 100.00%
33
+ STR
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ RSpec.describe Mutant::Reporter::CLI::Printer::MutationProgressResult do
2
+ setup_shared_context
3
+
4
+ let(:reportable) { mutation_a_result }
5
+
6
+ before do
7
+ allow(output).to receive(:tty?).and_return(true)
8
+ end
9
+
10
+ describe '.run' do
11
+ context 'on killed mutant' do
12
+ update(:mutation_a_test_result) { { passed: true } }
13
+
14
+ it_reports Mutant::Color::RED.format('F')
15
+ end
16
+
17
+ context 'on alive mutant' do
18
+ update(:mutation_a_test_result) { { passed: false } }
19
+
20
+ it_reports Mutant::Color::GREEN.format('.')
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,110 @@
1
+ RSpec.describe Mutant::Reporter::CLI::Printer::MutationResult do
2
+ setup_shared_context
3
+
4
+ let(:reportable) { mutation_a_result }
5
+
6
+ describe '.call' do
7
+ context 'failed kill' do
8
+ update(:mutation_a_test_result) { { passed: true } }
9
+
10
+ context 'on evil mutation' do
11
+ context 'with a diff' do
12
+ context 'on a tty' do
13
+ before do
14
+ allow(output).to receive(:tty?).and_return(true)
15
+ end
16
+
17
+ it_reports(
18
+ [
19
+ [Mutant::Color::NONE, "evil:subject-a:d27d2\n"],
20
+ [Mutant::Color::NONE, "@@ -1,2 +1,2 @@\n"],
21
+ [Mutant::Color::RED, "-true\n"],
22
+ [Mutant::Color::GREEN, "+false\n"],
23
+ [Mutant::Color::NONE, "-----------------------\n"]
24
+ ].map { |color, text| color.format(text) }.join
25
+ )
26
+ end
27
+
28
+ context 'on non tty' do
29
+ it_reports(<<-'STR')
30
+ evil:subject-a:d27d2
31
+ @@ -1,2 +1,2 @@
32
+ -true
33
+ +false
34
+ -----------------------
35
+ STR
36
+ end
37
+ end
38
+
39
+ context 'without a diff' do
40
+ # This is intentionally invalid AST mutant might produce
41
+ let(:subject_a_node) { s(:lvar, :super) }
42
+
43
+ # Unparses exactly the same way as above node
44
+ let(:mutation_a_node) { s(:zsuper) }
45
+
46
+ it_reports(<<-REPORT)
47
+ evil:subject-a:a5bc7
48
+ --- Internal failure ---
49
+ BUG: Mutation NOT resulted in exactly one diff hunk. Please report a reproduction!
50
+ Original unparsed source:
51
+ super
52
+ Original AST:
53
+ (lvar :super)
54
+ Mutated unparsed source:
55
+ super
56
+ Mutated AST:
57
+ (zsuper)
58
+ -----------------------
59
+ REPORT
60
+ end
61
+ end
62
+
63
+ context 'on neutral mutation' do
64
+ update(:mutation_a_test_result) { { passed: false } }
65
+
66
+ let(:mutation_a) do
67
+ Mutant::Mutation::Neutral.new(subject_a, s(:true))
68
+ end
69
+
70
+ it_reports(<<-REPORT)
71
+ neutral:subject-a:d5318
72
+ --- Neutral failure ---
73
+ Original code was inserted unmutated. And the test did NOT PASS.
74
+ Your tests do not pass initially or you found a bug in mutant / unparser.
75
+ Subject AST:
76
+ (true)
77
+ Unparsed Source:
78
+ true
79
+ Test Result:
80
+ - 1 @ runtime: 1.0
81
+ - test-a
82
+ Test Output:
83
+ mutation a test result output
84
+ -----------------------
85
+ REPORT
86
+ end
87
+
88
+ context 'on noop mutation' do
89
+ update(:mutation_a_test_result) { { passed: false } }
90
+
91
+ let(:mutation_a) do
92
+ Mutant::Mutation::Noop.new(subject_a, s(:true))
93
+ end
94
+
95
+ it_reports(<<-REPORT)
96
+ noop:subject-a:d5318
97
+ ---- Noop failure -----
98
+ No code was inserted. And the test did NOT PASS.
99
+ This is typically a problem of your specs not passing unmutated.
100
+ Test Result:
101
+ - 1 @ runtime: 1.0
102
+ - test-a
103
+ Test Output:
104
+ mutation a test result output
105
+ -----------------------
106
+ REPORT
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,51 @@
1
+ RSpec.describe Mutant::Reporter::CLI::Printer::StatusProgressive do
2
+ setup_shared_context
3
+
4
+ let(:reportable) { status }
5
+
6
+ describe '.call' do
7
+ context 'with empty scheduler' do
8
+ update(:env_result) { { subject_results: [] } }
9
+
10
+ it_reports <<-REPORT
11
+ (00/02) 0% - killtime: 0.00s runtime: 4.00s overhead: 4.00s
12
+ REPORT
13
+
14
+ context 'on non default coverage expectation' do
15
+ update(:config) { { expected_coverage: 0.1r } }
16
+
17
+ it_reports <<-REPORT
18
+ (00/02) 0% - killtime: 0.00s runtime: 4.00s overhead: 4.00s
19
+ REPORT
20
+ end
21
+ end
22
+
23
+ context 'with scheduler active on one subject' do
24
+ context 'without progress' do
25
+ update(:status) { { active_jobs: [].to_set } }
26
+
27
+ it_reports(<<-REPORT)
28
+ (02/02) 100% - killtime: 2.00s runtime: 4.00s overhead: 2.00s
29
+ REPORT
30
+ end
31
+
32
+ context 'with progress' do
33
+ update(:status) { { active_jobs: [job_b, job_a].to_set } }
34
+
35
+ context 'on failure' do
36
+ update(:mutation_a_test_result) { { passed: true } }
37
+
38
+ it_reports(<<-REPORT)
39
+ (01/02) 50% - killtime: 2.00s runtime: 4.00s overhead: 2.00s
40
+ REPORT
41
+ end
42
+
43
+ context 'on success' do
44
+ it_reports(<<-REPORT)
45
+ (02/02) 100% - killtime: 2.00s runtime: 4.00s overhead: 2.00s
46
+ REPORT
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,145 @@
1
+ RSpec.describe Mutant::Reporter::CLI::Printer::Status do
2
+ setup_shared_context
3
+
4
+ let(:reportable) { status }
5
+
6
+ describe '.call' do
7
+ context 'with empty scheduler' do
8
+ update(:env_result) { { subject_results: [] } }
9
+
10
+ it_reports <<-REPORT
11
+ Mutant configuration:
12
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
13
+ Integration: null
14
+ Expect Coverage: 100.00%
15
+ Jobs: 1
16
+ Includes: []
17
+ Requires: []
18
+ Subjects: 1
19
+ Mutations: 2
20
+ Kills: 0
21
+ Alive: 0
22
+ Runtime: 4.00s
23
+ Killtime: 0.00s
24
+ Overhead: Inf%
25
+ Coverage: 0.00%
26
+ Expected: 100.00%
27
+ Active subjects: 0
28
+ REPORT
29
+
30
+ context 'on non default coverage expectation' do
31
+ update(:config) { { expected_coverage: 0.1r } }
32
+
33
+ it_reports <<-REPORT
34
+ Mutant configuration:
35
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
36
+ Integration: null
37
+ Expect Coverage: 10.00%
38
+ Jobs: 1
39
+ Includes: []
40
+ Requires: []
41
+ Subjects: 1
42
+ Mutations: 2
43
+ Kills: 0
44
+ Alive: 0
45
+ Runtime: 4.00s
46
+ Killtime: 0.00s
47
+ Overhead: Inf%
48
+ Coverage: 0.00%
49
+ Expected: 10.00%
50
+ Active subjects: 0
51
+ REPORT
52
+ end
53
+ end
54
+
55
+ context 'with scheduler active on one subject' do
56
+ context 'without progress' do
57
+ update(:status) { { active_jobs: [].to_set } }
58
+
59
+ it_reports(<<-REPORT)
60
+ Mutant configuration:
61
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
62
+ Integration: null
63
+ Expect Coverage: 100.00%
64
+ Jobs: 1
65
+ Includes: []
66
+ Requires: []
67
+ Subjects: 1
68
+ Mutations: 2
69
+ Kills: 2
70
+ Alive: 0
71
+ Runtime: 4.00s
72
+ Killtime: 2.00s
73
+ Overhead: 100.00%
74
+ Coverage: 100.00%
75
+ Expected: 100.00%
76
+ Active subjects: 0
77
+ REPORT
78
+ end
79
+
80
+ context 'with progress' do
81
+ update(:status) { { active_jobs: [job_b, job_a].to_set } }
82
+
83
+ context 'on failure' do
84
+ update(:mutation_a_test_result) { { passed: true } }
85
+
86
+ it_reports(<<-REPORT)
87
+ Mutant configuration:
88
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
89
+ Integration: null
90
+ Expect Coverage: 100.00%
91
+ Jobs: 1
92
+ Includes: []
93
+ Requires: []
94
+ Subjects: 1
95
+ Mutations: 2
96
+ Kills: 1
97
+ Alive: 1
98
+ Runtime: 4.00s
99
+ Killtime: 2.00s
100
+ Overhead: 100.00%
101
+ Coverage: 50.00%
102
+ Expected: 100.00%
103
+ Active Jobs:
104
+ 0: evil:subject-a:d27d2
105
+ 1: evil:subject-a:d5a9d
106
+ Active subjects: 1
107
+ subject-a mutations: 2
108
+ F.
109
+ (01/02) 50% - killtime: 2.00s runtime: 2.00s overhead: 0.00s
110
+ - test-a
111
+ REPORT
112
+ end
113
+
114
+ context 'on success' do
115
+ it_reports(<<-REPORT)
116
+ Mutant configuration:
117
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
118
+ Integration: null
119
+ Expect Coverage: 100.00%
120
+ Jobs: 1
121
+ Includes: []
122
+ Requires: []
123
+ Subjects: 1
124
+ Mutations: 2
125
+ Kills: 2
126
+ Alive: 0
127
+ Runtime: 4.00s
128
+ Killtime: 2.00s
129
+ Overhead: 100.00%
130
+ Coverage: 100.00%
131
+ Expected: 100.00%
132
+ Active Jobs:
133
+ 0: evil:subject-a:d27d2
134
+ 1: evil:subject-a:d5a9d
135
+ Active subjects: 1
136
+ subject-a mutations: 2
137
+ ..
138
+ (02/02) 100% - killtime: 2.00s runtime: 2.00s overhead: 0.00s
139
+ - test-a
140
+ REPORT
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,37 @@
1
+ RSpec.describe Mutant::Reporter::CLI::Printer::SubjectProgress do
2
+ setup_shared_context
3
+
4
+ let(:reportable) { subject_a_result }
5
+
6
+ describe '.call' do
7
+ context 'on full coverage' do
8
+ it_reports <<-'STR'
9
+ subject-a mutations: 2
10
+ ..
11
+ (02/02) 100% - killtime: 2.00s runtime: 2.00s overhead: 0.00s
12
+ - test-a
13
+ STR
14
+ end
15
+
16
+ context 'on partial coverage' do
17
+ update(:mutation_a_test_result) { { passed: true } }
18
+
19
+ it_reports <<-'STR'
20
+ subject-a mutations: 2
21
+ F.
22
+ (01/02) 50% - killtime: 2.00s runtime: 2.00s overhead: 0.00s
23
+ - test-a
24
+ STR
25
+ end
26
+
27
+ context 'without results' do
28
+ update(:subject_a_result) { { mutation_results: [] } }
29
+
30
+ it_reports <<-'STR'
31
+ subject-a mutations: 2
32
+ (00/02) 0% - killtime: 0.00s runtime: 0.00s overhead: 0.00s
33
+ - test-a
34
+ STR
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,37 @@
1
+ RSpec.describe Mutant::Reporter::CLI::Printer::SubjectResult do
2
+ setup_shared_context
3
+
4
+ let(:reportable) { subject_a_result }
5
+
6
+ describe '.call' do
7
+ context 'on full coverage' do
8
+ it_reports <<-'STR'
9
+ subject-a
10
+ - test-a
11
+ STR
12
+ end
13
+
14
+ context 'on partial coverage' do
15
+ update(:mutation_a_test_result) { { passed: true } }
16
+
17
+ it_reports <<-'STR'
18
+ subject-a
19
+ - test-a
20
+ evil:subject-a:d27d2
21
+ @@ -1,2 +1,2 @@
22
+ -true
23
+ +false
24
+ -----------------------
25
+ STR
26
+ end
27
+
28
+ context 'without results' do
29
+ update(:subject_a_result) { { mutation_results: [] } }
30
+
31
+ it_reports <<-'STR'
32
+ subject-a
33
+ - test-a
34
+ STR
35
+ end
36
+ end
37
+ end