test_bench-session 2.0.0.0 → 2.1.0.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/lib/test_bench/session/controls/comment.rb +93 -4
  3. data/lib/test_bench/session/controls/detail.rb +79 -4
  4. data/lib/test_bench/session/controls/event.rb +7 -0
  5. data/lib/test_bench/session/controls/events/commented.rb +91 -10
  6. data/lib/test_bench/session/controls/events/context_finished.rb +49 -11
  7. data/lib/test_bench/session/controls/events/context_skipped.rb +26 -8
  8. data/lib/test_bench/session/controls/events/context_started.rb +44 -9
  9. data/lib/test_bench/session/controls/events/detailed.rb +91 -10
  10. data/lib/test_bench/session/controls/{capture_sink/event.rb → events/event_data.rb} +2 -2
  11. data/lib/test_bench/session/controls/events/failed.rb +27 -15
  12. data/lib/test_bench/session/controls/events/fixture_finished.rb +32 -11
  13. data/lib/test_bench/session/controls/events/fixture_started.rb +26 -8
  14. data/lib/test_bench/session/controls/events/test_finished.rb +49 -11
  15. data/lib/test_bench/session/controls/events/test_skipped.rb +26 -8
  16. data/lib/test_bench/session/controls/events/test_started.rb +44 -9
  17. data/lib/test_bench/session/controls/events.rb +15 -9
  18. data/lib/test_bench/session/controls/exception.rb +28 -10
  19. data/lib/test_bench/session/controls/failure.rb +5 -16
  20. data/lib/test_bench/session/controls/fixture.rb +7 -4
  21. data/lib/test_bench/session/controls/output/detail.rb +29 -0
  22. data/lib/test_bench/session/controls/output.rb +55 -0
  23. data/lib/test_bench/session/controls/random.rb +1 -1
  24. data/lib/test_bench/session/controls/result.rb +15 -4
  25. data/lib/test_bench/session/controls/{capture_sink → substitute}/path.rb +6 -3
  26. data/lib/test_bench/session/controls/title.rb +24 -12
  27. data/lib/test_bench/session/controls.rb +12 -12
  28. data/lib/test_bench/session/events.rb +7 -14
  29. data/lib/test_bench/session/output/get.rb +27 -0
  30. data/lib/test_bench/session/output/writer/buffer/interactive/viewport.rb +164 -0
  31. data/lib/test_bench/session/output/writer/buffer/interactive.rb +139 -0
  32. data/lib/test_bench/session/output/writer/buffer.rb +27 -0
  33. data/lib/test_bench/session/output/writer/defaults.rb +17 -0
  34. data/lib/test_bench/session/output/writer/substitute.rb +17 -0
  35. data/lib/test_bench/session/output/writer.rb +95 -0
  36. data/lib/test_bench/session/output.rb +375 -0
  37. data/lib/test_bench/session/projection.rb +28 -0
  38. data/lib/test_bench/session/session.rb +51 -65
  39. data/lib/test_bench/session/store.rb +59 -0
  40. data/lib/test_bench/session/substitute/path.rb +63 -0
  41. data/lib/test_bench/session/substitute/sink.rb +104 -0
  42. data/lib/test_bench/session/substitute.rb +17 -34
  43. data/lib/test_bench/session.rb +16 -5
  44. metadata +22 -17
  45. data/lib/test_bench/session/controls/capture_sink/record.rb +0 -19
  46. data/lib/test_bench/session/controls/events/aborted.rb +0 -29
  47. data/lib/test_bench/session/controls/events/file_finished.rb +0 -32
  48. data/lib/test_bench/session/controls/events/file_started.rb +0 -29
  49. data/lib/test_bench/session/controls/events/finished.rb +0 -32
  50. data/lib/test_bench/session/controls/events/started.rb +0 -29
  51. data/lib/test_bench/session/controls/file.rb +0 -58
  52. data/lib/test_bench/session/telemetry/capture_sink/path.rb +0 -65
  53. data/lib/test_bench/session/telemetry/capture_sink/record.rb +0 -39
  54. data/lib/test_bench/session/telemetry/capture_sink.rb +0 -63
@@ -2,24 +2,36 @@ module TestBench
2
2
  class Session
3
3
  module Controls
4
4
  module Title
5
- module Test
6
- def self.example(suffix=nil)
7
- suffix = " #{suffix}" if not suffix.nil?
5
+ module Context
6
+ def self.example
7
+ "Some Context"
8
+ end
9
+
10
+ def self.other_example
11
+ "Some Other Context"
12
+ end
13
+
14
+ def self.random
15
+ suffix = Random.string
8
16
 
9
- "Some test#{suffix}"
17
+ "#{example} #{suffix}"
10
18
  end
11
- def self.other_example = "Some other test"
12
- def self.random = example(Random.string)
13
19
  end
14
20
 
15
- module Context
16
- def self.example(suffix=nil)
17
- suffix = " #{suffix}" if not suffix.nil?
21
+ module Test
22
+ def self.example
23
+ "Some test"
24
+ end
25
+
26
+ def self.other_example
27
+ "Some other test"
28
+ end
29
+
30
+ def self.random
31
+ suffix = Random.string
18
32
 
19
- "Some Context#{suffix}"
33
+ "#{example} #{suffix}"
20
34
  end
21
- def self.other_example = "Some Other Context"
22
- def self.random = example(Random.string)
23
35
  end
24
36
  end
25
37
  end
@@ -1,4 +1,5 @@
1
1
  require 'test_bench/telemetry/controls'
2
+ require 'test_bench/output/controls'
2
3
 
3
4
  require 'test_bench/session/controls/random'
4
5
  require 'test_bench/session/controls/time'
@@ -8,29 +9,28 @@ require 'test_bench/session/controls/exception'
8
9
 
9
10
  require 'test_bench/session/controls/failure'
10
11
  require 'test_bench/session/controls/title'
12
+ require 'test_bench/session/controls/exception'
11
13
  require 'test_bench/session/controls/comment'
12
14
  require 'test_bench/session/controls/detail'
13
15
  require 'test_bench/session/controls/fixture'
14
- require 'test_bench/session/controls/file'
15
16
 
17
+ require 'test_bench/session/controls/events/event_data'
16
18
  require 'test_bench/session/controls/events/failed'
17
- require 'test_bench/session/controls/events/test_started'
18
- require 'test_bench/session/controls/events/test_finished'
19
- require 'test_bench/session/controls/events/test_skipped'
20
19
  require 'test_bench/session/controls/events/context_started'
21
20
  require 'test_bench/session/controls/events/context_finished'
22
21
  require 'test_bench/session/controls/events/context_skipped'
22
+ require 'test_bench/session/controls/events/test_started'
23
+ require 'test_bench/session/controls/events/test_finished'
24
+ require 'test_bench/session/controls/events/test_skipped'
23
25
  require 'test_bench/session/controls/events/commented'
24
26
  require 'test_bench/session/controls/events/detailed'
25
27
  require 'test_bench/session/controls/events/fixture_started'
26
28
  require 'test_bench/session/controls/events/fixture_finished'
27
- require 'test_bench/session/controls/events/file_started'
28
- require 'test_bench/session/controls/events/file_finished'
29
- require 'test_bench/session/controls/events/started'
30
- require 'test_bench/session/controls/events/aborted'
31
- require 'test_bench/session/controls/events/finished'
32
29
  require 'test_bench/session/controls/events'
33
30
 
34
- require 'test_bench/session/controls/capture_sink/path'
35
- require 'test_bench/session/controls/capture_sink/event'
36
- require 'test_bench/session/controls/capture_sink/record'
31
+ require 'test_bench/session/controls/substitute/path'
32
+
33
+ require 'test_bench/session/controls/event'
34
+
35
+ require 'test_bench/session/controls/output'
36
+ require 'test_bench/session/controls/output/detail'
@@ -5,28 +5,21 @@ module TestBench
5
5
  constants(false).each(&block)
6
6
  end
7
7
 
8
- Failed = TestBench::Telemetry::Event.define(:message, :path, :line_number)
9
-
10
- TestStarted = TestBench::Telemetry::Event.define(:title)
11
- TestFinished = TestBench::Telemetry::Event.define(:title, :result)
12
- TestSkipped = TestBench::Telemetry::Event.define(:title)
8
+ Failed = TestBench::Telemetry::Event.define(:message)
13
9
 
14
10
  ContextStarted = TestBench::Telemetry::Event.define(:title)
15
11
  ContextFinished = TestBench::Telemetry::Event.define(:title, :result)
16
12
  ContextSkipped = TestBench::Telemetry::Event.define(:title)
17
13
 
18
- Commented = TestBench::Telemetry::Event.define(:text)
19
- Detailed = TestBench::Telemetry::Event.define(:text)
14
+ TestStarted = TestBench::Telemetry::Event.define(:title)
15
+ TestFinished = TestBench::Telemetry::Event.define(:title, :result)
16
+ TestSkipped = TestBench::Telemetry::Event.define(:title)
17
+
18
+ Commented = TestBench::Telemetry::Event.define(:text, :quote, :heading)
19
+ Detailed = TestBench::Telemetry::Event.define(:text, :quote, :heading)
20
20
 
21
21
  FixtureStarted = TestBench::Telemetry::Event.define(:name)
22
22
  FixtureFinished = TestBench::Telemetry::Event.define(:name, :result)
23
-
24
- FileStarted = TestBench::Telemetry::Event.define(:path)
25
- FileFinished = TestBench::Telemetry::Event.define(:path, :result)
26
-
27
- Started = TestBench::Telemetry::Event.define(:process_count)
28
- Aborted = TestBench::Telemetry::Event.define(:abort_process_id)
29
- Finished = TestBench::Telemetry::Event.define(:result, :process_count)
30
23
  end
31
24
  end
32
25
  end
@@ -0,0 +1,27 @@
1
+ module TestBench
2
+ class Session
3
+ class Output
4
+ module Get
5
+ def self.call(substitute_session, styling: nil)
6
+ styling = true if styling.nil?
7
+
8
+ session_sink = substitute_session.sink
9
+
10
+ output = Output.new
11
+
12
+ if styling
13
+ output.writer.styling!
14
+ end
15
+
16
+ session_sink.records.each do |record|
17
+ event_data = record.event_data
18
+
19
+ output.receive(event_data)
20
+ end
21
+
22
+ output.writer.written_text
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,164 @@
1
+ module TestBench
2
+ class Session
3
+ class Output
4
+ class Writer
5
+ module Buffer
6
+ class Interactive
7
+ Viewport = Struct.new(:width, :height, :row, :column, :scroll_rows, :rows_scrolled) do
8
+ def self.build(width, height, row, column, scroll_rows=nil)
9
+ scroll_rows ||= 0
10
+
11
+ rows_scrolled = 0
12
+
13
+ new(width, height, row, column, scroll_rows, rows_scrolled)
14
+ end
15
+
16
+ def self.null
17
+ build(0, 0, 0, 0)
18
+ end
19
+
20
+ def self.get
21
+ width, height, row, column = nil
22
+
23
+ STDIN.raw do |stdin|
24
+ height, width = stdin.winsize
25
+
26
+ row, column = stdin.cursor
27
+ end
28
+
29
+ scroll_rows = row
30
+
31
+ build(width, height, row, column, scroll_rows)
32
+ end
33
+
34
+ def write(text)
35
+ bytes_written = 0
36
+
37
+ escape_sequence_pattern = self.class.escape_sequence_pattern
38
+
39
+ until text.empty?
40
+ write_text, escape_sequence, text = text.partition(escape_sequence_pattern)
41
+
42
+ bytes_written += write!(write_text)
43
+ bytes_written += escape_sequence.bytesize
44
+ end
45
+
46
+ bytes_written
47
+ end
48
+
49
+ def write!(text)
50
+ newline = text.end_with?("\n")
51
+
52
+ if newline
53
+ text = text[0...-1]
54
+ end
55
+
56
+ bytes_written = write_text(text)
57
+
58
+ if newline
59
+ bytes_written += write_newline
60
+ end
61
+
62
+ bytes_written
63
+ end
64
+
65
+ def write_text(text)
66
+ if text.start_with?("\e")
67
+ return text.bytesize
68
+ end
69
+
70
+ written_text = text[0...capacity]
71
+
72
+ bytes_written = written_text.bytesize
73
+
74
+ row = self.row
75
+ column = self.column
76
+
77
+ text_rows, text_columns = bytes_written.divmod(width)
78
+
79
+ row += text_rows
80
+
81
+ columns_remaining = width - column
82
+ if columns_remaining > text_columns
83
+ column += text_columns
84
+ else
85
+ row += 1
86
+ column = text_columns - columns_remaining
87
+ end
88
+
89
+ if row >= height
90
+ final_row = height - 1
91
+
92
+ scroll_rows = row - final_row
93
+ self.rows_scrolled += scroll_rows
94
+
95
+ row = final_row
96
+ end
97
+
98
+ self.row = row
99
+ self.column = column
100
+
101
+ bytes_written
102
+ end
103
+
104
+ def write_newline
105
+ if bottom_row?
106
+ if scroll_rows_remaining.zero?
107
+ return 0
108
+ end
109
+
110
+ self.rows_scrolled += 1
111
+ else
112
+ self.row += 1
113
+ end
114
+
115
+ self.column = 0
116
+
117
+ 1
118
+ end
119
+
120
+ def capacity?
121
+ if scroll_rows_remaining > 0
122
+ true
123
+ else
124
+ not bottom_row?
125
+ end
126
+ end
127
+
128
+ def capacity
129
+ capacity = 0
130
+
131
+ rows_remaining = height + scroll_rows_remaining - row - 1
132
+
133
+ if rows_remaining > 0
134
+ capacity += (rows_remaining - 1) * width
135
+
136
+ final_row = width - column
137
+ capacity += final_row
138
+ end
139
+
140
+ capacity
141
+ end
142
+
143
+ def scroll_rows_remaining
144
+ scroll_rows - rows_scrolled
145
+ end
146
+
147
+ def bottom_row?
148
+ row == height - 1
149
+ end
150
+
151
+ def self.escape_sequence_pattern
152
+ initiator = %r{\e\[}
153
+ terminator = %r{[[:alpha:]]}
154
+ sequence = %r{[[:digit:]]+(?:;[[:digit:]]+)*}
155
+
156
+ %r{#{initiator}#{sequence}?#{terminator}}
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,139 @@
1
+ module TestBench
2
+ class Session
3
+ class Output
4
+ class Writer
5
+ module Buffer
6
+ class Interactive
7
+ attr_accessor :viewport
8
+
9
+ attr_accessor :raw_stderr
10
+
11
+ attr_accessor :stderr_pipe
12
+
13
+ def stderr_buffer
14
+ @stderr_buffer ||= String.new
15
+ end
16
+
17
+ def device
18
+ @device ||= TestBench::Output::Device::Substitute.build
19
+ end
20
+ attr_writer :device
21
+
22
+ attr_accessor :buffering
23
+ def buffering? = !!buffering
24
+
25
+ def self.build(device=nil)
26
+ device ||= Defaults.device
27
+
28
+ instance = new
29
+ instance.device = device
30
+ instance
31
+ end
32
+
33
+ def self.configure(receiver, device: nil, attr_name: nil)
34
+ attr_name ||= :buffer
35
+
36
+ instance = build(device)
37
+ receiver.public_send(:"#{attr_name}=", instance)
38
+ end
39
+
40
+ def receive(text)
41
+ if not cursor_saved?
42
+ save_cursor
43
+ end
44
+
45
+ bytes_written = viewport.write(text)
46
+
47
+ write_text = text.byteslice(0, bytes_written)
48
+ device.write(write_text)
49
+
50
+ if not viewport.capacity?
51
+ if not buffering?
52
+ buffering_message = "Output is buffering"
53
+
54
+ device.write("\e[0G\e[2m#{buffering_message}\e[22m")
55
+
56
+ self.buffering = true
57
+ end
58
+ end
59
+
60
+ update_stderr_buffer
61
+
62
+ bytes_written
63
+ end
64
+
65
+ def flush(*_devices)
66
+ if cursor_saved?
67
+ update_stderr_buffer
68
+ restore_cursor
69
+ end
70
+ end
71
+
72
+ def save_cursor
73
+ self.viewport = Viewport.get
74
+
75
+ self.raw_stderr = STDERR.dup
76
+
77
+ reader, writer = IO.pipe
78
+
79
+ new_stderr = writer
80
+ STDERR.reopen(new_stderr)
81
+
82
+ stderr_buffer.clear
83
+
84
+ self.stderr_pipe = reader
85
+
86
+ device.write("\e[s")
87
+ end
88
+
89
+ def restore_cursor
90
+ stderr_pipe.close
91
+
92
+ device.write("\e[u")
93
+
94
+ rows_scrolled = viewport.rows_scrolled
95
+
96
+ if not rows_scrolled.zero?
97
+ upward_movements = rows_scrolled
98
+ device.write("\e[#{upward_movements}F")
99
+ end
100
+
101
+ stderr_buffer.each_line do |line|
102
+ raw_stderr.write("\e[0K")
103
+ raw_stderr.write(line)
104
+ end
105
+
106
+ STDERR.reopen(raw_stderr)
107
+ self.raw_stderr = nil
108
+
109
+ self.viewport = nil
110
+ end
111
+
112
+ def update_stderr_buffer
113
+ loop do
114
+ stderr_text = stderr_pipe.read_nonblock(4096, exception: false)
115
+
116
+ if stderr_text == :wait_readable
117
+ break
118
+ end
119
+
120
+ viewport.write(stderr_text)
121
+
122
+ if not buffering?
123
+ raw_stderr.write(stderr_text)
124
+ end
125
+
126
+ self.stderr_buffer << stderr_text
127
+ end
128
+ end
129
+
130
+ def viewport?
131
+ !viewport.nil?
132
+ end
133
+ alias :cursor_saved? :viewport?
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,27 @@
1
+ module TestBench
2
+ class Session
3
+ class Output
4
+ class Writer
5
+ module Buffer
6
+ def self.configure(receiver, device: nil, experimental_output: nil, attr_name: nil)
7
+ device ||= Defaults.device
8
+ experimental_output ||= Defaults.experimental_output
9
+ attr_name ||= :buffer
10
+
11
+ if experimental_output
12
+ interactive = device.tty?
13
+ else
14
+ interactive = false
15
+ end
16
+
17
+ if interactive
18
+ Buffer::Interactive.configure(receiver, device:, attr_name:)
19
+ else
20
+ TestBench::Output::Writer::Buffer.configure(receiver, attr_name:)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ module TestBench
2
+ class Session
3
+ class Output
4
+ class Writer
5
+ module Defaults
6
+ def self.device
7
+ TestBench::Output::Writer::Defaults.device
8
+ end
9
+
10
+ def self.experimental_output
11
+ ENV.fetch('TEST_BENCH_EXPERIMENTAL_OUTPUT', 'off') == 'on'
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module TestBench
2
+ class Session
3
+ class Output
4
+ class Writer
5
+ module Substitute
6
+ def self.build
7
+ Writer.build
8
+ end
9
+
10
+ class Writer < Writer
11
+ include TestBench::Output::Writer::Substitute
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,95 @@
1
+ module TestBench
2
+ class Session
3
+ class Output
4
+ class Writer < TestBench::Output::Writer
5
+ attr_accessor :peer
6
+
7
+ def alternate_device
8
+ @alternate_device ||= TestBench::Output::Device::Substitute.build
9
+ end
10
+ attr_writer :alternate_device
11
+
12
+ def indentation_depth
13
+ @indentation_depth ||= 0
14
+ end
15
+ attr_writer :indentation_depth
16
+
17
+ def configure
18
+ device = self.device
19
+
20
+ self.alternate_device = TestBench::Output::Device::Null.build
21
+
22
+ Buffer.configure(self, device:)
23
+ end
24
+
25
+ def self.follow(previous_writer)
26
+ device = previous_writer
27
+
28
+ alternate_device = previous_writer.peer
29
+ alternate_device ||= TestBench::Output::Device::Null.build
30
+
31
+ previous_digest = previous_writer.digest
32
+ digest = previous_digest.clone
33
+
34
+ writer = new
35
+ writer.sync = false
36
+ writer.device = device
37
+ writer.alternate_device = alternate_device
38
+ writer.styling_policy = previous_writer.styling_policy
39
+ writer.digest = digest
40
+ writer.sequence = previous_writer.sequence
41
+ writer.column_sequence = previous_writer.column_sequence
42
+ writer.indentation_depth = previous_writer.indentation_depth
43
+ writer.digest = previous_writer.digest.clone
44
+ writer
45
+ end
46
+
47
+ def branch
48
+ alternate = self.class.follow(self)
49
+ primary = self.class.follow(self)
50
+
51
+ primary.peer = alternate
52
+
53
+ return primary, alternate
54
+ end
55
+
56
+ def indent
57
+ indentation = ' ' * indentation_depth
58
+
59
+ print(indentation)
60
+ end
61
+
62
+ def flush
63
+ buffer.flush(device, alternate_device)
64
+ end
65
+
66
+ def write!(data)
67
+ device.write(data)
68
+ alternate_device.write(data)
69
+ end
70
+
71
+ def increase_indentation
72
+ self.indentation_depth += 1
73
+ end
74
+ alias :indent! :increase_indentation
75
+
76
+ def decrease_indentation
77
+ self.indentation_depth -= 1
78
+ end
79
+ alias :deindent! :decrease_indentation
80
+
81
+ def follows?(other_writer)
82
+ if sequence < other_writer.sequence
83
+ false
84
+ elsif device == other_writer
85
+ true
86
+ elsif device == other_writer.peer
87
+ true
88
+ else
89
+ false
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end