test_bench-session 2.0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/lib/test_bench/session/controls/capture_sink/event.rb +9 -0
  3. data/lib/test_bench/session/controls/capture_sink/path.rb +30 -0
  4. data/lib/test_bench/session/controls/capture_sink/record.rb +19 -0
  5. data/lib/test_bench/session/controls/comment.rb +16 -0
  6. data/lib/test_bench/session/controls/detail.rb +16 -0
  7. data/lib/test_bench/session/controls/events/aborted.rb +29 -0
  8. data/lib/test_bench/session/controls/events/commented.rb +29 -0
  9. data/lib/test_bench/session/controls/events/context_finished.rb +32 -0
  10. data/lib/test_bench/session/controls/events/context_skipped.rb +29 -0
  11. data/lib/test_bench/session/controls/events/context_started.rb +29 -0
  12. data/lib/test_bench/session/controls/events/detailed.rb +29 -0
  13. data/lib/test_bench/session/controls/events/failed.rb +35 -0
  14. data/lib/test_bench/session/controls/events/file_finished.rb +32 -0
  15. data/lib/test_bench/session/controls/events/file_started.rb +29 -0
  16. data/lib/test_bench/session/controls/events/finished.rb +32 -0
  17. data/lib/test_bench/session/controls/events/fixture_finished.rb +32 -0
  18. data/lib/test_bench/session/controls/events/fixture_started.rb +29 -0
  19. data/lib/test_bench/session/controls/events/started.rb +29 -0
  20. data/lib/test_bench/session/controls/events/test_finished.rb +32 -0
  21. data/lib/test_bench/session/controls/events/test_skipped.rb +29 -0
  22. data/lib/test_bench/session/controls/events/test_started.rb +29 -0
  23. data/lib/test_bench/session/controls/events.rb +27 -0
  24. data/lib/test_bench/session/controls/exception.rb +27 -0
  25. data/lib/test_bench/session/controls/failure.rb +30 -0
  26. data/lib/test_bench/session/controls/file.rb +58 -0
  27. data/lib/test_bench/session/controls/fixture.rb +16 -0
  28. data/lib/test_bench/session/controls/process_id.rb +7 -0
  29. data/lib/test_bench/session/controls/random.rb +7 -0
  30. data/lib/test_bench/session/controls/result.rb +12 -0
  31. data/lib/test_bench/session/controls/time.rb +7 -0
  32. data/lib/test_bench/session/controls/title.rb +27 -0
  33. data/lib/test_bench/session/controls.rb +36 -0
  34. data/lib/test_bench/session/events.rb +32 -0
  35. data/lib/test_bench/session/session.rb +232 -0
  36. data/lib/test_bench/session/substitute.rb +93 -0
  37. data/lib/test_bench/session/telemetry/capture_sink/path.rb +65 -0
  38. data/lib/test_bench/session/telemetry/capture_sink/record.rb +39 -0
  39. data/lib/test_bench/session/telemetry/capture_sink.rb +63 -0
  40. data/lib/test_bench/session.rb +11 -0
  41. metadata +109 -0
@@ -0,0 +1,30 @@
1
+ module TestBench
2
+ class Session
3
+ module Controls
4
+ module Failure
5
+ module Message
6
+ def self.example(suffix=nil)
7
+ suffix = " #{suffix}" if not suffix.nil?
8
+
9
+ "Some failure message#{suffix}"
10
+ end
11
+ def self.random = example(Controls::Random.string)
12
+ end
13
+
14
+ module Path
15
+ def self.example(suffix=nil)
16
+ suffix = "_#{suffix}" if not suffix.nil?
17
+
18
+ "path/to/some_file#{suffix}.rb"
19
+ end
20
+ def self.random = example(Controls::Random.string)
21
+ end
22
+
23
+ module LineNumber
24
+ def self.example = 11
25
+ def self.random = Controls::Random.integer % 1111
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,58 @@
1
+ module TestBench
2
+ class Session
3
+ module Controls
4
+ module File
5
+ def self.example(contents=nil)
6
+ contents ||= self.contents
7
+
8
+ path = TestBench::Telemetry::Controls::File::Temporary.example
9
+
10
+ ::File.write(path, contents)
11
+
12
+ path
13
+ end
14
+
15
+ def self.contents = Pass.contents
16
+
17
+ module Failure
18
+ def self.example(session: nil)
19
+ contents = contents(session:)
20
+
21
+ File.example(contents)
22
+ end
23
+
24
+ def self.contents(session: nil)
25
+ session ||= Session.new
26
+
27
+ <<~RUBY
28
+ session = ObjectSpace._id2ref(#{session.object_id})
29
+ session.assert(false, __FILE__, __LINE__)
30
+ RUBY
31
+ end
32
+ end
33
+
34
+ module Pass
35
+ def self.example
36
+ File.example(contents)
37
+ end
38
+
39
+ def self.contents
40
+ ''
41
+ end
42
+ end
43
+
44
+ module Path
45
+ def self.example(suffix=nil)
46
+ extension = '.rb'
47
+
48
+ filename = TestBench::Telemetry::Controls::File::Name.example(suffix, extension:)
49
+
50
+ ::File.join('some_dir', 'some_other_dir', filename)
51
+ end
52
+
53
+ def self.random = example(Random.string)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,16 @@
1
+ module TestBench
2
+ class Session
3
+ module Controls
4
+ module Fixture
5
+ module Name
6
+ def self.example(suffix=nil)
7
+ suffix = "_#{suffix}" if not suffix.nil?
8
+
9
+ "SomeNamespace::SomeFixture#{suffix}"
10
+ end
11
+ def self.random = example(Random.string)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ module TestBench
2
+ class Session
3
+ module Controls
4
+ ProcessID = TestBench::Telemetry::Controls::ProcessID
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module TestBench
2
+ class Session
3
+ module Controls
4
+ Random = TestBench::Telemetry::Controls::Random
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ module TestBench
2
+ class Session
3
+ module Controls
4
+ module Result
5
+ def self.example = pass
6
+ def self.pass = true
7
+ def self.failure = false
8
+ def self.random = Random.boolean
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ module TestBench
2
+ class Session
3
+ module Controls
4
+ Time = TestBench::Telemetry::Controls::Time
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,27 @@
1
+ module TestBench
2
+ class Session
3
+ module Controls
4
+ module Title
5
+ module Test
6
+ def self.example(suffix=nil)
7
+ suffix = " #{suffix}" if not suffix.nil?
8
+
9
+ "Some test#{suffix}"
10
+ end
11
+ def self.other_example = "Some other test"
12
+ def self.random = example(Random.string)
13
+ end
14
+
15
+ module Context
16
+ def self.example(suffix=nil)
17
+ suffix = " #{suffix}" if not suffix.nil?
18
+
19
+ "Some Context#{suffix}"
20
+ end
21
+ def self.other_example = "Some Other Context"
22
+ def self.random = example(Random.string)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ require 'test_bench/telemetry/controls'
2
+
3
+ require 'test_bench/session/controls/random'
4
+ require 'test_bench/session/controls/time'
5
+ require 'test_bench/session/controls/process_id'
6
+ require 'test_bench/session/controls/result'
7
+ require 'test_bench/session/controls/exception'
8
+
9
+ require 'test_bench/session/controls/failure'
10
+ require 'test_bench/session/controls/title'
11
+ require 'test_bench/session/controls/comment'
12
+ require 'test_bench/session/controls/detail'
13
+ require 'test_bench/session/controls/fixture'
14
+ require 'test_bench/session/controls/file'
15
+
16
+ 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
+ require 'test_bench/session/controls/events/context_started'
21
+ require 'test_bench/session/controls/events/context_finished'
22
+ require 'test_bench/session/controls/events/context_skipped'
23
+ require 'test_bench/session/controls/events/commented'
24
+ require 'test_bench/session/controls/events/detailed'
25
+ require 'test_bench/session/controls/events/fixture_started'
26
+ 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
+ require 'test_bench/session/controls/events'
33
+
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'
@@ -0,0 +1,32 @@
1
+ module TestBench
2
+ class Session
3
+ module Events
4
+ def self.each_type(&block)
5
+ constants(false).each(&block)
6
+ end
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)
13
+
14
+ ContextStarted = TestBench::Telemetry::Event.define(:title)
15
+ ContextFinished = TestBench::Telemetry::Event.define(:title, :result)
16
+ ContextSkipped = TestBench::Telemetry::Event.define(:title)
17
+
18
+ Commented = TestBench::Telemetry::Event.define(:text)
19
+ Detailed = TestBench::Telemetry::Event.define(:text)
20
+
21
+ FixtureStarted = TestBench::Telemetry::Event.define(:name)
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
+ end
31
+ end
32
+ end
@@ -0,0 +1,232 @@
1
+ module TestBench
2
+ class Session
3
+ Failure = Class.new(RuntimeError)
4
+ Abort = Class.new(Failure)
5
+
6
+ def telemetry
7
+ @telemetry ||= TestBench::Telemetry::Substitute.build
8
+ end
9
+ attr_writer :telemetry
10
+
11
+ def failure_sequence
12
+ @failure_sequence ||= 0
13
+ end
14
+ attr_writer :failure_sequence
15
+
16
+ def assertion_sequence
17
+ @assertion_sequence ||= 0
18
+ end
19
+ attr_writer :assertion_sequence
20
+
21
+ def skip_sequence
22
+ @skip_sequence ||= 0
23
+ end
24
+ attr_writer :skip_sequence
25
+
26
+ def self.build(*sinks)
27
+ instance = new
28
+ TestBench::Telemetry.configure(instance, *sinks)
29
+ instance
30
+ end
31
+
32
+ def self.configure(receiver, *sinks, attr_name: nil)
33
+ attr_name ||= :test_session
34
+
35
+ instance = build(*sinks)
36
+ receiver.public_send(:"#{attr_name}=", instance)
37
+ end
38
+
39
+ def start(process_count)
40
+ telemetry.record(Events::Started.new(process_count))
41
+ end
42
+
43
+ def abort(abort_process_id)
44
+ record_failure
45
+
46
+ telemetry.record(Events::Aborted.new(abort_process_id))
47
+ end
48
+
49
+ def finish(process_count)
50
+ result = !failed?
51
+
52
+ telemetry.record(Events::Finished.new(result, process_count))
53
+ end
54
+
55
+ def file(path)
56
+ original_failure_sequence = failure_sequence
57
+
58
+ telemetry.record(Events::FileStarted.new(path))
59
+
60
+ source = File.read(path)
61
+
62
+ begin
63
+ TOPLEVEL_BINDING.eval(source, path)
64
+ rescue Failure
65
+ end
66
+
67
+ result = !failed?(original_failure_sequence)
68
+
69
+ telemetry.record(Events::FileFinished.new(path, result))
70
+
71
+ result
72
+ end
73
+
74
+ def fixture(name, &block)
75
+ original_failure_sequence = failure_sequence
76
+
77
+ telemetry.record(Events::FixtureStarted.new(name))
78
+
79
+ begin
80
+ block.()
81
+ rescue Failure
82
+ end
83
+
84
+ result = !failed?(original_failure_sequence)
85
+
86
+ telemetry.record(Events::FixtureFinished.new(name, result))
87
+
88
+ result
89
+ end
90
+
91
+ def detail(text)
92
+ telemetry.record(Events::Detailed.new(text))
93
+ end
94
+
95
+ def comment(comment)
96
+ telemetry.record(Events::Commented.new(comment))
97
+ end
98
+
99
+ def context!(...)
100
+ if context(...) == false
101
+ message = Session.abort_message
102
+ raise Abort, message
103
+ end
104
+ end
105
+
106
+ def context(title=nil, &block)
107
+ if block.nil?
108
+ telemetry.record(Events::ContextSkipped.new(title))
109
+ return
110
+ end
111
+
112
+ original_failure_sequence = failure_sequence
113
+
114
+ telemetry.record(Events::ContextStarted.new(title))
115
+
116
+ begin
117
+ block.()
118
+
119
+ rescue Failure
120
+
121
+ ensure
122
+ result = !failed?(original_failure_sequence)
123
+
124
+ telemetry.record(Events::ContextFinished.new(title, result))
125
+ end
126
+
127
+ result
128
+ end
129
+
130
+ def test!(...)
131
+ if test(...) == false
132
+ message = Session.abort_message
133
+ raise Abort, message
134
+ end
135
+ end
136
+
137
+ def test(path, line_number, title=nil, &block)
138
+ if block.nil?
139
+ telemetry.record(Events::TestSkipped.new(title))
140
+ return
141
+ end
142
+
143
+ original_failure_sequence = failure_sequence
144
+ original_assertion_sequence = assertion_sequence
145
+
146
+ telemetry.record(Events::TestStarted.new(title))
147
+
148
+ begin
149
+ block.()
150
+
151
+ result = !failed?(original_failure_sequence)
152
+
153
+ if result
154
+ if not asserted?(original_assertion_sequence)
155
+ failure_message = Session.no_assertion_message
156
+ fail(failure_message, path, line_number)
157
+ end
158
+ end
159
+
160
+ rescue Failure
161
+ result = false
162
+
163
+ ensure
164
+ telemetry.record(Events::TestFinished.new(title, result))
165
+ end
166
+
167
+ result
168
+ end
169
+
170
+ def assert(result, path, line_number)
171
+ failure_message = Session.assertion_failure_message
172
+
173
+ if result != true && result != false
174
+ raise TypeError, "Value #{result.inspect} isn't a boolean"
175
+ end
176
+
177
+ record_assertion
178
+
179
+ if result == false
180
+ fail(failure_message, path, line_number)
181
+ end
182
+ end
183
+
184
+ def fail(message, path, line_number)
185
+ record_failure
186
+
187
+ telemetry.record(Events::Failed.new(message, path, line_number))
188
+
189
+ raise Failure, message
190
+ end
191
+
192
+ def asserted?(compare_sequence=nil)
193
+ compare_sequence ||= 0
194
+
195
+ compare_sequence != assertion_sequence
196
+ end
197
+
198
+ def record_assertion
199
+ self.assertion_sequence += 1
200
+ end
201
+
202
+ def failed?(compare_sequence=nil)
203
+ compare_sequence ||= 0
204
+
205
+ compare_sequence != failure_sequence
206
+ end
207
+
208
+ def record_failure
209
+ self.failure_sequence += 1
210
+ end
211
+
212
+ def skipped?
213
+ skip_sequence != 0
214
+ end
215
+
216
+ def record_skip
217
+ self.skip_sequence += 1
218
+ end
219
+
220
+ def self.assertion_failure_message
221
+ "Assertion failed"
222
+ end
223
+
224
+ def self.no_assertion_message
225
+ "Test didn't perform an assertion"
226
+ end
227
+
228
+ def self.abort_message
229
+ "Abort"
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,93 @@
1
+ module TestBench
2
+ class Session
3
+ module Substitute
4
+ def self.build
5
+ Session.build
6
+ end
7
+
8
+ class Session < Session
9
+ attr_accessor :result
10
+
11
+ def self.build
12
+ instance = new
13
+
14
+ telemetry = instance.telemetry
15
+ Telemetry::CaptureSink.configure(telemetry, attr_name: :sink)
16
+
17
+ telemetry.register(telemetry.sink)
18
+
19
+ instance
20
+ end
21
+
22
+ def file(path)
23
+ telemetry.record(Events::FileStarted.new(path))
24
+
25
+ telemetry.record(Events::FileFinished.new(path, result))
26
+
27
+ result
28
+ end
29
+
30
+ Events.each_type do |event_type|
31
+ event_type_method_cased = TestBench::Telemetry::Event::Type.method_cased(event_type)
32
+
33
+ event_class = Events.const_get(event_type, false)
34
+
35
+ module_eval(<<~RUBY, __FILE__, __LINE__)
36
+ def one_#{event_type_method_cased}_event?(...)
37
+ one_event?(#{event_class}, ...)
38
+ end
39
+
40
+ def one_#{event_type_method_cased}_event(...)
41
+ one_event(#{event_class}, ...)
42
+ end
43
+
44
+ def any_#{event_type_method_cased}_event?(...)
45
+ any_event?(#{event_class}, ...)
46
+ end
47
+ alias :#{event_type_method_cased}_event? :any_#{event_type_method_cased}_event?
48
+
49
+ def #{event_type_method_cased}_events(...)
50
+ events(#{event_class}, ...)
51
+ end
52
+ RUBY
53
+ end
54
+
55
+ def one_event?(...) = telemetry.one_event?(...)
56
+ def one_event(...) = telemetry.one_event(...)
57
+ def any_event?(...) = telemetry.any_event?(...)
58
+ alias :event? :any_event?
59
+ def events(...) = telemetry.events(...)
60
+
61
+ alias :failure? :failed_event?
62
+ alias :one_failure? :one_failed_event?
63
+
64
+ alias :test? :test_finished_event?
65
+ alias :one_test? :one_test_finished_event?
66
+
67
+ alias :context? :context_finished_event?
68
+ alias :one_context? :one_context_finished_event?
69
+
70
+ alias :comment? :commented_event?
71
+ alias :one_comment? :one_commented_event?
72
+
73
+ alias :detail? :detailed_event?
74
+ alias :one_detail? :one_detailed_event?
75
+
76
+ alias :fixture? :fixture_finished_event?
77
+ alias :one_fixture? :one_fixture_finished_event?
78
+
79
+ alias :file? :file_finished_event?
80
+ alias :one_file? :one_file_finished_event?
81
+
82
+ alias :started? :started_event?
83
+ alias :one_started? :one_started_event?
84
+
85
+ alias :finished? :finished_event?
86
+ alias :one_finished? :one_finished_event?
87
+
88
+ alias :aborted? :aborted_event?
89
+ alias :one_aborted? :one_aborted_event?
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,65 @@
1
+ module TestBench
2
+ class Session
3
+ module Telemetry
4
+ class CaptureSink
5
+ class Path
6
+ def segments
7
+ @segments ||= []
8
+ end
9
+ attr_writer :segments
10
+
11
+ def match?(*segments, segment)
12
+ if not segment == self.segments.last
13
+ return false
14
+ end
15
+
16
+ segment_iterator = self.segments.to_enum
17
+
18
+ control_segments = [*segments, segment]
19
+
20
+ control_segments.all? do |control_segment|
21
+ begin
22
+ next_segment = segment_iterator.next
23
+ end until next_segment == control_segment
24
+ true
25
+
26
+ rescue StopIteration
27
+ false
28
+ end
29
+ end
30
+
31
+ def push_segment(segment)
32
+ segments << segment
33
+ end
34
+ alias :push :push_segment
35
+ alias :<< :push
36
+
37
+ def pop_segment(compare_segment=nil)
38
+ segments.pop
39
+ end
40
+ alias :pop :pop_segment
41
+
42
+ def copy(receiver)
43
+ path = self.class.new
44
+
45
+ segments.each do |segment|
46
+ path << segment
47
+ end
48
+
49
+ receiver.path = path
50
+ path
51
+ end
52
+
53
+ def eql?(compare)
54
+ if compare.is_a?(self.class)
55
+ segments == compare.segments
56
+ else
57
+ false
58
+ end
59
+ end
60
+ alias :== :eql?
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,39 @@
1
+ module TestBench
2
+ class Session
3
+ module Telemetry
4
+ class CaptureSink
5
+ Record = Struct.new(:event, :path) do
6
+ def match?(*path_segments, &block)
7
+ if not path_segments?(*path_segments)
8
+ false
9
+ elsif not block?(&block)
10
+ false
11
+ else
12
+ true
13
+ end
14
+ end
15
+
16
+ def path_segments_match?(*segments)
17
+ if segments.empty?
18
+ true
19
+ else
20
+ path.match?(*segments)
21
+ end
22
+ end
23
+ alias :path_segments? :path_segments_match?
24
+
25
+ def block_match?(&block)
26
+ if block.nil?
27
+ true
28
+ elsif block.(event.event_type, *event.values)
29
+ true
30
+ else
31
+ false
32
+ end
33
+ end
34
+ alias :block? :block_match?
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end