test_bench_legacy 1.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/bench +10 -0
- data/lib/test_bench.rb +37 -0
- data/lib/test_bench/activate.rb +3 -0
- data/lib/test_bench/assert.rb +58 -0
- data/lib/test_bench/assert/failed.rb +25 -0
- data/lib/test_bench/assert/proc.rb +24 -0
- data/lib/test_bench/assert/refute.rb +9 -0
- data/lib/test_bench/cli.rb +4 -0
- data/lib/test_bench/cli/cli.rb +108 -0
- data/lib/test_bench/controls.rb +16 -0
- data/lib/test_bench/controls/binding.rb +17 -0
- data/lib/test_bench/controls/clock/elapsed.rb +41 -0
- data/lib/test_bench/controls/clock/reference.rb +15 -0
- data/lib/test_bench/controls/dir_substitute.rb +58 -0
- data/lib/test_bench/controls/error.rb +63 -0
- data/lib/test_bench/controls/executor/substitute.rb +27 -0
- data/lib/test_bench/controls/expand_path.rb +23 -0
- data/lib/test_bench/controls/fixture.rb +36 -0
- data/lib/test_bench/controls/kernel_substitute.rb +72 -0
- data/lib/test_bench/controls/output.rb +106 -0
- data/lib/test_bench/controls/path.rb +11 -0
- data/lib/test_bench/controls/result.rb +64 -0
- data/lib/test_bench/controls/telemetry.rb +23 -0
- data/lib/test_bench/controls/test_script.rb +23 -0
- data/lib/test_bench/executor.rb +45 -0
- data/lib/test_bench/expand_path.rb +44 -0
- data/lib/test_bench/fixture.rb +17 -0
- data/lib/test_bench/output.rb +169 -0
- data/lib/test_bench/output/assertions.rb +43 -0
- data/lib/test_bench/output/palette.rb +59 -0
- data/lib/test_bench/output/writer.rb +94 -0
- data/lib/test_bench/output/writer/assertions.rb +29 -0
- data/lib/test_bench/output/writer/assertions/line.rb +76 -0
- data/lib/test_bench/registry.rb +32 -0
- data/lib/test_bench/result.rb +71 -0
- data/lib/test_bench/result/assertions.rb +11 -0
- data/lib/test_bench/result/null.rb +12 -0
- data/lib/test_bench/runner.rb +59 -0
- data/lib/test_bench/settings.rb +62 -0
- data/lib/test_bench/settings/defaults.rb +29 -0
- data/lib/test_bench/settings/environment.rb +124 -0
- data/lib/test_bench/settings/registry.rb +17 -0
- data/lib/test_bench/structure.rb +89 -0
- data/lib/test_bench/telemetry.rb +130 -0
- data/lib/test_bench/telemetry/assertions.rb +85 -0
- data/lib/test_bench/telemetry/registry.rb +17 -0
- data/lib/test_bench/telemetry/subscription.rb +23 -0
- data/lib/test_bench/test_bench.rb +33 -0
- metadata +94 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
module TestBench
|
2
|
+
class Executor
|
3
|
+
attr_reader :binding
|
4
|
+
attr_reader :kernel
|
5
|
+
|
6
|
+
def initialize binding, kernel
|
7
|
+
@binding = binding
|
8
|
+
@kernel = kernel
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.build
|
12
|
+
binding = TOPLEVEL_BINDING
|
13
|
+
|
14
|
+
new binding, Kernel
|
15
|
+
end
|
16
|
+
|
17
|
+
def call files
|
18
|
+
files.each do |file|
|
19
|
+
execute file
|
20
|
+
end
|
21
|
+
|
22
|
+
telemetry.passed?
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute file
|
26
|
+
telemetry.file_started file
|
27
|
+
|
28
|
+
begin
|
29
|
+
unbound_context_method = TestBench::Structure.instance_method :context
|
30
|
+
bound_context_method = unbound_context_method.bind binding.receiver
|
31
|
+
|
32
|
+
bound_context_method.call :suppress_exit => true do
|
33
|
+
kernel.load File.expand_path file
|
34
|
+
end
|
35
|
+
|
36
|
+
ensure
|
37
|
+
telemetry.file_finished file
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def telemetry
|
42
|
+
Telemetry::Registry.get binding
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module TestBench
|
2
|
+
class ExpandPath
|
3
|
+
attr_reader :dir
|
4
|
+
attr_reader :exclude_pattern
|
5
|
+
attr_reader :root_directory
|
6
|
+
|
7
|
+
def initialize root_directory, exclude_pattern, dir
|
8
|
+
@dir = dir
|
9
|
+
@exclude_pattern = exclude_pattern
|
10
|
+
@root_directory = root_directory
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.build root_directory, exclude_pattern=nil, dir: nil
|
14
|
+
dir ||= Dir
|
15
|
+
|
16
|
+
exclude_pattern ||= Settings.toplevel.exclude_pattern
|
17
|
+
exclude_pattern = Regexp.new exclude_pattern if exclude_pattern.is_a? String
|
18
|
+
|
19
|
+
root_directory = Pathname root_directory
|
20
|
+
|
21
|
+
new root_directory, exclude_pattern, dir
|
22
|
+
end
|
23
|
+
|
24
|
+
def call pattern
|
25
|
+
full_pattern = root_directory.join pattern
|
26
|
+
|
27
|
+
if dir.exist? full_pattern
|
28
|
+
full_pattern = full_pattern.join '**/*.rb'
|
29
|
+
end
|
30
|
+
|
31
|
+
expand full_pattern.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def expand full_pattern
|
35
|
+
dir[full_pattern].flat_map do |file|
|
36
|
+
if exclude_pattern.match file
|
37
|
+
[]
|
38
|
+
else
|
39
|
+
[file]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module TestBench
|
2
|
+
module Fixture
|
3
|
+
def self.included cls
|
4
|
+
cls.class_exec do
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
delegate %i(assert comment context refute test) => :structure
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_writer :structure
|
12
|
+
|
13
|
+
def structure
|
14
|
+
@structure ||= TOPLEVEL_BINDING.receiver
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module TestBench
|
2
|
+
class Output
|
3
|
+
attr_writer :file_result
|
4
|
+
attr_writer :reverse_backtraces
|
5
|
+
attr_writer :run_result
|
6
|
+
attr_writer :writer
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@file_result = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.build level=nil
|
13
|
+
writer = Writer.build $stdout
|
14
|
+
writer.level = level if level
|
15
|
+
|
16
|
+
instance = new
|
17
|
+
instance.writer = writer
|
18
|
+
instance
|
19
|
+
end
|
20
|
+
|
21
|
+
def asserted
|
22
|
+
file_result.asserted
|
23
|
+
run_result.asserted
|
24
|
+
end
|
25
|
+
|
26
|
+
def commented prose
|
27
|
+
writer.normal prose, :fg => :normal
|
28
|
+
end
|
29
|
+
|
30
|
+
def context_entered prose=nil
|
31
|
+
return if prose.nil?
|
32
|
+
|
33
|
+
writer.normal prose, :fg => :green
|
34
|
+
|
35
|
+
writer.increase_indentation unless writer.level == :quiet
|
36
|
+
end
|
37
|
+
|
38
|
+
def context_exited prose=nil
|
39
|
+
return if prose.nil?
|
40
|
+
|
41
|
+
writer.decrease_indentation unless writer.level == :quiet
|
42
|
+
|
43
|
+
writer.normal ' ' if writer.indentation.zero?
|
44
|
+
end
|
45
|
+
|
46
|
+
def device
|
47
|
+
@device ||= StringIO.new
|
48
|
+
end
|
49
|
+
|
50
|
+
def error_raised error
|
51
|
+
run_result.error_raised error
|
52
|
+
file_result.error_raised error
|
53
|
+
|
54
|
+
detail_summary = "#{error.backtrace[0]}: #{error.message} (#{error.class})"
|
55
|
+
|
56
|
+
lines = [detail_summary]
|
57
|
+
error.backtrace[1..-1].each do |frame|
|
58
|
+
lines << " from #{frame}"
|
59
|
+
end
|
60
|
+
|
61
|
+
lines.reverse! if reverse_backtraces
|
62
|
+
|
63
|
+
lines.each do |line|
|
64
|
+
writer.quiet line, :fg => :red
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def file_finished path
|
69
|
+
run_result.file_finished path
|
70
|
+
file_result.finished
|
71
|
+
|
72
|
+
summary = summarize_result file_result
|
73
|
+
|
74
|
+
self.file_result = nil
|
75
|
+
|
76
|
+
writer.verbose "Finished running #{path}"
|
77
|
+
writer.verbose summary
|
78
|
+
writer.verbose ' '
|
79
|
+
end
|
80
|
+
|
81
|
+
def file_result
|
82
|
+
@file_result or Result::Null
|
83
|
+
end
|
84
|
+
|
85
|
+
def file_started path
|
86
|
+
writer.normal "Running #{path}"
|
87
|
+
|
88
|
+
file_result = Result.build
|
89
|
+
|
90
|
+
self.file_result = file_result
|
91
|
+
|
92
|
+
file_result
|
93
|
+
end
|
94
|
+
|
95
|
+
def reverse_backtraces
|
96
|
+
ivar = :@reverse_backtraces
|
97
|
+
|
98
|
+
if instance_variable_defined? ivar
|
99
|
+
instance_variable_get ivar
|
100
|
+
else
|
101
|
+
instance_variable_set ivar, false
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def run_finished
|
106
|
+
run_result.run_finished
|
107
|
+
|
108
|
+
files_label = if run_result.files.size == 1 then 'file' else 'files' end
|
109
|
+
|
110
|
+
color = if run_result.passed? then :cyan else :red end
|
111
|
+
|
112
|
+
writer.quiet "Finished running #{run_result.files.size} #{files_label}"
|
113
|
+
|
114
|
+
summary = summarize_result run_result
|
115
|
+
|
116
|
+
writer.quiet summary, :fg => color
|
117
|
+
end
|
118
|
+
|
119
|
+
def run_started
|
120
|
+
self.run_result
|
121
|
+
end
|
122
|
+
|
123
|
+
def run_result
|
124
|
+
@run_result ||= Result.build
|
125
|
+
end
|
126
|
+
|
127
|
+
def summarize_result result
|
128
|
+
minutes, seconds = result.elapsed_time.divmod 60
|
129
|
+
|
130
|
+
elapsed = String.new
|
131
|
+
elapsed << "#{minutes}m" unless minutes.zero?
|
132
|
+
elapsed << "%.3fs" % seconds
|
133
|
+
|
134
|
+
test_label = if result.tests == 1 then 'test' else 'tests' end
|
135
|
+
error_label = if result.errors == 1 then 'error' else 'errors' end
|
136
|
+
"Ran %d #{test_label} in #{elapsed} (%.3fs tests/second)\n%d passed, %d skipped, %d failed, %d total #{error_label}" %
|
137
|
+
[result.tests, result.tests_per_second, result.passes, result.skips, result.failures, result.errors]
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_failed prose
|
141
|
+
file_result.test_failed prose
|
142
|
+
run_result.test_failed prose
|
143
|
+
|
144
|
+
writer.quiet prose, :fg => :white, :bg => :red
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_passed prose
|
148
|
+
file_result.test_passed prose
|
149
|
+
run_result.test_passed prose
|
150
|
+
|
151
|
+
writer.normal prose, :fg => :green
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_skipped prose
|
155
|
+
file_result.test_skipped prose
|
156
|
+
run_result.test_skipped prose
|
157
|
+
|
158
|
+
writer.normal prose, :fg => :brown
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_started prose
|
162
|
+
writer.verbose "Started test #{prose.inspect}", :fg => :gray
|
163
|
+
end
|
164
|
+
|
165
|
+
def writer
|
166
|
+
@writer ||= Writer.new
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module TestBench
|
2
|
+
class Output
|
3
|
+
module Assertions
|
4
|
+
def color_output?
|
5
|
+
text = 'Some Text'
|
6
|
+
color = :gray
|
7
|
+
|
8
|
+
write text, :fg => color, :bg => color
|
9
|
+
|
10
|
+
wrote_line? text, :fg => color, :bg => color
|
11
|
+
end
|
12
|
+
|
13
|
+
def text_written
|
14
|
+
device.rewind
|
15
|
+
device.read
|
16
|
+
end
|
17
|
+
|
18
|
+
def wrote? text
|
19
|
+
text_written == text
|
20
|
+
end
|
21
|
+
|
22
|
+
def wrote_line? text, indent: nil, **colors
|
23
|
+
color ||= {}
|
24
|
+
indent ||= 0
|
25
|
+
|
26
|
+
color_escape = Palette.escape_code(**colors)
|
27
|
+
unless color_escape.empty?
|
28
|
+
text = "#{color_escape}#{text}\e[0m"
|
29
|
+
end
|
30
|
+
|
31
|
+
matcher = Regexp.escape "#{' ' * indent}#{text}"
|
32
|
+
|
33
|
+
pattern = /^#{matcher}$/n
|
34
|
+
|
35
|
+
pattern.match text_written
|
36
|
+
end
|
37
|
+
|
38
|
+
def wrote_nothing?
|
39
|
+
text_written.empty?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module TestBench
|
2
|
+
class Output
|
3
|
+
module Palette
|
4
|
+
def self.apply prose, **colors
|
5
|
+
escape_code = self.escape_code(**colors)
|
6
|
+
|
7
|
+
if escape_code.empty?
|
8
|
+
prose
|
9
|
+
else
|
10
|
+
"#{escape_code}#{prose}\e[0m"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.escape_code fg: nil, bg: nil
|
15
|
+
return '' if fg.nil? and bg.nil?
|
16
|
+
|
17
|
+
brightness, fg = get fg if fg
|
18
|
+
_, bg = get bg if bg
|
19
|
+
|
20
|
+
str = String.new "\e["
|
21
|
+
|
22
|
+
str << "#{brightness};3#{fg}" if fg
|
23
|
+
str << ';' if fg and bg
|
24
|
+
str << "4#{bg}" if bg
|
25
|
+
str << 'm'
|
26
|
+
|
27
|
+
str
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.get name
|
31
|
+
code = names.index name
|
32
|
+
return unless code
|
33
|
+
brightness, code = code.divmod 8
|
34
|
+
return brightness, code
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.names
|
38
|
+
@names ||= %i(
|
39
|
+
black
|
40
|
+
red
|
41
|
+
green
|
42
|
+
brown
|
43
|
+
blue
|
44
|
+
magenta
|
45
|
+
cyan
|
46
|
+
gray
|
47
|
+
dark_gray
|
48
|
+
bright_red
|
49
|
+
bright_green
|
50
|
+
yellow
|
51
|
+
bright_blue
|
52
|
+
bright_magenta
|
53
|
+
bright_cyan
|
54
|
+
white
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module TestBench
|
2
|
+
class Output
|
3
|
+
class Writer
|
4
|
+
attr_accessor :color
|
5
|
+
attr_writer :device
|
6
|
+
attr_accessor :indentation
|
7
|
+
attr_writer :level
|
8
|
+
attr_reader :mutex
|
9
|
+
|
10
|
+
def initialize level=nil
|
11
|
+
@level = level
|
12
|
+
@indentation = 0
|
13
|
+
@mutex = Mutex.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.build device
|
17
|
+
instance = new
|
18
|
+
instance.device = device
|
19
|
+
instance
|
20
|
+
end
|
21
|
+
|
22
|
+
def color?
|
23
|
+
return color unless color.nil?
|
24
|
+
device.tty?
|
25
|
+
end
|
26
|
+
|
27
|
+
def decrease_indentation
|
28
|
+
mutex.synchronize do
|
29
|
+
self.indentation -= 1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def device
|
34
|
+
@device ||= StringIO.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def increase_indentation
|
38
|
+
mutex.synchronize do
|
39
|
+
self.indentation += 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def level
|
44
|
+
@level ||= :normal
|
45
|
+
end
|
46
|
+
|
47
|
+
def lower_verbosity
|
48
|
+
if level == :verbose
|
49
|
+
self.level = :normal
|
50
|
+
elsif level == :normal
|
51
|
+
self.level = :quiet
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def normal prose, **arguments
|
56
|
+
arguments[:render] = false if level == :quiet
|
57
|
+
write prose, **arguments
|
58
|
+
end
|
59
|
+
|
60
|
+
def quiet prose, **arguments
|
61
|
+
write prose, **arguments
|
62
|
+
end
|
63
|
+
|
64
|
+
def raise_verbosity
|
65
|
+
if level == :quiet
|
66
|
+
self.level = :normal
|
67
|
+
elsif level == :normal
|
68
|
+
self.level = :verbose
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def verbose prose, **arguments
|
73
|
+
arguments[:render] = false unless level == :verbose
|
74
|
+
write prose, **arguments
|
75
|
+
end
|
76
|
+
|
77
|
+
def write prose, bg: nil, fg: nil, render: nil
|
78
|
+
render = true if render.nil?
|
79
|
+
|
80
|
+
if render
|
81
|
+
text = String.new prose
|
82
|
+
|
83
|
+
indentation = ' ' * self.indentation
|
84
|
+
|
85
|
+
prose = Palette.apply prose, bg: bg, fg: fg if color?
|
86
|
+
|
87
|
+
text = "#{indentation}#{prose}#{$INPUT_RECORD_SEPARATOR}"
|
88
|
+
|
89
|
+
device.write text
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|