test_bench_legacy 1.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/bin/bench +10 -0
  3. data/lib/test_bench.rb +37 -0
  4. data/lib/test_bench/activate.rb +3 -0
  5. data/lib/test_bench/assert.rb +58 -0
  6. data/lib/test_bench/assert/failed.rb +25 -0
  7. data/lib/test_bench/assert/proc.rb +24 -0
  8. data/lib/test_bench/assert/refute.rb +9 -0
  9. data/lib/test_bench/cli.rb +4 -0
  10. data/lib/test_bench/cli/cli.rb +108 -0
  11. data/lib/test_bench/controls.rb +16 -0
  12. data/lib/test_bench/controls/binding.rb +17 -0
  13. data/lib/test_bench/controls/clock/elapsed.rb +41 -0
  14. data/lib/test_bench/controls/clock/reference.rb +15 -0
  15. data/lib/test_bench/controls/dir_substitute.rb +58 -0
  16. data/lib/test_bench/controls/error.rb +63 -0
  17. data/lib/test_bench/controls/executor/substitute.rb +27 -0
  18. data/lib/test_bench/controls/expand_path.rb +23 -0
  19. data/lib/test_bench/controls/fixture.rb +36 -0
  20. data/lib/test_bench/controls/kernel_substitute.rb +72 -0
  21. data/lib/test_bench/controls/output.rb +106 -0
  22. data/lib/test_bench/controls/path.rb +11 -0
  23. data/lib/test_bench/controls/result.rb +64 -0
  24. data/lib/test_bench/controls/telemetry.rb +23 -0
  25. data/lib/test_bench/controls/test_script.rb +23 -0
  26. data/lib/test_bench/executor.rb +45 -0
  27. data/lib/test_bench/expand_path.rb +44 -0
  28. data/lib/test_bench/fixture.rb +17 -0
  29. data/lib/test_bench/output.rb +169 -0
  30. data/lib/test_bench/output/assertions.rb +43 -0
  31. data/lib/test_bench/output/palette.rb +59 -0
  32. data/lib/test_bench/output/writer.rb +94 -0
  33. data/lib/test_bench/output/writer/assertions.rb +29 -0
  34. data/lib/test_bench/output/writer/assertions/line.rb +76 -0
  35. data/lib/test_bench/registry.rb +32 -0
  36. data/lib/test_bench/result.rb +71 -0
  37. data/lib/test_bench/result/assertions.rb +11 -0
  38. data/lib/test_bench/result/null.rb +12 -0
  39. data/lib/test_bench/runner.rb +59 -0
  40. data/lib/test_bench/settings.rb +62 -0
  41. data/lib/test_bench/settings/defaults.rb +29 -0
  42. data/lib/test_bench/settings/environment.rb +124 -0
  43. data/lib/test_bench/settings/registry.rb +17 -0
  44. data/lib/test_bench/structure.rb +89 -0
  45. data/lib/test_bench/telemetry.rb +130 -0
  46. data/lib/test_bench/telemetry/assertions.rb +85 -0
  47. data/lib/test_bench/telemetry/registry.rb +17 -0
  48. data/lib/test_bench/telemetry/subscription.rb +23 -0
  49. data/lib/test_bench/test_bench.rb +33 -0
  50. 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