spectre-core 1.12.2 → 1.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/spectre +77 -36
- data/lib/spectre/assertion.rb +39 -39
- data/lib/spectre/async.rb +31 -0
- data/lib/spectre/bag.rb +1 -1
- data/lib/spectre/curl.rb +9 -8
- data/lib/spectre/helpers.rb +4 -0
- data/lib/spectre/http/keystone.rb +0 -2
- data/lib/spectre/http.rb +25 -6
- data/lib/spectre/logger/console.rb +9 -3
- data/lib/spectre/logger/file.rb +26 -20
- data/lib/spectre/logger.rb +39 -12
- data/lib/spectre/mixin.rb +3 -3
- data/lib/spectre/reporter/console.rb +20 -23
- data/lib/spectre/reporter/html.rb +1167 -0
- data/lib/spectre/reporter/junit.rb +26 -21
- data/lib/spectre/reporter/vstest.rb +167 -0
- data/lib/spectre.rb +88 -58
- data/resources/OpenSans-Regular.ttf +0 -0
- data/resources/fa-regular-400.ttf +0 -0
- data/resources/fa-solid-900.ttf +0 -0
- data/resources/spectre_icon.svg +106 -0
- data/resources/vue.global.prod.js +1 -0
- metadata +17 -10
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
1
3
|
# https://llg.cubic.org/docs/junit/
|
2
4
|
# Azure mappings: https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/test/publish-test-results?view=azure-devops&tabs=junit%2Cyaml
|
3
5
|
|
@@ -7,38 +9,43 @@ module Spectre::Reporter
|
|
7
9
|
@config = config
|
8
10
|
end
|
9
11
|
|
12
|
+
def get_name run_info
|
13
|
+
run_name = "[#{run_info.spec.name}] #{run_info.spec.subject.desc}"
|
14
|
+
run_name += " - #{run_info.spec.context.__desc} -" unless run_info.spec.context.__desc.nil?
|
15
|
+
run_name += " #{run_info.spec.desc}"
|
16
|
+
run_name
|
17
|
+
end
|
18
|
+
|
10
19
|
def report run_infos
|
11
20
|
now = Time.now.getutc
|
12
21
|
timestamp = now.strftime('%s')
|
13
|
-
datetime = now.strftime('%FT%T
|
22
|
+
datetime = now.strftime('%FT%T.%L')
|
14
23
|
|
15
24
|
xml_str = '<?xml version="1.0" encoding="UTF-8" ?>'
|
16
25
|
xml_str += '<testsuites>'
|
17
26
|
|
18
27
|
suite_id = 0
|
19
28
|
|
20
|
-
run_infos.group_by { |x| x.spec.subject }.each do |subject,
|
21
|
-
failures =
|
22
|
-
errors =
|
23
|
-
skipped =
|
29
|
+
run_infos.group_by { |x| x.spec.subject }.each do |subject, info_group|
|
30
|
+
failures = info_group.select { |x| x.failure != nil }
|
31
|
+
errors = info_group.select { |x| x.error != nil }
|
32
|
+
skipped = info_group.select { |x| x.skipped? }
|
24
33
|
|
25
|
-
xml_str +=
|
34
|
+
xml_str += %{<testsuite package="#{CGI::escapeHTML(subject.desc)}" id="#{CGI::escapeHTML(suite_id.to_s)}" name="#{CGI::escapeHTML(subject.desc)}" timestamp="#{datetime}" tests="#{run_infos.count}" failures="#{failures.count}" errors="#{errors.count}" skipped="#{skipped.count}">}
|
26
35
|
suite_id += 1
|
27
36
|
|
28
|
-
|
29
|
-
|
37
|
+
info_group.each do |run_info|
|
38
|
+
started = run_info.started.strftime('%FT%T.%L')
|
39
|
+
|
40
|
+
xml_str += %{<testcase classname="#{CGI::escapeHTML(run_info.spec.file.to_s)}" name="#{get_name(run_info)}" timestamp="#{started}" time="#{('%.3f' % run_info.duration)}">}
|
30
41
|
|
31
42
|
if run_info.failure and !run_info.failure.cause
|
32
43
|
failure_message = "Expected #{run_info.failure.expectation}"
|
33
44
|
failure_message += " with #{run_info.data}" if run_info.data
|
45
|
+
failure_message += " but it failed"
|
46
|
+
failure_message += " with message: #{run_info.failure.message}" if run_info.failure.message
|
34
47
|
|
35
|
-
|
36
|
-
failure_message += " but it failed with #{run_info.failure.message}"
|
37
|
-
else
|
38
|
-
failure_message += " but it failed"
|
39
|
-
end
|
40
|
-
|
41
|
-
xml_str += '<failure message="' + failure_message.gsub('"', '`') + '"></failure>'
|
48
|
+
xml_str += %{<failure message="#{CGI::escapeHTML(failure_message.gsub('"', '`'))}"></failure>}
|
42
49
|
end
|
43
50
|
|
44
51
|
|
@@ -49,8 +56,8 @@ module Spectre::Reporter
|
|
49
56
|
failure_message = error.message
|
50
57
|
text = error.backtrace.join "\n"
|
51
58
|
|
52
|
-
xml_str +=
|
53
|
-
xml_str +=
|
59
|
+
xml_str += %{<error message="#{CGI::escapeHTML(failure_message.gsub('"', '`'))}" type="#{type}">}
|
60
|
+
xml_str += "<![CDATA[#{text}]]>"
|
54
61
|
xml_str += '</error>'
|
55
62
|
end
|
56
63
|
|
@@ -67,7 +74,7 @@ module Spectre::Reporter
|
|
67
74
|
|
68
75
|
if run_info.data
|
69
76
|
data_str = run_info.data
|
70
|
-
data_str = run_info.data.
|
77
|
+
data_str = run_info.data.to_json unless run_info.data.is_a? String or run_info.data.is_a? Integer
|
71
78
|
xml_str += "data: #{data_str}\n"
|
72
79
|
end
|
73
80
|
|
@@ -92,9 +99,7 @@ module Spectre::Reporter
|
|
92
99
|
|
93
100
|
file_path = File.join(@config['out_path'], "spectre-junit_#{timestamp}.xml")
|
94
101
|
|
95
|
-
File.
|
96
|
-
file.write(xml_str)
|
97
|
-
end
|
102
|
+
File.write(file_path, xml_str)
|
98
103
|
end
|
99
104
|
end
|
100
105
|
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'socket'
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
# Azure mappings: https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/test/publish-test-results?view=azure-devops&tabs=trx%2Cyaml
|
6
|
+
|
7
|
+
module Spectre::Reporter
|
8
|
+
class VSTest
|
9
|
+
def initialize config
|
10
|
+
@config = config
|
11
|
+
@date_format = '%FT%T.%L'
|
12
|
+
end
|
13
|
+
|
14
|
+
def report run_infos
|
15
|
+
now = Time.now.getutc
|
16
|
+
|
17
|
+
xml_str = '<?xml version="1.0" encoding="UTF-8" ?>'
|
18
|
+
xml_str += %{<TestRun xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">}
|
19
|
+
|
20
|
+
started = run_infos[0].started
|
21
|
+
finished = run_infos[-1].finished
|
22
|
+
|
23
|
+
computer_name = Socket.gethostname
|
24
|
+
|
25
|
+
xml_str += %{<Times start="#{started.strftime(@date_format)}" finish="#{finished.strftime(@date_format)}" />}
|
26
|
+
|
27
|
+
|
28
|
+
# Write summary with file attachments
|
29
|
+
xml_str += '<ResultSummary>'
|
30
|
+
xml_str += '<ResultFiles>'
|
31
|
+
xml_str += %{<ResultFile path="#{File.absolute_path(@config['log_file'])}"></ResultFile>} if File.exists? @config['log_file']
|
32
|
+
|
33
|
+
report_files = Dir[File.join(@config['out_path'], '*')]
|
34
|
+
|
35
|
+
if report_files.any?
|
36
|
+
report_files.each do |report_file|
|
37
|
+
xml_str += %{<ResultFile path="#{File.absolute_path(report_file)}"></ResultFile>}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
xml_str += '</ResultFiles>'
|
42
|
+
xml_str += '</ResultSummary>'
|
43
|
+
|
44
|
+
|
45
|
+
# Write test definitions
|
46
|
+
test_definitions = run_infos
|
47
|
+
.sort_by { |x| x.spec.name }
|
48
|
+
.map { |x| [SecureRandom.uuid(), SecureRandom.uuid(), x] }
|
49
|
+
|
50
|
+
xml_str += '<TestDefinitions>'
|
51
|
+
test_definitions.each do |test_id, execution_id, run_info|
|
52
|
+
xml_str += %{<UnitTest name="#{CGI::escapeHTML get_name(run_info)}" storage="#{CGI::escapeHTML(run_info.spec.file.to_s)}" id="#{test_id}">}
|
53
|
+
xml_str += %{<Execution id="#{execution_id}" />}
|
54
|
+
xml_str += '</UnitTest>'
|
55
|
+
end
|
56
|
+
xml_str += '</TestDefinitions>'
|
57
|
+
|
58
|
+
|
59
|
+
# Write test results
|
60
|
+
xml_str += '<Results>'
|
61
|
+
test_definitions.each do |test_id, execution_id, run_info|
|
62
|
+
duration_str = Time.at(run_info.duration).gmtime.strftime('%T.%L')
|
63
|
+
|
64
|
+
if run_info.failed?
|
65
|
+
outcome = 'Failed'
|
66
|
+
elsif run_info.error?
|
67
|
+
outcome = 'Error'
|
68
|
+
elsif run_info.skipped?
|
69
|
+
outcome = 'Skipped'
|
70
|
+
else
|
71
|
+
outcome = 'Passed'
|
72
|
+
end
|
73
|
+
|
74
|
+
xml_str += %{<UnitTestResult executionId="#{execution_id}" testId="#{test_id}" testName="#{CGI::escapeHTML get_name(run_info)}" computerName="#{computer_name}" duration="#{duration_str}" startTime="#{run_info.started.strftime(@date_format)}" endTime="#{run_info.finished.strftime(@date_format)}" outcome="#{outcome}">}
|
75
|
+
|
76
|
+
if run_info.log.any? or run_info.failed? or run_info.error?
|
77
|
+
xml_str += '<Output>'
|
78
|
+
|
79
|
+
# Write log entries
|
80
|
+
xml_str += '<StdOut>'
|
81
|
+
log_str = ''
|
82
|
+
|
83
|
+
if run_info.properties.count > 0
|
84
|
+
run_info.properties.each do |key, val|
|
85
|
+
log_str += "#{key}: #{val}\n"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
if run_info.data
|
90
|
+
data_str = run_info.data
|
91
|
+
data_str = run_info.data.to_json unless run_info.data.is_a? String or run_info.data.is_a? Integer
|
92
|
+
log_str += "data: #{data_str}\n"
|
93
|
+
end
|
94
|
+
|
95
|
+
run_info.log.each do |timestamp, message, level, name|
|
96
|
+
log_str += %{#{timestamp.strftime(@date_format)} #{level.to_s.upcase} -- #{name}: #{CGI::escapeHTML(message.to_s)}\n}
|
97
|
+
end
|
98
|
+
|
99
|
+
xml_str += log_str
|
100
|
+
xml_str += '</StdOut>'
|
101
|
+
|
102
|
+
# Write error information
|
103
|
+
if run_info.failed? or run_info.error?
|
104
|
+
xml_str += '<ErrorInfo>'
|
105
|
+
|
106
|
+
if run_info.failed? and not run_info.failure.cause
|
107
|
+
xml_str += '<Message>'
|
108
|
+
|
109
|
+
failure_message = "Expected #{run_info.failure.expectation}"
|
110
|
+
failure_message += " with #{run_info.data}" if run_info.data
|
111
|
+
failure_message += " but it failed"
|
112
|
+
failure_message += " with message: #{run_info.failure.message}" if run_info.failure.message
|
113
|
+
|
114
|
+
xml_str += CGI::escapeHTML(failure_message)
|
115
|
+
|
116
|
+
xml_str += '</Message>'
|
117
|
+
end
|
118
|
+
|
119
|
+
if run_info.error or (run_info.failed? and run_info.failure.cause)
|
120
|
+
error = run_info.error || run_info.failure.cause
|
121
|
+
|
122
|
+
failure_message = error.message
|
123
|
+
|
124
|
+
xml_str += '<Message>'
|
125
|
+
xml_str += CGI::escapeHTML(failure_message)
|
126
|
+
xml_str += '</Message>'
|
127
|
+
|
128
|
+
stack_trace = error.backtrace.join "\n"
|
129
|
+
|
130
|
+
xml_str += '<StackTrace>'
|
131
|
+
xml_str += CGI::escapeHTML(stack_trace)
|
132
|
+
xml_str += '</StackTrace>'
|
133
|
+
end
|
134
|
+
|
135
|
+
xml_str += '</ErrorInfo>'
|
136
|
+
end
|
137
|
+
|
138
|
+
xml_str += '</Output>'
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
xml_str += '</UnitTestResult>'
|
143
|
+
end
|
144
|
+
xml_str += '</Results>'
|
145
|
+
|
146
|
+
|
147
|
+
# End report
|
148
|
+
xml_str += '</TestRun>'
|
149
|
+
|
150
|
+
|
151
|
+
Dir.mkdir(@config['out_path']) unless Dir.exists? @config['out_path']
|
152
|
+
|
153
|
+
file_path = File.join(@config['out_path'], "spectre-vstest_#{now.strftime('%s')}.trx")
|
154
|
+
|
155
|
+
File.write(file_path, xml_str)
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
def get_name run_info
|
161
|
+
run_name = "[#{run_info.spec.name}] #{run_info.spec.subject.desc}"
|
162
|
+
run_name += " - #{run_info.spec.context.__desc} -" unless run_info.spec.context.__desc.nil?
|
163
|
+
run_name += " #{run_info.spec.desc}"
|
164
|
+
run_name
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
data/lib/spectre.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module Spectre
|
2
2
|
module Version
|
3
3
|
MAJOR = 1
|
4
|
-
MINOR =
|
5
|
-
TINY =
|
4
|
+
MINOR = 13
|
5
|
+
TINY = 0
|
6
6
|
end
|
7
7
|
|
8
8
|
VERSION = [Version::MAJOR, Version::MINOR, Version::TINY].compact * '.'
|
@@ -10,7 +10,7 @@ module Spectre
|
|
10
10
|
|
11
11
|
class ::Hash
|
12
12
|
def deep_merge!(second)
|
13
|
-
merger = proc { |
|
13
|
+
merger = proc { |_key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge!(v2, &merger) : v2 }
|
14
14
|
self.merge!(second, &merger)
|
15
15
|
end
|
16
16
|
|
@@ -34,9 +34,6 @@ module Spectre
|
|
34
34
|
|
35
35
|
|
36
36
|
class SpectreError < Exception
|
37
|
-
def initialize message
|
38
|
-
super message
|
39
|
-
end
|
40
37
|
end
|
41
38
|
|
42
39
|
class ExpectationFailure < Exception
|
@@ -48,6 +45,9 @@ module Spectre
|
|
48
45
|
end
|
49
46
|
end
|
50
47
|
|
48
|
+
class SpectreSkip < Interrupt
|
49
|
+
end
|
50
|
+
|
51
51
|
|
52
52
|
###########################################
|
53
53
|
# Internal Classes
|
@@ -111,7 +111,7 @@ module Spectre
|
|
111
111
|
|
112
112
|
class RunInfo
|
113
113
|
attr_accessor :spec, :data, :started, :finished, :error, :failure, :skipped
|
114
|
-
attr_reader :log, :properties
|
114
|
+
attr_reader :expectations, :log, :properties
|
115
115
|
|
116
116
|
def initialize spec, data=nil
|
117
117
|
@spec = spec
|
@@ -122,6 +122,7 @@ module Spectre
|
|
122
122
|
@failure = nil
|
123
123
|
@skipped = false
|
124
124
|
@log = []
|
125
|
+
@expectations = []
|
125
126
|
@properties = {}
|
126
127
|
end
|
127
128
|
|
@@ -134,12 +135,24 @@ module Spectre
|
|
134
135
|
end
|
135
136
|
|
136
137
|
def failed?
|
138
|
+
@failure != nil
|
139
|
+
end
|
140
|
+
|
141
|
+
def error?
|
137
142
|
@error != nil
|
138
143
|
end
|
144
|
+
|
145
|
+
def status
|
146
|
+
return :error if error?
|
147
|
+
return :failed if failed?
|
148
|
+
return :skipped if skipped?
|
149
|
+
|
150
|
+
return :success
|
151
|
+
end
|
139
152
|
end
|
140
153
|
|
141
154
|
class Runner
|
142
|
-
@@current
|
155
|
+
@@current = nil
|
143
156
|
|
144
157
|
def self.current
|
145
158
|
@@current
|
@@ -148,11 +161,11 @@ module Spectre
|
|
148
161
|
def run specs
|
149
162
|
runs = []
|
150
163
|
|
151
|
-
specs.group_by { |x| x.subject }.each do |subject,
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
runs.concat run_context(context,
|
164
|
+
specs.group_by { |x| x.subject }.each do |subject, subject_specs|
|
165
|
+
Logging.log_subject subject do
|
166
|
+
subject_specs.group_by { |x| x.context }.each do |context, context_specs|
|
167
|
+
Logging.log_context(context) do
|
168
|
+
runs.concat run_context(context, context_specs)
|
156
169
|
end
|
157
170
|
end
|
158
171
|
end
|
@@ -166,8 +179,8 @@ module Spectre
|
|
166
179
|
def run_context context, specs
|
167
180
|
runs = []
|
168
181
|
|
169
|
-
|
170
|
-
setup_run =
|
182
|
+
context.__setup_blocks.each do |setup_spec|
|
183
|
+
setup_run = run_setup(setup_spec)
|
171
184
|
runs << setup_run
|
172
185
|
return runs if setup_run.error or setup_run.failure
|
173
186
|
end
|
@@ -180,47 +193,42 @@ module Spectre
|
|
180
193
|
spec.data
|
181
194
|
.map { |x| x.is_a?(Hash) ? OpenStruct.new(x) : x }
|
182
195
|
.each do |data|
|
183
|
-
|
196
|
+
Logging.log_spec(spec, data) do
|
184
197
|
runs << run_spec(spec, data)
|
185
198
|
end
|
186
199
|
end
|
187
200
|
else
|
188
|
-
|
201
|
+
Logging.log_spec(spec) do
|
189
202
|
runs << run_spec(spec)
|
190
203
|
end
|
191
204
|
end
|
192
205
|
end
|
193
206
|
ensure
|
194
|
-
|
195
|
-
runs <<
|
207
|
+
context.__teardown_blocks.each do |teardown_spec|
|
208
|
+
runs << run_setup(teardown_spec)
|
196
209
|
end
|
197
210
|
end
|
198
211
|
|
199
212
|
runs
|
200
213
|
end
|
201
214
|
|
202
|
-
def
|
203
|
-
|
204
|
-
spec = Spec.new name, context.__subject, name, [], nil, nil, ctx, nil
|
205
|
-
|
206
|
-
run_info = RunInfo.new spec
|
215
|
+
def run_setup spec
|
216
|
+
run_info = RunInfo.new(spec)
|
207
217
|
|
208
218
|
@@current = run_info
|
209
219
|
|
210
220
|
run_info.started = Time.now
|
211
221
|
|
212
|
-
|
222
|
+
Logging.log_context(spec.context) do
|
213
223
|
begin
|
214
|
-
|
215
|
-
block.call
|
216
|
-
end
|
224
|
+
spec.block.call()
|
217
225
|
|
218
226
|
run_info.finished = Time.now
|
219
227
|
rescue ExpectationFailure => e
|
220
228
|
run_info.failure = e
|
221
229
|
rescue Exception => e
|
222
230
|
run_info.error = e
|
223
|
-
|
231
|
+
Logging.log_error(spec, e)
|
224
232
|
end
|
225
233
|
end
|
226
234
|
|
@@ -240,9 +248,9 @@ module Spectre
|
|
240
248
|
|
241
249
|
begin
|
242
250
|
if spec.context.__before_blocks.count > 0
|
243
|
-
before_ctx = SpecContext.new(spec.subject, 'before')
|
251
|
+
before_ctx = SpecContext.new(spec.subject, 'before', spec.context)
|
244
252
|
|
245
|
-
|
253
|
+
Logging.log_context before_ctx do
|
246
254
|
spec.context.__before_blocks.each do |block|
|
247
255
|
block.call(data)
|
248
256
|
end
|
@@ -252,17 +260,20 @@ module Spectre
|
|
252
260
|
spec.block.call(data)
|
253
261
|
rescue ExpectationFailure => e
|
254
262
|
run_info.failure = e
|
263
|
+
rescue SpectreSkip => e
|
264
|
+
run_info.skipped = true
|
265
|
+
Logging.log_skipped(spec, e.message)
|
255
266
|
rescue Interrupt
|
256
267
|
run_info.skipped = true
|
257
|
-
|
268
|
+
Logging.log_skipped(spec, 'canceled by user')
|
258
269
|
rescue Exception => e
|
259
270
|
run_info.error = e
|
260
|
-
|
271
|
+
Logging.log_error(spec, e)
|
261
272
|
ensure
|
262
273
|
if spec.context.__after_blocks.count > 0
|
263
|
-
after_ctx = SpecContext.new(spec.subject, 'after')
|
274
|
+
after_ctx = SpecContext.new(spec.subject, 'after', spec.context)
|
264
275
|
|
265
|
-
|
276
|
+
Logging.log_context after_ctx do
|
266
277
|
begin
|
267
278
|
spec.context.__after_blocks.each do |block|
|
268
279
|
block.call
|
@@ -273,7 +284,7 @@ module Spectre
|
|
273
284
|
run_info.failure = e
|
274
285
|
rescue Exception => e
|
275
286
|
run_info.error = e
|
276
|
-
|
287
|
+
Logging.log_error(spec, e)
|
277
288
|
end
|
278
289
|
end
|
279
290
|
end
|
@@ -294,11 +305,12 @@ module Spectre
|
|
294
305
|
|
295
306
|
|
296
307
|
class SpecContext < DslClass
|
297
|
-
attr_reader :__subject, :__desc, :__before_blocks, :__after_blocks, :__setup_blocks, :__teardown_blocks
|
308
|
+
attr_reader :__subject, :__desc, :__parent, :__before_blocks, :__after_blocks, :__setup_blocks, :__teardown_blocks
|
298
309
|
|
299
|
-
def initialize subject, desc=nil
|
310
|
+
def initialize subject, desc=nil, parent=nil
|
300
311
|
@__subject = subject
|
301
312
|
@__desc = desc
|
313
|
+
@__parent = parent
|
302
314
|
|
303
315
|
@__before_blocks = []
|
304
316
|
@__after_blocks = []
|
@@ -307,20 +319,7 @@ module Spectre
|
|
307
319
|
end
|
308
320
|
|
309
321
|
def it desc, tags: [], with: [], &block
|
310
|
-
|
311
|
-
# Nasty, but it works
|
312
|
-
# Maybe there is another way, but this works for now
|
313
|
-
spec_file = nil
|
314
|
-
begin
|
315
|
-
raise
|
316
|
-
rescue => e
|
317
|
-
spec_file = e.backtrace
|
318
|
-
.select { |file| !file.include? 'lib/spectre' }
|
319
|
-
.first
|
320
|
-
.match(/(.*\.rb):\d+/)
|
321
|
-
.captures
|
322
|
-
.first
|
323
|
-
end
|
322
|
+
spec_file = get_file()
|
324
323
|
|
325
324
|
@__subject.add_spec(desc, tags, with, block, self, spec_file)
|
326
325
|
end
|
@@ -334,17 +333,44 @@ module Spectre
|
|
334
333
|
end
|
335
334
|
|
336
335
|
def setup &block
|
337
|
-
|
336
|
+
name = "#{@__subject.name}-setup"
|
337
|
+
spec_file = get_file()
|
338
|
+
|
339
|
+
setup_ctx = SpecContext.new(@__subject, 'setup', self)
|
340
|
+
@__setup_blocks << Spec.new(name, @__subject, 'setup', [], nil, block, setup_ctx, spec_file)
|
338
341
|
end
|
339
342
|
|
340
343
|
def teardown &block
|
341
|
-
|
344
|
+
name = "#{@__subject.name}-teardown"
|
345
|
+
spec_file = get_file()
|
346
|
+
|
347
|
+
teardown_ctx = SpecContext.new(@__subject, 'teardown', self)
|
348
|
+
@__teardown_blocks << Spec.new(name, @__subject, 'teardown', [], nil, block, teardown_ctx, spec_file)
|
342
349
|
end
|
343
350
|
|
344
351
|
def context desc=nil, &block
|
345
|
-
ctx = SpecContext.new(@__subject, desc)
|
352
|
+
ctx = SpecContext.new(@__subject, desc, self)
|
346
353
|
ctx._evaluate &block
|
347
354
|
end
|
355
|
+
|
356
|
+
private
|
357
|
+
|
358
|
+
def get_file
|
359
|
+
# Get the file, where the spec is defined.
|
360
|
+
# Nasty, but it works
|
361
|
+
# Maybe there is another way, but this works for now
|
362
|
+
|
363
|
+
begin
|
364
|
+
raise
|
365
|
+
rescue => e
|
366
|
+
return e.backtrace
|
367
|
+
.select { |file| !file.include? 'lib/spectre' }
|
368
|
+
.first
|
369
|
+
.match(/(.*\.rb):\d+/)
|
370
|
+
.captures
|
371
|
+
.first
|
372
|
+
end
|
373
|
+
end
|
348
374
|
end
|
349
375
|
|
350
376
|
|
@@ -397,14 +423,14 @@ module Spectre
|
|
397
423
|
|
398
424
|
def tag? tags, tag_exp
|
399
425
|
tags = tags.map { |x| x.to_s }
|
400
|
-
all_tags = tag_exp.split
|
426
|
+
all_tags = tag_exp.split('+')
|
401
427
|
included_tags = all_tags.select { |x| !x.start_with? '!' }
|
402
428
|
excluded_tags = all_tags.select { |x| x.start_with? '!' }.map { |x| x[1..-1] }
|
403
429
|
included_tags & tags == included_tags and excluded_tags & tags == []
|
404
430
|
end
|
405
431
|
|
406
432
|
def delegate *method_names, to: nil
|
407
|
-
Spectre::Delegator.delegate
|
433
|
+
Spectre::Delegator.delegate(*method_names, to)
|
408
434
|
end
|
409
435
|
|
410
436
|
def register &block
|
@@ -438,9 +464,13 @@ module Spectre
|
|
438
464
|
def property key, val
|
439
465
|
Spectre::Runner.current.properties[key] = val
|
440
466
|
end
|
467
|
+
|
468
|
+
def skip message=nil
|
469
|
+
raise SpectreSkip.new(message)
|
470
|
+
end
|
441
471
|
end
|
442
472
|
|
443
|
-
delegate :describe, :property, to: Spectre
|
473
|
+
delegate :describe, :property, :skip, to: Spectre
|
444
474
|
end
|
445
475
|
|
446
476
|
|
Binary file
|
Binary file
|
Binary file
|