test_bench-fixture 1.0.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.
- checksums.yaml +7 -0
- data/lib/test_bench/fixture.rb +18 -0
- data/lib/test_bench/fixture/assertion_failure.rb +19 -0
- data/lib/test_bench/fixture/controls.rb +10 -0
- data/lib/test_bench/fixture/controls/caller_location.rb +72 -0
- data/lib/test_bench/fixture/controls/error.rb +47 -0
- data/lib/test_bench/fixture/controls/error/backtrace.rb +31 -0
- data/lib/test_bench/fixture/controls/fixture.rb +85 -0
- data/lib/test_bench/fixture/controls/output.rb +64 -0
- data/lib/test_bench/fixture/controls/result.rb +23 -0
- data/lib/test_bench/fixture/controls/test_file.rb +72 -0
- data/lib/test_bench/fixture/error_policy.rb +75 -0
- data/lib/test_bench/fixture/fixture.rb +149 -0
- data/lib/test_bench/fixture/output.rb +56 -0
- data/lib/test_bench/fixture/output/log.rb +109 -0
- data/lib/test_bench/fixture/output/multiple.rb +42 -0
- data/lib/test_bench/fixture/output/null.rb +9 -0
- data/lib/test_bench/fixture/output/substitute.rb +141 -0
- data/lib/test_bench/fixture/session.rb +246 -0
- data/lib/test_bench/fixture/session/substitute.rb +126 -0
- data/lib/test_bench/fixture/session/substitute/match_tests.rb +131 -0
- metadata +76 -0
@@ -0,0 +1,246 @@
|
|
1
|
+
module TestBench
|
2
|
+
module Fixture
|
3
|
+
class Session
|
4
|
+
Error = Class.new(RuntimeError)
|
5
|
+
|
6
|
+
def assertion_counter
|
7
|
+
@assertion_counter ||= 0
|
8
|
+
end
|
9
|
+
attr_writer :assertion_counter
|
10
|
+
|
11
|
+
def error_counter
|
12
|
+
@error_counter ||= 0
|
13
|
+
end
|
14
|
+
attr_writer :error_counter
|
15
|
+
|
16
|
+
def started
|
17
|
+
instance_variable_defined?(:@started) ?
|
18
|
+
@started :
|
19
|
+
@started = false
|
20
|
+
end
|
21
|
+
attr_writer :started
|
22
|
+
alias_method :started?, :started
|
23
|
+
|
24
|
+
def finished
|
25
|
+
instance_variable_defined?(:@finished) ?
|
26
|
+
@finished :
|
27
|
+
@finished = false
|
28
|
+
end
|
29
|
+
attr_writer :finished
|
30
|
+
alias_method :finished?, :finished
|
31
|
+
|
32
|
+
def error_policy
|
33
|
+
@error_policy ||= ErrorPolicy::Build.(:rescue_assert)
|
34
|
+
end
|
35
|
+
attr_writer :error_policy
|
36
|
+
|
37
|
+
def output
|
38
|
+
@output ||= Output::Substitute.build
|
39
|
+
end
|
40
|
+
attr_writer :output
|
41
|
+
|
42
|
+
def self.build(output: nil, error_policy: nil)
|
43
|
+
instance = new
|
44
|
+
|
45
|
+
if output.nil?
|
46
|
+
Output::Log.configure(instance)
|
47
|
+
else
|
48
|
+
instance.output = output
|
49
|
+
end
|
50
|
+
|
51
|
+
ErrorPolicy.configure(instance, policy: error_policy)
|
52
|
+
|
53
|
+
instance
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.configure(receiver, session: nil, output: nil, error_policy: nil, attr_name: nil)
|
57
|
+
attr_name ||= :session
|
58
|
+
|
59
|
+
if session.nil?
|
60
|
+
instance = build(output: output, error_policy: error_policy)
|
61
|
+
else
|
62
|
+
instance = session
|
63
|
+
end
|
64
|
+
|
65
|
+
receiver.public_send(:"#{attr_name}=", instance)
|
66
|
+
|
67
|
+
instance
|
68
|
+
end
|
69
|
+
|
70
|
+
def start
|
71
|
+
if started
|
72
|
+
raise Error, "Session has already been started"
|
73
|
+
end
|
74
|
+
|
75
|
+
self.started = true
|
76
|
+
|
77
|
+
output.start
|
78
|
+
end
|
79
|
+
|
80
|
+
def finish
|
81
|
+
if finished
|
82
|
+
raise Error, "Session has already finished"
|
83
|
+
end
|
84
|
+
|
85
|
+
self.finished = true
|
86
|
+
|
87
|
+
result = !failed?
|
88
|
+
|
89
|
+
output.finish(result)
|
90
|
+
|
91
|
+
result
|
92
|
+
end
|
93
|
+
|
94
|
+
def comment(text)
|
95
|
+
output.comment(text)
|
96
|
+
end
|
97
|
+
|
98
|
+
def error(error)
|
99
|
+
fail!
|
100
|
+
|
101
|
+
output.error(error)
|
102
|
+
|
103
|
+
error_policy.(error)
|
104
|
+
end
|
105
|
+
|
106
|
+
def assert(value, caller_location: nil)
|
107
|
+
caller_location ||= caller_locations.first
|
108
|
+
|
109
|
+
result = value ? true : false
|
110
|
+
|
111
|
+
self.assertion_counter += 1
|
112
|
+
|
113
|
+
output.assert(result, caller_location)
|
114
|
+
|
115
|
+
unless result
|
116
|
+
self.error_counter += 1
|
117
|
+
|
118
|
+
assertion_failure = AssertionFailure.build(caller_location)
|
119
|
+
raise assertion_failure
|
120
|
+
end
|
121
|
+
|
122
|
+
result
|
123
|
+
end
|
124
|
+
|
125
|
+
def assert_block(caller_location: nil, &block)
|
126
|
+
caller_location ||= caller_locations.first
|
127
|
+
|
128
|
+
previous_error_counter = self.error_counter
|
129
|
+
previous_assertion_counter = self.assertion_counter
|
130
|
+
|
131
|
+
output.enter_assert_block(caller_location)
|
132
|
+
|
133
|
+
begin
|
134
|
+
block.()
|
135
|
+
|
136
|
+
ensure
|
137
|
+
if self.error_counter > previous_error_counter
|
138
|
+
result = false
|
139
|
+
elsif self.assertion_counter == previous_assertion_counter
|
140
|
+
result = false
|
141
|
+
else
|
142
|
+
result = true
|
143
|
+
end
|
144
|
+
|
145
|
+
output.exit_assert_block(caller_location, result)
|
146
|
+
|
147
|
+
current_exception = $!
|
148
|
+
if current_exception.nil? || current_exception.instance_of?(AssertionFailure)
|
149
|
+
assert(result, caller_location: caller_location)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def load(path)
|
155
|
+
output.enter_file(path)
|
156
|
+
|
157
|
+
action = proc { Kernel.load(path) }
|
158
|
+
|
159
|
+
result = evaluate(action)
|
160
|
+
|
161
|
+
output.exit_file(path, result)
|
162
|
+
|
163
|
+
result
|
164
|
+
end
|
165
|
+
|
166
|
+
def test(title=nil, &block)
|
167
|
+
if block.nil?
|
168
|
+
output.skip_test(title)
|
169
|
+
return
|
170
|
+
end
|
171
|
+
|
172
|
+
output.start_test(title)
|
173
|
+
|
174
|
+
evaluate(block) do |result|
|
175
|
+
output.finish_test(title, result)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def context(title=nil, &block)
|
180
|
+
if block.nil?
|
181
|
+
output.skip_context(title)
|
182
|
+
return
|
183
|
+
end
|
184
|
+
|
185
|
+
output.enter_context(title)
|
186
|
+
|
187
|
+
evaluate(block) do |result|
|
188
|
+
output.exit_context(title, result)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def fixture(fixture, &block)
|
193
|
+
if block.nil? && !fixture.respond_to?(:call)
|
194
|
+
raise Error, "Block must be given when a fixture does not respond to #call"
|
195
|
+
end
|
196
|
+
|
197
|
+
actions = []
|
198
|
+
|
199
|
+
if fixture.respond_to?(:call)
|
200
|
+
actions << fixture
|
201
|
+
end
|
202
|
+
|
203
|
+
unless block.nil?
|
204
|
+
actions << proc { block.(fixture) }
|
205
|
+
end
|
206
|
+
|
207
|
+
output.start_fixture(fixture)
|
208
|
+
|
209
|
+
action = proc { actions.each(&:call) }
|
210
|
+
result = evaluate(action)
|
211
|
+
|
212
|
+
output.finish_fixture(fixture, result)
|
213
|
+
|
214
|
+
result
|
215
|
+
end
|
216
|
+
|
217
|
+
def evaluate(action, &block)
|
218
|
+
previous_error_counter = self.error_counter
|
219
|
+
|
220
|
+
begin
|
221
|
+
action.()
|
222
|
+
|
223
|
+
rescue => error
|
224
|
+
error(error)
|
225
|
+
|
226
|
+
ensure
|
227
|
+
current_exception = $!
|
228
|
+
|
229
|
+
result = error_counter == previous_error_counter
|
230
|
+
|
231
|
+
block.(result, current_exception) unless block.nil?
|
232
|
+
end
|
233
|
+
|
234
|
+
result
|
235
|
+
end
|
236
|
+
|
237
|
+
def fail!
|
238
|
+
self.error_counter += 1
|
239
|
+
end
|
240
|
+
|
241
|
+
def failed?
|
242
|
+
error_counter.nonzero? ? true : false
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module TestBench
|
2
|
+
module Fixture
|
3
|
+
class Session
|
4
|
+
module Substitute
|
5
|
+
def self.build
|
6
|
+
Session.new
|
7
|
+
end
|
8
|
+
|
9
|
+
class Session < Session
|
10
|
+
Error = Class.new(RuntimeError)
|
11
|
+
|
12
|
+
attr_accessor :load_failure
|
13
|
+
|
14
|
+
def commented?(text)
|
15
|
+
output.recorded?(:comment) do |t|
|
16
|
+
t == text
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def asserted?(result=nil, caller_location: nil)
|
21
|
+
output.recorded?(:assert) do |r, cl|
|
22
|
+
(result.nil? || r == result) &&
|
23
|
+
(caller_location.nil? || cl == caller_location)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def load_failure!
|
28
|
+
self.load_failure = true
|
29
|
+
end
|
30
|
+
|
31
|
+
def load(path)
|
32
|
+
result = load_failure ? false : true
|
33
|
+
|
34
|
+
output.enter_file(path)
|
35
|
+
|
36
|
+
output.exit_file(path, result)
|
37
|
+
|
38
|
+
result
|
39
|
+
end
|
40
|
+
|
41
|
+
def loaded?(path)
|
42
|
+
output.recorded?(:exit_file) do |p|
|
43
|
+
p == path
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test?(title)
|
48
|
+
output.recorded?(:finish_test) do |t|
|
49
|
+
t == title
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def context?(title)
|
54
|
+
output.recorded?(:exit_context) do |t|
|
55
|
+
t == title
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def fixture?(fixture)
|
60
|
+
output.recorded?(:finish_fixture) do |f|
|
61
|
+
f == fixture
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def passed?(*titles)
|
66
|
+
!pass(*titles).nil?
|
67
|
+
end
|
68
|
+
|
69
|
+
def failed?(*titles)
|
70
|
+
return super if titles.empty?
|
71
|
+
|
72
|
+
!failure(*titles).nil?
|
73
|
+
end
|
74
|
+
|
75
|
+
def one_pass(*titles)
|
76
|
+
passes = passes(*titles)
|
77
|
+
|
78
|
+
if passes.count > 1
|
79
|
+
raise Error, "Multiple passing tests match (Titles: #{titles.inspect})"
|
80
|
+
end
|
81
|
+
|
82
|
+
passes.first
|
83
|
+
end
|
84
|
+
|
85
|
+
def one_passed?(*titles)
|
86
|
+
one_pass(*titles) ? true : false
|
87
|
+
end
|
88
|
+
|
89
|
+
def pass(*titles)
|
90
|
+
passes(*titles).first
|
91
|
+
end
|
92
|
+
|
93
|
+
def passes(*titles)
|
94
|
+
match_tests(*titles, result: true)
|
95
|
+
end
|
96
|
+
|
97
|
+
def one_failure(*titles)
|
98
|
+
failures = failures(*titles)
|
99
|
+
|
100
|
+
if failures.count > 1
|
101
|
+
raise Error, "Multiple failing tests match (Titles: #{titles.inspect})"
|
102
|
+
end
|
103
|
+
|
104
|
+
failures.first
|
105
|
+
end
|
106
|
+
|
107
|
+
def one_failed?(*titles)
|
108
|
+
one_failure(*titles) ? true : false
|
109
|
+
end
|
110
|
+
|
111
|
+
def failure(*titles)
|
112
|
+
failures(*titles).first
|
113
|
+
end
|
114
|
+
|
115
|
+
def failures(*titles)
|
116
|
+
match_tests(*titles, result: false)
|
117
|
+
end
|
118
|
+
|
119
|
+
def match_tests(*titles, result: nil)
|
120
|
+
MatchTests.(self, *titles, result: result)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module TestBench
|
2
|
+
module Fixture
|
3
|
+
class Session
|
4
|
+
module Substitute
|
5
|
+
class MatchTests
|
6
|
+
include Output
|
7
|
+
|
8
|
+
attr_reader :output_substitute
|
9
|
+
attr_reader :patterns
|
10
|
+
attr_reader :result
|
11
|
+
|
12
|
+
def matches
|
13
|
+
@matches ||= []
|
14
|
+
end
|
15
|
+
|
16
|
+
def stack
|
17
|
+
@stack ||= []
|
18
|
+
end
|
19
|
+
|
20
|
+
def pattern_index
|
21
|
+
@pattern_index ||= 0
|
22
|
+
end
|
23
|
+
attr_writer :pattern_index
|
24
|
+
|
25
|
+
def initialize(output_substitute, result, *patterns)
|
26
|
+
@output_substitute = output_substitute
|
27
|
+
@result = result
|
28
|
+
@patterns = patterns
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.build(run, *patterns, result: nil)
|
32
|
+
output_substitute = run.output
|
33
|
+
|
34
|
+
patterns.map! do |pattern|
|
35
|
+
if pattern.is_a?(String)
|
36
|
+
Regexp.new("\\A#{Regexp.escape(pattern)}\\z")
|
37
|
+
else
|
38
|
+
pattern
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
new(output_substitute, result, *patterns)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.call(run, *patterns, result: nil)
|
46
|
+
instance = build(run, *patterns, result: result)
|
47
|
+
instance.()
|
48
|
+
end
|
49
|
+
|
50
|
+
def call
|
51
|
+
output_substitute.replay_records(self)
|
52
|
+
|
53
|
+
matches
|
54
|
+
end
|
55
|
+
|
56
|
+
def enter_context(title)
|
57
|
+
push(title)
|
58
|
+
end
|
59
|
+
|
60
|
+
def exit_context(_, _)
|
61
|
+
pop
|
62
|
+
end
|
63
|
+
|
64
|
+
def finish_test(title, result)
|
65
|
+
push(title)
|
66
|
+
|
67
|
+
if match?(result)
|
68
|
+
text = stack.join("\t")
|
69
|
+
|
70
|
+
matches << text
|
71
|
+
end
|
72
|
+
|
73
|
+
pop unless title.nil?
|
74
|
+
end
|
75
|
+
|
76
|
+
def skip_test(title)
|
77
|
+
push(title)
|
78
|
+
|
79
|
+
pop
|
80
|
+
end
|
81
|
+
|
82
|
+
def push(title)
|
83
|
+
return if title.nil?
|
84
|
+
|
85
|
+
if next_pattern.match?(title)
|
86
|
+
self.pattern_index += 1
|
87
|
+
end
|
88
|
+
|
89
|
+
stack.push(title)
|
90
|
+
end
|
91
|
+
|
92
|
+
def pop
|
93
|
+
title = stack.pop
|
94
|
+
|
95
|
+
if previous_pattern.match?(title)
|
96
|
+
self.pattern_index -= 1
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def match?(result)
|
101
|
+
return false unless pattern_index == patterns.count
|
102
|
+
|
103
|
+
if self.result.nil?
|
104
|
+
true
|
105
|
+
else
|
106
|
+
result == self.result
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def next_pattern
|
111
|
+
return Pattern.none if pattern_index == patterns.count
|
112
|
+
|
113
|
+
patterns.fetch(pattern_index)
|
114
|
+
end
|
115
|
+
|
116
|
+
def previous_pattern
|
117
|
+
return Pattern.none if pattern_index.zero?
|
118
|
+
|
119
|
+
patterns[pattern_index - 1]
|
120
|
+
end
|
121
|
+
|
122
|
+
module Pattern
|
123
|
+
def self.none
|
124
|
+
%r{\z\A}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|