test_bench-session 2.0.0.0 → 2.1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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