minitest-bender 0.0.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -1
- data/Gemfile +1 -1
- data/README.md +37 -6
- data/lib/minitest-bender/colorizer.rb +61 -0
- data/lib/minitest-bender/configuration.rb +174 -0
- data/lib/minitest-bender/printers/plain.rb +29 -0
- data/lib/minitest-bender/printers/with_progress_bar.rb +115 -0
- data/lib/minitest-bender/recorders/grouped_icons.rb +36 -0
- data/lib/minitest-bender/recorders/icons.rb +26 -0
- data/lib/minitest-bender/recorders/none.rb +17 -0
- data/lib/minitest-bender/recorders/progress.rb +25 -0
- data/lib/minitest-bender/recorders/progress_groups.rb +48 -0
- data/lib/minitest-bender/recorders/progress_groups_and_issues.rb +55 -0
- data/lib/minitest-bender/recorders/progress_issues.rb +32 -0
- data/lib/minitest-bender/recorders/progress_verbose.rb +34 -0
- data/lib/minitest-bender/result_context.rb +39 -0
- data/lib/minitest-bender/result_factory.rb +5 -0
- data/lib/minitest-bender/results/base.rb +94 -38
- data/lib/minitest-bender/results/expectation.rb +10 -8
- data/lib/minitest-bender/results/test.rb +21 -8
- data/lib/minitest-bender/sections/activity.rb +95 -0
- data/lib/minitest-bender/sections/issues.rb +22 -0
- data/lib/minitest-bender/sections/sorted_overview.rb +115 -0
- data/lib/minitest-bender/sections/suite_status.rb +72 -0
- data/lib/minitest-bender/sections/time_ranking.rb +49 -0
- data/lib/minitest-bender/states/base.rb +76 -19
- data/lib/minitest-bender/states/failing.rb +11 -8
- data/lib/minitest-bender/states/passing.rb +19 -8
- data/lib/minitest-bender/states/raising.rb +42 -20
- data/lib/minitest-bender/states/skipped.rb +12 -9
- data/lib/minitest-bender/utils.rb +26 -0
- data/lib/minitest-bender/version.rb +1 -1
- data/lib/minitest/bender.rb +166 -77
- data/lib/minitest/bender_plugin.rb +49 -3
- data/lib/minitest_bender.rb +23 -5
- data/minitest-bender.gemspec +6 -6
- metadata +39 -22
@@ -0,0 +1,36 @@
|
|
1
|
+
module MinitestBender
|
2
|
+
module Recorders
|
3
|
+
class GroupedIcons
|
4
|
+
def initialize(io)
|
5
|
+
@printer = Printers::Plain.new(io)
|
6
|
+
end
|
7
|
+
|
8
|
+
def print_context(result_context)
|
9
|
+
printer.print_line
|
10
|
+
|
11
|
+
context_path = result_context.path
|
12
|
+
context_separator = result_context.separator
|
13
|
+
prefix = result_context.prefix
|
14
|
+
|
15
|
+
path = context_path[0...-1].join(context_separator)
|
16
|
+
path << context_separator unless path.empty?
|
17
|
+
klass = context_path.last
|
18
|
+
|
19
|
+
printer.print("#{prefix}#{path}#{Colorizer.colorize(klass, :normal, :bold)} ")
|
20
|
+
end
|
21
|
+
|
22
|
+
def print_result(result)
|
23
|
+
printer.print(result.to_icon)
|
24
|
+
printer.advance
|
25
|
+
end
|
26
|
+
|
27
|
+
def print_context_with_results(_result_context, _results)
|
28
|
+
# do_nothing
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :printer
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module MinitestBender
|
2
|
+
module Recorders
|
3
|
+
class Icons
|
4
|
+
def initialize(io)
|
5
|
+
@printer = Printers::Plain.new(io)
|
6
|
+
end
|
7
|
+
|
8
|
+
def print_context(_result_context)
|
9
|
+
# do nothing
|
10
|
+
end
|
11
|
+
|
12
|
+
def print_result(result)
|
13
|
+
printer.print(result.to_icon)
|
14
|
+
printer.advance
|
15
|
+
end
|
16
|
+
|
17
|
+
def print_context_with_results(_result_context, _results)
|
18
|
+
# do_nothing
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :printer
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module MinitestBender
|
2
|
+
module Recorders
|
3
|
+
class None
|
4
|
+
def print_context(_result_context)
|
5
|
+
# do nothing
|
6
|
+
end
|
7
|
+
|
8
|
+
def print_result(_result)
|
9
|
+
# do nothing
|
10
|
+
end
|
11
|
+
|
12
|
+
def print_context_with_results(_result_context, _results)
|
13
|
+
# do_nothing
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module MinitestBender
|
2
|
+
module Recorders
|
3
|
+
class Progress
|
4
|
+
def initialize(io, total_tests_count)
|
5
|
+
@printer = Printers::WithProgressBar.new(io, total_tests_count)
|
6
|
+
end
|
7
|
+
|
8
|
+
def print_context(_result_context)
|
9
|
+
# do nothing
|
10
|
+
end
|
11
|
+
|
12
|
+
def print_result(result)
|
13
|
+
printer.advance
|
14
|
+
end
|
15
|
+
|
16
|
+
def print_context_with_results(_result_context, _results)
|
17
|
+
# do_nothing
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :printer
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module MinitestBender
|
2
|
+
module Recorders
|
3
|
+
class ProgressGroups
|
4
|
+
def initialize(io, total_tests_count)
|
5
|
+
@printer = Printers::WithProgressBar.new(io, total_tests_count)
|
6
|
+
@total_tests_count = total_tests_count
|
7
|
+
end
|
8
|
+
|
9
|
+
def print_context(_result_context)
|
10
|
+
# do nothing
|
11
|
+
end
|
12
|
+
|
13
|
+
def print_result(result)
|
14
|
+
printer.advance
|
15
|
+
end
|
16
|
+
|
17
|
+
def print_context_with_results(result_context, results)
|
18
|
+
context_path = result_context.path
|
19
|
+
context_separator = result_context.separator
|
20
|
+
prefix = result_context.prefix
|
21
|
+
|
22
|
+
path = context_path[0...-1].join(context_separator)
|
23
|
+
path << context_separator unless path.empty?
|
24
|
+
klass = context_path.last
|
25
|
+
|
26
|
+
printer.print_line("#{prefix}#{counters(result_context)} #{path}#{Colorizer.colorize(klass, :normal, :bold)}")
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :printer, :total_tests_count
|
32
|
+
|
33
|
+
def counters(result_context)
|
34
|
+
states.map do |state|
|
35
|
+
state.colored_icon_with_context_count(result_context, counters_padding_right)
|
36
|
+
end.join(' ')
|
37
|
+
end
|
38
|
+
|
39
|
+
def states
|
40
|
+
@states ||= MinitestBender.states.values
|
41
|
+
end
|
42
|
+
|
43
|
+
def counters_padding_right
|
44
|
+
@counters_padding_right ||= total_tests_count.to_s.size + 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module MinitestBender
|
2
|
+
module Recorders
|
3
|
+
class ProgressGroupsAndIssues
|
4
|
+
def initialize(io, total_tests_count)
|
5
|
+
@printer = Printers::WithProgressBar.new(io, total_tests_count)
|
6
|
+
@total_tests_count = total_tests_count
|
7
|
+
end
|
8
|
+
|
9
|
+
def print_context(_result_context)
|
10
|
+
# do nothing
|
11
|
+
end
|
12
|
+
|
13
|
+
def print_result(result)
|
14
|
+
printer.print_line(result_line(result)) unless result.passed?
|
15
|
+
lines = result.state.detail_lines_without_header(result)
|
16
|
+
printer.print_lines(lines)
|
17
|
+
printer.advance
|
18
|
+
end
|
19
|
+
|
20
|
+
def print_context_with_results(result_context, results)
|
21
|
+
context_path = result_context.path
|
22
|
+
context_separator = result_context.separator
|
23
|
+
prefix = result_context.prefix
|
24
|
+
|
25
|
+
path = context_path[0...-1].join(context_separator)
|
26
|
+
path << context_separator unless path.empty?
|
27
|
+
klass = context_path.last
|
28
|
+
|
29
|
+
printer.print_line("#{prefix}#{counters(result_context)} #{path}#{Colorizer.colorize(klass, :normal, :bold)}")
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :printer, :total_tests_count
|
35
|
+
|
36
|
+
def result_line(result)
|
37
|
+
" #{result.formatted_label_and_time}#{result.formatted_number} #{result.formatted_name_with_context}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def counters(result_context)
|
41
|
+
states.map do |state|
|
42
|
+
state.colored_icon_with_context_count(result_context, counters_padding_right)
|
43
|
+
end.join(' ')
|
44
|
+
end
|
45
|
+
|
46
|
+
def states
|
47
|
+
@states ||= MinitestBender.states.values
|
48
|
+
end
|
49
|
+
|
50
|
+
def counters_padding_right
|
51
|
+
@counters_padding_right ||= total_tests_count.to_s.size + 1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module MinitestBender
|
2
|
+
module Recorders
|
3
|
+
class ProgressIssues
|
4
|
+
def initialize(io, total_tests_count)
|
5
|
+
@printer = Printers::WithProgressBar.new(io, total_tests_count)
|
6
|
+
end
|
7
|
+
|
8
|
+
def print_context(_result_context)
|
9
|
+
# do nothing
|
10
|
+
end
|
11
|
+
|
12
|
+
def print_result(result)
|
13
|
+
printer.print_line(result_line(result)) unless result.passed?
|
14
|
+
lines = result.state.detail_lines_without_header(result)
|
15
|
+
printer.print_lines(lines)
|
16
|
+
printer.advance
|
17
|
+
end
|
18
|
+
|
19
|
+
def print_context_with_results(_result_context, _results)
|
20
|
+
# do_nothing
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :printer
|
26
|
+
|
27
|
+
def result_line(result)
|
28
|
+
" #{result.formatted_label_and_time}#{result.formatted_number} #{result.formatted_name_with_context}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module MinitestBender
|
2
|
+
module Recorders
|
3
|
+
class ProgressVerbose
|
4
|
+
def initialize(io, total_tests_count)
|
5
|
+
@printer = Printers::WithProgressBar.new(io, total_tests_count)
|
6
|
+
end
|
7
|
+
|
8
|
+
def print_context(result_context)
|
9
|
+
printer.print_line
|
10
|
+
printer.print_line(Colorizer.colorize(result_context.with_prefix, :normal, :bold))
|
11
|
+
end
|
12
|
+
|
13
|
+
def print_result(result)
|
14
|
+
printer.print_line(result_line(result))
|
15
|
+
lines = result.state.detail_lines_without_header(result)
|
16
|
+
padded_lines = lines.map { |line| " #{line}" }
|
17
|
+
printer.print_lines(padded_lines)
|
18
|
+
printer.advance
|
19
|
+
end
|
20
|
+
|
21
|
+
def print_context_with_results(_result_context, _results)
|
22
|
+
# do_nothing
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :printer
|
28
|
+
|
29
|
+
def result_line(result)
|
30
|
+
" #{result.formatted_label_and_time}#{result.formatted_number} #{result.name}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module MinitestBender
|
5
|
+
class ResultContext < String
|
6
|
+
PREFIX = '• '
|
7
|
+
SEPARATOR = ' ▸ '
|
8
|
+
CLASS_SEPARATOR = '::'
|
9
|
+
|
10
|
+
def initialize(class_name)
|
11
|
+
@class_name = class_name
|
12
|
+
super(path.join(separator))
|
13
|
+
end
|
14
|
+
|
15
|
+
def path
|
16
|
+
class_name.split(class_separator)
|
17
|
+
end
|
18
|
+
|
19
|
+
def with_prefix
|
20
|
+
prefix + self
|
21
|
+
end
|
22
|
+
|
23
|
+
def separator
|
24
|
+
SEPARATOR
|
25
|
+
end
|
26
|
+
|
27
|
+
def prefix
|
28
|
+
PREFIX
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :class_name
|
34
|
+
|
35
|
+
def class_separator
|
36
|
+
CLASS_SEPARATOR
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -26,6 +26,11 @@ module MinitestBender
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def parsed_name(minitest_result)
|
29
|
+
if minitest_result.name.is_a?(Class)
|
30
|
+
# something went wrong inside minitest (infinite loop?)
|
31
|
+
raise minitest_result.failures[0].error
|
32
|
+
end
|
33
|
+
|
29
34
|
minitest_result.name.match(RESULT_NAME_REGEXP)
|
30
35
|
end
|
31
36
|
end
|
@@ -1,77 +1,133 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'forwardable'
|
5
|
+
|
1
6
|
module MinitestBender
|
2
7
|
module Results
|
3
8
|
class Base
|
4
9
|
extend Forwardable
|
5
10
|
def_delegators :@minitest_result, :passed?, :skipped?, :assertions, :failures, :time
|
11
|
+
attr_reader :state, :execution_order
|
12
|
+
|
13
|
+
NAME_PREFIX = '♦'
|
6
14
|
|
7
15
|
def initialize(minitest_result)
|
8
16
|
@minitest_result = minitest_result
|
9
17
|
@state = MinitestBender.states.fetch(minitest_result.result_code)
|
18
|
+
@execution_order = state.add_result(self).size
|
10
19
|
end
|
11
20
|
|
12
21
|
def context
|
13
|
-
@context ||=
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end.gsub('::', ' > ')
|
22
|
+
@context ||= ResultContext.new(adjusted_class_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_icon
|
26
|
+
state.colored_icon
|
19
27
|
end
|
20
28
|
|
21
|
-
def
|
22
|
-
|
29
|
+
def name_sort_key
|
30
|
+
name
|
23
31
|
end
|
24
32
|
|
25
|
-
def
|
26
|
-
"
|
33
|
+
def formatted_name_with_context
|
34
|
+
"#{Colorizer.colorize(context, :normal)} #{name_prefix} #{Colorizer.colorize(name, :normal, :bold)}"
|
27
35
|
end
|
28
36
|
|
29
37
|
def rerun_line(padding)
|
30
38
|
unformatted = "Rerun: #{rerun_command}"
|
31
|
-
"#{padding}#{
|
39
|
+
"#{padding}#{Colorizer.colorize(unformatted, :tests)}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def formatted_label
|
43
|
+
state.formatted_label
|
44
|
+
end
|
45
|
+
|
46
|
+
def time_with_unit_and_padding_right
|
47
|
+
time_in_s = time
|
48
|
+
case time_in_s
|
49
|
+
when 0...1
|
50
|
+
sprintf('%.0fms ', time_in_s * 1000)
|
51
|
+
when 1...10
|
52
|
+
sprintf('%.2fs ', time_in_s)
|
53
|
+
when 10...100
|
54
|
+
sprintf('%.1fs ', time_in_s)
|
55
|
+
when 100...10000
|
56
|
+
sprintf('%.0fs ', time_in_s)
|
57
|
+
else
|
58
|
+
sprintf('%.0fs', time_in_s)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def formatted_time
|
63
|
+
Colorizer.colorize(time_with_unit_and_padding_right.rjust(6), :time)
|
64
|
+
end
|
65
|
+
|
66
|
+
def formatted_label_and_time
|
67
|
+
"#{formatted_label} #{formatted_time}"
|
32
68
|
end
|
33
69
|
|
34
|
-
def
|
35
|
-
state.
|
70
|
+
def formatted_message
|
71
|
+
state.formatted_message(self)
|
72
|
+
end
|
73
|
+
|
74
|
+
def file_path
|
75
|
+
@file_path ||= source_location[0]
|
76
|
+
end
|
77
|
+
|
78
|
+
def source_line_number
|
79
|
+
@source_line_number ||= source_location[1]
|
36
80
|
end
|
37
81
|
|
38
|
-
|
39
|
-
|
82
|
+
# credit where credit is due: minitest-line
|
83
|
+
def source_location
|
84
|
+
if minitest_at_least_5_11?
|
85
|
+
minitest_result.source_location
|
86
|
+
else
|
87
|
+
minitest_result.method(minitest_result.name).source_location rescue ['unknown', -1]
|
88
|
+
end
|
40
89
|
end
|
41
90
|
|
42
91
|
private
|
43
92
|
|
44
|
-
attr_reader :minitest_result
|
93
|
+
attr_reader :minitest_result
|
45
94
|
|
46
|
-
def
|
47
|
-
|
95
|
+
def adjusted_class_name
|
96
|
+
class_name
|
48
97
|
end
|
49
98
|
|
50
|
-
def
|
51
|
-
|
99
|
+
def class_name
|
100
|
+
if minitest_at_least_5_11?
|
101
|
+
minitest_result.klass
|
102
|
+
else
|
103
|
+
minitest_result.class.name
|
104
|
+
end
|
52
105
|
end
|
53
106
|
|
54
|
-
def
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
when 100...10000
|
65
|
-
sprintf('%.0fs ', time_in_s)
|
66
|
-
else
|
67
|
-
sprintf('%.0fs', time_in_s)
|
68
|
-
end
|
69
|
-
Colorin.grey_700(time_with_unit.rjust(6))
|
107
|
+
def minitest_at_least_5_11?
|
108
|
+
@minitest_at_least_5_11 ||= Gem.loaded_specs['minitest'].version >= Gem::Version.new('5.11')
|
109
|
+
end
|
110
|
+
|
111
|
+
def class_separator
|
112
|
+
CLASS_SEPARATOR
|
113
|
+
end
|
114
|
+
|
115
|
+
def name_prefix
|
116
|
+
NAME_PREFIX
|
70
117
|
end
|
71
118
|
|
72
119
|
def rerun_command
|
73
|
-
relative_location = state.test_location(self)
|
74
|
-
|
120
|
+
return unless (relative_location = state.test_location(self))
|
121
|
+
|
122
|
+
relative_location = relative_location.split(':').first
|
123
|
+
|
124
|
+
stem = Minitest::Bender.configuration.rerun_command_stem
|
125
|
+
|
126
|
+
if stem.include?('rake')
|
127
|
+
"#{stem} TEST=#{relative_location} TESTOPTS=\"--name=#{name_for_rerun_command}\""
|
128
|
+
else
|
129
|
+
"#{stem} #{relative_location} --name=#{name_for_rerun_command}"
|
130
|
+
end
|
75
131
|
end
|
76
132
|
end
|
77
133
|
end
|