mutant 0.7.9 → 0.8.0

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 (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