test_bench 1.0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/lib/test_bench.rb +37 -0
  3. data/lib/test_bench/cli.rb +43 -0
  4. data/lib/test_bench/cli/parse_arguments.rb +168 -0
  5. data/lib/test_bench/controls.rb +22 -0
  6. data/lib/test_bench/controls/caller_location.rb +5 -0
  7. data/lib/test_bench/controls/depth.rb +21 -0
  8. data/lib/test_bench/controls/device.rb +27 -0
  9. data/lib/test_bench/controls/directory.rb +15 -0
  10. data/lib/test_bench/controls/error.rb +35 -0
  11. data/lib/test_bench/controls/fixture.rb +29 -0
  12. data/lib/test_bench/controls/output/escape_code.rb +23 -0
  13. data/lib/test_bench/controls/output/newline_character.rb +11 -0
  14. data/lib/test_bench/controls/output/print_error.rb +19 -0
  15. data/lib/test_bench/controls/output/styling.rb +29 -0
  16. data/lib/test_bench/controls/output/summary/error.rb +44 -0
  17. data/lib/test_bench/controls/output/summary/run.rb +59 -0
  18. data/lib/test_bench/controls/path.rb +15 -0
  19. data/lib/test_bench/controls/pattern.rb +29 -0
  20. data/lib/test_bench/controls/result.rb +5 -0
  21. data/lib/test_bench/controls/test_file.rb +5 -0
  22. data/lib/test_bench/controls/time.rb +61 -0
  23. data/lib/test_bench/deactivation_variants.rb +21 -0
  24. data/lib/test_bench/environment/boolean.rb +40 -0
  25. data/lib/test_bench/fixtures.rb +3 -0
  26. data/lib/test_bench/fixtures/configure_receiver.rb +80 -0
  27. data/lib/test_bench/output.rb +9 -0
  28. data/lib/test_bench/output/build.rb +57 -0
  29. data/lib/test_bench/output/levels/debug.rb +229 -0
  30. data/lib/test_bench/output/levels/failure.rb +31 -0
  31. data/lib/test_bench/output/levels/none.rb +13 -0
  32. data/lib/test_bench/output/levels/pass.rb +274 -0
  33. data/lib/test_bench/output/levels/summary.rb +21 -0
  34. data/lib/test_bench/output/print_error.rb +163 -0
  35. data/lib/test_bench/output/summary/error.rb +77 -0
  36. data/lib/test_bench/output/summary/run.rb +102 -0
  37. data/lib/test_bench/output/summary/run/print.rb +98 -0
  38. data/lib/test_bench/output/timer.rb +75 -0
  39. data/lib/test_bench/output/timer/substitute.rb +45 -0
  40. data/lib/test_bench/output/writer.rb +192 -0
  41. data/lib/test_bench/output/writer/dependency.rb +12 -0
  42. data/lib/test_bench/output/writer/sgr.rb +54 -0
  43. data/lib/test_bench/output/writer/substitute.rb +38 -0
  44. data/lib/test_bench/run.rb +103 -0
  45. data/lib/test_bench/run/substitute.rb +36 -0
  46. data/lib/test_bench/test_bench.rb +76 -0
  47. data/script/bench +19 -0
  48. metadata +117 -0
@@ -0,0 +1,75 @@
1
+ module TestBench
2
+ module Output
3
+ class Timer
4
+ Error = Class.new(RuntimeError)
5
+
6
+ attr_accessor :start_time
7
+
8
+ def self.configure(receiver, attr_name: nil)
9
+ attr_name ||= :timer
10
+
11
+ instance = new
12
+ receiver.public_send(:"#{attr_name}=", instance)
13
+ instance
14
+ end
15
+
16
+ def start(now=nil)
17
+ now ||= ::Time.now.utc
18
+
19
+ if mode == Mode.running
20
+ raise Error, "Timer has already started (Start Time: #{start_time})"
21
+ end
22
+
23
+ self.start_time = now
24
+ end
25
+
26
+ def stop(now=nil)
27
+ now ||= ::Time.now.utc
28
+
29
+ if mode == Mode.stopped
30
+ raise Error, "Timer has not started"
31
+ end
32
+
33
+ start_time = reset
34
+
35
+ elapsed = now - start_time
36
+
37
+ elapsed.round(3)
38
+ end
39
+
40
+ def running?
41
+ mode == Mode.running
42
+ end
43
+
44
+ def stopped?
45
+ mode == Mode.stopped
46
+ end
47
+
48
+ def mode
49
+ if start_time.nil?
50
+ Mode.stopped
51
+ else
52
+ Mode.running
53
+ end
54
+ end
55
+
56
+ def reset
57
+ previous_start_time = self.start_time
58
+
59
+ self.start_time = nil
60
+
61
+ previous_start_time
62
+ end
63
+
64
+ module Mode
65
+ def self.running
66
+ :running
67
+ end
68
+
69
+ def self.stopped
70
+ :stopped
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,45 @@
1
+ module TestBench
2
+ module Output
3
+ class Timer
4
+ module Substitute
5
+ def self.build
6
+ Timer.new
7
+ end
8
+
9
+ class Timer < Timer
10
+ def elapsed_time
11
+ @elapsed_time ||= 0
12
+ end
13
+ attr_writer :elapsed_time
14
+
15
+ def mode
16
+ @mode ||= Mode.stopped
17
+ end
18
+ attr_writer :mode
19
+
20
+ def start(_=nil)
21
+ if mode == Mode.running
22
+ raise Error, "Timer has already started"
23
+ end
24
+
25
+ self.mode = Mode.running
26
+ end
27
+
28
+ def stop(_=nil)
29
+ if mode == Mode.stopped
30
+ raise Error, "Timer has not started"
31
+ end
32
+
33
+ self.mode = Mode.stopped
34
+
35
+ elapsed_time.round(3)
36
+ end
37
+
38
+ def set(elapsed_time)
39
+ self.elapsed_time = elapsed_time
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,192 @@
1
+ module TestBench
2
+ module Output
3
+ class Writer
4
+ Error = Class.new(RuntimeError)
5
+
6
+ def device
7
+ @device ||= StringIO.new
8
+ end
9
+ attr_writer :device
10
+
11
+ attr_accessor :styling
12
+
13
+ def styling_enabled
14
+ instance_variable_defined?(:@styling_enabled) ?
15
+ @styling_enabled :
16
+ @styling_enabled = self.class.styling?(device, styling)
17
+ end
18
+ attr_writer :styling_enabled
19
+ alias_method :styling?, :styling_enabled
20
+
21
+ def mode
22
+ @mode ||= Mode.text
23
+ end
24
+ attr_writer :mode
25
+
26
+ def byte_offset
27
+ @byte_offset ||= 0
28
+ end
29
+ attr_writer :byte_offset
30
+
31
+ def indentation_depth
32
+ @indentation_depth ||= 0
33
+ end
34
+ attr_writer :indentation_depth
35
+
36
+ def configure(styling: nil, device: nil)
37
+ device ||= Defaults.device
38
+
39
+ unless styling.nil?
40
+ self.class.assure_styling_setting(styling)
41
+ end
42
+
43
+ self.device = device
44
+ self.styling = styling
45
+ end
46
+
47
+ def self.build(device=nil, styling: nil)
48
+ instance = new
49
+ instance.configure(device: device, styling: styling)
50
+ instance
51
+ end
52
+
53
+ def self.configure(receiver, writer: nil, styling: nil, device: nil, attr_name: nil)
54
+ attr_name ||= :writer
55
+
56
+ if writer.nil?
57
+ instance = build(device, styling: styling)
58
+ else
59
+ instance = writer
60
+ end
61
+
62
+ receiver.public_send(:"#{attr_name}=", instance)
63
+
64
+ instance
65
+ end
66
+
67
+ def text(text)
68
+ if mode == Mode.escape_sequence
69
+ self.mode = Mode.text
70
+
71
+ write('m')
72
+ end
73
+
74
+ write(text)
75
+
76
+ self
77
+ end
78
+
79
+ def escape_code(id)
80
+ escape_code = SGR.escape_code(id)
81
+
82
+ if mode == Mode.text
83
+ return self unless styling?
84
+
85
+ self.mode = Mode.escape_sequence
86
+
87
+ write("\e[")
88
+ else
89
+ write(';')
90
+ end
91
+
92
+ write(escape_code)
93
+
94
+ self
95
+ end
96
+
97
+ def sync
98
+ text('')
99
+ end
100
+
101
+ def indent
102
+ indentation = ' ' * indentation_depth
103
+
104
+ text(indentation)
105
+ end
106
+
107
+ def newline
108
+ sync
109
+ device.puts
110
+ self.byte_offset += 1
111
+ self
112
+ end
113
+
114
+ def write(data)
115
+ bytes_written = device.write(data)
116
+
117
+ self.byte_offset += bytes_written
118
+ end
119
+
120
+ def current?(byte_offset)
121
+ byte_offset >= self.byte_offset
122
+ end
123
+
124
+ def increase_indentation
125
+ self.indentation_depth += 1
126
+ end
127
+
128
+ def decrease_indentation
129
+ self.indentation_depth -= 1
130
+ end
131
+
132
+ def self.styling?(device, styling_setting=nil)
133
+ styling_setting ||= Defaults.styling_setting
134
+
135
+ assure_styling_setting(styling_setting)
136
+
137
+ case styling_setting
138
+ when :detect
139
+ device.tty?
140
+ when :on
141
+ true
142
+ when :off
143
+ false
144
+ end
145
+ end
146
+
147
+ def self.assure_styling_setting(styling_setting)
148
+ unless styling_settings.include?(styling_setting)
149
+ raise Error, "Invalid output styling #{styling_setting.inspect} (Valid values: #{styling_settings.map(&:inspect).join(', ')})"
150
+ end
151
+ end
152
+
153
+ def self.styling_settings
154
+ [
155
+ :detect,
156
+ :on,
157
+ :off
158
+ ]
159
+ end
160
+
161
+ def self.default_styling_setting
162
+ styling_settings.fetch(0)
163
+ end
164
+
165
+ module Mode
166
+ def self.text
167
+ :text
168
+ end
169
+
170
+ def self.escape_sequence
171
+ :escape_sequence
172
+ end
173
+ end
174
+
175
+ module Defaults
176
+ def self.device
177
+ $stdout
178
+ end
179
+
180
+ def self.styling_setting
181
+ styling = ::ENV['TEST_BENCH_OUTPUT_STYLING']
182
+
183
+ if styling.nil?
184
+ Writer.default_styling_setting
185
+ else
186
+ styling.to_sym
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,12 @@
1
+ module TestBench
2
+ module Output
3
+ class Writer
4
+ module Dependency
5
+ def writer
6
+ @writer ||= Substitute.build
7
+ end
8
+ attr_writer :writer
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,54 @@
1
+ module TestBench
2
+ module Output
3
+ class Writer
4
+ module SGR
5
+ def self.escape_code(name)
6
+ assure_escape_code(name)
7
+
8
+ code_map.fetch(name)
9
+ end
10
+
11
+ def self.assure_escape_code(name)
12
+ unless code_map.key?(name)
13
+ raise Error, "Invalid escape code #{name.inspect} (Example values: #{code_map.keys.first(3).map(&:inspect).join(', ')})"
14
+ end
15
+ end
16
+
17
+ def self.code_map
18
+ @code_map ||= {
19
+ :reset => '0',
20
+
21
+ :bold => '1',
22
+ :faint => '2',
23
+ :italic => '3',
24
+ :underline => '4',
25
+
26
+ :reset_intensity => '22',
27
+ :reset_italic => '23',
28
+ :reset_underline => '24',
29
+
30
+ :black => '30',
31
+ :red => '31',
32
+ :green => '32',
33
+ :yellow => '33',
34
+ :blue => '34',
35
+ :magenta => '35',
36
+ :cyan => '36',
37
+ :white => '37',
38
+ :reset_fg => '39',
39
+
40
+ :black_bg => '40',
41
+ :red_bg => '41',
42
+ :green_bg => '42',
43
+ :yellow_bg => '43',
44
+ :blue_bg => '44',
45
+ :magenta_bg => '45',
46
+ :cyan_bg => '46',
47
+ :white_bg => '47',
48
+ :reset_bg => '49'
49
+ }
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,38 @@
1
+ module TestBench
2
+ module Output
3
+ class Writer
4
+ module Substitute
5
+ def self.build
6
+ writer = Writer.new
7
+ writer.styling_enabled = false
8
+ writer
9
+ end
10
+
11
+ class Writer < Writer
12
+ def written?(pattern=nil)
13
+ pattern = self.pattern(pattern)
14
+
15
+ written_text = device.string
16
+
17
+ pattern.match?(written_text)
18
+ end
19
+
20
+ def pattern(pattern)
21
+ case pattern
22
+ when nil
23
+ /./
24
+ when String
25
+ Regexp.new("\\A#{Regexp.escape(pattern)}\\z")
26
+ else
27
+ pattern
28
+ end
29
+ end
30
+
31
+ def enable_styling!
32
+ self.styling_enabled = true
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,103 @@
1
+ module TestBench
2
+ class Run
3
+ Error = Class.new(RuntimeError)
4
+
5
+ def session
6
+ @session ||= Session::Substitute.build
7
+ end
8
+ attr_writer :session
9
+
10
+ def exclude_file_pattern
11
+ @exclude_file_pattern ||= Defaults.exclude_file_pattern
12
+ end
13
+ attr_writer :exclude_file_pattern
14
+
15
+ attr_reader :paths
16
+
17
+ def initialize(*paths)
18
+ @paths = Array(paths)
19
+ end
20
+
21
+ def self.build(*paths, exclude_file_pattern: nil, session: nil, output: nil)
22
+ session ||= TestBench.session
23
+
24
+ instance = new(*paths)
25
+
26
+ instance.exclude_file_pattern = exclude_file_pattern unless exclude_file_pattern.nil?
27
+
28
+ Session.configure(instance, session: session)
29
+ instance.session.output = output unless output.nil?
30
+
31
+ instance
32
+ end
33
+
34
+ def self.configure(receiver, *paths, attr_name: nil, **args)
35
+ attr_name ||= :run
36
+
37
+ instance = build(*paths, **args)
38
+ receiver.public_send(:"#{attr_name}=", instance)
39
+ instance
40
+ end
41
+
42
+ def self.call(*paths, **args, &block)
43
+ instance = build(*paths, **args)
44
+
45
+ if block.nil?
46
+ instance.()
47
+ else
48
+ instance.() do
49
+ block.(instance)
50
+ end
51
+ end
52
+ end
53
+
54
+ def call(&block)
55
+ session.start
56
+
57
+ if block.nil?
58
+ paths.each do |path|
59
+ path(path)
60
+ end
61
+ else
62
+ block.()
63
+ end
64
+
65
+ ensure
66
+ session.finish
67
+ end
68
+
69
+ def path(path)
70
+ if File.directory?(path)
71
+ directory(path)
72
+ elsif File.exist?(path)
73
+ file(path)
74
+ else
75
+ raise Error, "Path not found (Path: #{path.inspect})"
76
+ end
77
+ end
78
+
79
+ def directory(path)
80
+ glob_pattern = File.join(path, '**/*.rb')
81
+
82
+ Dir[glob_pattern].sort.each do |path|
83
+ next if exclude_file_pattern.match?(path)
84
+
85
+ file(path)
86
+ end
87
+ end
88
+
89
+ def file(path)
90
+ session.load(path)
91
+ end
92
+
93
+ module Defaults
94
+ def self.exclude_file_pattern
95
+ pattern = ENV.fetch('TEST_BENCH_EXCLUDE_FILE_PATTERN') do
96
+ '_init.rb$'
97
+ end
98
+
99
+ Regexp.new(pattern)
100
+ end
101
+ end
102
+ end
103
+ end