spectre-core 1.12.4 → 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 +31 -24
- data/lib/spectre/assertion.rb +38 -38
- data/lib/spectre/async.rb +31 -0
- data/lib/spectre/bag.rb +1 -1
- data/lib/spectre/curl.rb +4 -6
- 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 +1 -1
- data/lib/spectre/logger/file.rb +19 -19
- data/lib/spectre/logger.rb +37 -10
- data/lib/spectre/mixin.rb +3 -3
- data/lib/spectre/reporter/console.rb +19 -22
- data/lib/spectre/reporter/html.rb +1167 -0
- data/lib/spectre/reporter/junit.rb +24 -21
- data/lib/spectre/reporter/vstest.rb +167 -0
- data/lib/spectre.rb +78 -61
- 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 +13 -6
@@ -9,38 +9,43 @@ module Spectre::Reporter
|
|
9
9
|
@config = config
|
10
10
|
end
|
11
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
|
+
|
12
19
|
def report run_infos
|
13
20
|
now = Time.now.getutc
|
14
21
|
timestamp = now.strftime('%s')
|
15
|
-
datetime = now.strftime('%FT%T
|
22
|
+
datetime = now.strftime('%FT%T.%L')
|
16
23
|
|
17
24
|
xml_str = '<?xml version="1.0" encoding="UTF-8" ?>'
|
18
25
|
xml_str += '<testsuites>'
|
19
26
|
|
20
27
|
suite_id = 0
|
21
28
|
|
22
|
-
run_infos.group_by { |x| x.spec.subject }.each do |subject,
|
23
|
-
failures =
|
24
|
-
errors =
|
25
|
-
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? }
|
26
33
|
|
27
|
-
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}">}
|
28
35
|
suite_id += 1
|
29
36
|
|
30
|
-
|
31
|
-
|
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)}">}
|
32
41
|
|
33
42
|
if run_info.failure and !run_info.failure.cause
|
34
43
|
failure_message = "Expected #{run_info.failure.expectation}"
|
35
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
|
36
47
|
|
37
|
-
|
38
|
-
failure_message += " but it failed with #{run_info.failure.message}"
|
39
|
-
else
|
40
|
-
failure_message += " but it failed"
|
41
|
-
end
|
42
|
-
|
43
|
-
xml_str += '<failure message="' + CGI::escapeHTML(failure_message.gsub('"', '`')) + '"></failure>'
|
48
|
+
xml_str += %{<failure message="#{CGI::escapeHTML(failure_message.gsub('"', '`'))}"></failure>}
|
44
49
|
end
|
45
50
|
|
46
51
|
|
@@ -51,8 +56,8 @@ module Spectre::Reporter
|
|
51
56
|
failure_message = error.message
|
52
57
|
text = error.backtrace.join "\n"
|
53
58
|
|
54
|
-
xml_str +=
|
55
|
-
xml_str +=
|
59
|
+
xml_str += %{<error message="#{CGI::escapeHTML(failure_message.gsub('"', '`'))}" type="#{type}">}
|
60
|
+
xml_str += "<![CDATA[#{text}]]>"
|
56
61
|
xml_str += '</error>'
|
57
62
|
end
|
58
63
|
|
@@ -69,7 +74,7 @@ module Spectre::Reporter
|
|
69
74
|
|
70
75
|
if run_info.data
|
71
76
|
data_str = run_info.data
|
72
|
-
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
|
73
78
|
xml_str += "data: #{data_str}\n"
|
74
79
|
end
|
75
80
|
|
@@ -94,9 +99,7 @@ module Spectre::Reporter
|
|
94
99
|
|
95
100
|
file_path = File.join(@config['out_path'], "spectre-junit_#{timestamp}.xml")
|
96
101
|
|
97
|
-
File.
|
98
|
-
file.write(xml_str)
|
99
|
-
end
|
102
|
+
File.write(file_path, xml_str)
|
100
103
|
end
|
101
104
|
end
|
102
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
|
@@ -49,9 +46,6 @@ module Spectre
|
|
49
46
|
end
|
50
47
|
|
51
48
|
class SpectreSkip < Interrupt
|
52
|
-
def initialize message
|
53
|
-
super message
|
54
|
-
end
|
55
49
|
end
|
56
50
|
|
57
51
|
|
@@ -117,7 +111,7 @@ module Spectre
|
|
117
111
|
|
118
112
|
class RunInfo
|
119
113
|
attr_accessor :spec, :data, :started, :finished, :error, :failure, :skipped
|
120
|
-
attr_reader :log, :properties
|
114
|
+
attr_reader :expectations, :log, :properties
|
121
115
|
|
122
116
|
def initialize spec, data=nil
|
123
117
|
@spec = spec
|
@@ -128,6 +122,7 @@ module Spectre
|
|
128
122
|
@failure = nil
|
129
123
|
@skipped = false
|
130
124
|
@log = []
|
125
|
+
@expectations = []
|
131
126
|
@properties = {}
|
132
127
|
end
|
133
128
|
|
@@ -140,12 +135,24 @@ module Spectre
|
|
140
135
|
end
|
141
136
|
|
142
137
|
def failed?
|
138
|
+
@failure != nil
|
139
|
+
end
|
140
|
+
|
141
|
+
def error?
|
143
142
|
@error != nil
|
144
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
|
145
152
|
end
|
146
153
|
|
147
154
|
class Runner
|
148
|
-
@@current
|
155
|
+
@@current = nil
|
149
156
|
|
150
157
|
def self.current
|
151
158
|
@@current
|
@@ -154,11 +161,11 @@ module Spectre
|
|
154
161
|
def run specs
|
155
162
|
runs = []
|
156
163
|
|
157
|
-
specs.group_by { |x| x.subject }.each do |subject,
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
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)
|
162
169
|
end
|
163
170
|
end
|
164
171
|
end
|
@@ -172,8 +179,8 @@ module Spectre
|
|
172
179
|
def run_context context, specs
|
173
180
|
runs = []
|
174
181
|
|
175
|
-
|
176
|
-
setup_run =
|
182
|
+
context.__setup_blocks.each do |setup_spec|
|
183
|
+
setup_run = run_setup(setup_spec)
|
177
184
|
runs << setup_run
|
178
185
|
return runs if setup_run.error or setup_run.failure
|
179
186
|
end
|
@@ -186,47 +193,42 @@ module Spectre
|
|
186
193
|
spec.data
|
187
194
|
.map { |x| x.is_a?(Hash) ? OpenStruct.new(x) : x }
|
188
195
|
.each do |data|
|
189
|
-
|
196
|
+
Logging.log_spec(spec, data) do
|
190
197
|
runs << run_spec(spec, data)
|
191
198
|
end
|
192
199
|
end
|
193
200
|
else
|
194
|
-
|
201
|
+
Logging.log_spec(spec) do
|
195
202
|
runs << run_spec(spec)
|
196
203
|
end
|
197
204
|
end
|
198
205
|
end
|
199
206
|
ensure
|
200
|
-
|
201
|
-
runs <<
|
207
|
+
context.__teardown_blocks.each do |teardown_spec|
|
208
|
+
runs << run_setup(teardown_spec)
|
202
209
|
end
|
203
210
|
end
|
204
211
|
|
205
212
|
runs
|
206
213
|
end
|
207
214
|
|
208
|
-
def
|
209
|
-
|
210
|
-
spec = Spec.new name, context.__subject, name, [], nil, nil, ctx, nil
|
211
|
-
|
212
|
-
run_info = RunInfo.new spec
|
215
|
+
def run_setup spec
|
216
|
+
run_info = RunInfo.new(spec)
|
213
217
|
|
214
218
|
@@current = run_info
|
215
219
|
|
216
220
|
run_info.started = Time.now
|
217
221
|
|
218
|
-
|
222
|
+
Logging.log_context(spec.context) do
|
219
223
|
begin
|
220
|
-
|
221
|
-
block.call
|
222
|
-
end
|
224
|
+
spec.block.call()
|
223
225
|
|
224
226
|
run_info.finished = Time.now
|
225
227
|
rescue ExpectationFailure => e
|
226
228
|
run_info.failure = e
|
227
229
|
rescue Exception => e
|
228
230
|
run_info.error = e
|
229
|
-
|
231
|
+
Logging.log_error(spec, e)
|
230
232
|
end
|
231
233
|
end
|
232
234
|
|
@@ -246,9 +248,9 @@ module Spectre
|
|
246
248
|
|
247
249
|
begin
|
248
250
|
if spec.context.__before_blocks.count > 0
|
249
|
-
before_ctx = SpecContext.new(spec.subject, 'before')
|
251
|
+
before_ctx = SpecContext.new(spec.subject, 'before', spec.context)
|
250
252
|
|
251
|
-
|
253
|
+
Logging.log_context before_ctx do
|
252
254
|
spec.context.__before_blocks.each do |block|
|
253
255
|
block.call(data)
|
254
256
|
end
|
@@ -260,18 +262,18 @@ module Spectre
|
|
260
262
|
run_info.failure = e
|
261
263
|
rescue SpectreSkip => e
|
262
264
|
run_info.skipped = true
|
263
|
-
|
265
|
+
Logging.log_skipped(spec, e.message)
|
264
266
|
rescue Interrupt
|
265
267
|
run_info.skipped = true
|
266
|
-
|
268
|
+
Logging.log_skipped(spec, 'canceled by user')
|
267
269
|
rescue Exception => e
|
268
270
|
run_info.error = e
|
269
|
-
|
271
|
+
Logging.log_error(spec, e)
|
270
272
|
ensure
|
271
273
|
if spec.context.__after_blocks.count > 0
|
272
|
-
after_ctx = SpecContext.new(spec.subject, 'after')
|
274
|
+
after_ctx = SpecContext.new(spec.subject, 'after', spec.context)
|
273
275
|
|
274
|
-
|
276
|
+
Logging.log_context after_ctx do
|
275
277
|
begin
|
276
278
|
spec.context.__after_blocks.each do |block|
|
277
279
|
block.call
|
@@ -282,7 +284,7 @@ module Spectre
|
|
282
284
|
run_info.failure = e
|
283
285
|
rescue Exception => e
|
284
286
|
run_info.error = e
|
285
|
-
|
287
|
+
Logging.log_error(spec, e)
|
286
288
|
end
|
287
289
|
end
|
288
290
|
end
|
@@ -303,11 +305,12 @@ module Spectre
|
|
303
305
|
|
304
306
|
|
305
307
|
class SpecContext < DslClass
|
306
|
-
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
|
307
309
|
|
308
|
-
def initialize subject, desc=nil
|
310
|
+
def initialize subject, desc=nil, parent=nil
|
309
311
|
@__subject = subject
|
310
312
|
@__desc = desc
|
313
|
+
@__parent = parent
|
311
314
|
|
312
315
|
@__before_blocks = []
|
313
316
|
@__after_blocks = []
|
@@ -316,20 +319,7 @@ module Spectre
|
|
316
319
|
end
|
317
320
|
|
318
321
|
def it desc, tags: [], with: [], &block
|
319
|
-
|
320
|
-
# Nasty, but it works
|
321
|
-
# Maybe there is another way, but this works for now
|
322
|
-
spec_file = nil
|
323
|
-
begin
|
324
|
-
raise
|
325
|
-
rescue => e
|
326
|
-
spec_file = e.backtrace
|
327
|
-
.select { |file| !file.include? 'lib/spectre' }
|
328
|
-
.first
|
329
|
-
.match(/(.*\.rb):\d+/)
|
330
|
-
.captures
|
331
|
-
.first
|
332
|
-
end
|
322
|
+
spec_file = get_file()
|
333
323
|
|
334
324
|
@__subject.add_spec(desc, tags, with, block, self, spec_file)
|
335
325
|
end
|
@@ -343,17 +333,44 @@ module Spectre
|
|
343
333
|
end
|
344
334
|
|
345
335
|
def setup &block
|
346
|
-
|
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)
|
347
341
|
end
|
348
342
|
|
349
343
|
def teardown &block
|
350
|
-
|
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)
|
351
349
|
end
|
352
350
|
|
353
351
|
def context desc=nil, &block
|
354
|
-
ctx = SpecContext.new(@__subject, desc)
|
352
|
+
ctx = SpecContext.new(@__subject, desc, self)
|
355
353
|
ctx._evaluate &block
|
356
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
|
357
374
|
end
|
358
375
|
|
359
376
|
|
@@ -406,14 +423,14 @@ module Spectre
|
|
406
423
|
|
407
424
|
def tag? tags, tag_exp
|
408
425
|
tags = tags.map { |x| x.to_s }
|
409
|
-
all_tags = tag_exp.split
|
426
|
+
all_tags = tag_exp.split('+')
|
410
427
|
included_tags = all_tags.select { |x| !x.start_with? '!' }
|
411
428
|
excluded_tags = all_tags.select { |x| x.start_with? '!' }.map { |x| x[1..-1] }
|
412
429
|
included_tags & tags == included_tags and excluded_tags & tags == []
|
413
430
|
end
|
414
431
|
|
415
432
|
def delegate *method_names, to: nil
|
416
|
-
Spectre::Delegator.delegate
|
433
|
+
Spectre::Delegator.delegate(*method_names, to)
|
417
434
|
end
|
418
435
|
|
419
436
|
def register &block
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,106 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
3
|
+
|
4
|
+
<svg
|
5
|
+
width="100"
|
6
|
+
height="100"
|
7
|
+
viewBox="0 0 26.458333 26.458334"
|
8
|
+
version="1.1"
|
9
|
+
id="spectre-logo"
|
10
|
+
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
|
11
|
+
sodipodi:docname="spectre_icon.svg"
|
12
|
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
13
|
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
14
|
+
xmlns="http://www.w3.org/2000/svg"
|
15
|
+
xmlns:svg="http://www.w3.org/2000/svg">
|
16
|
+
<sodipodi:namedview
|
17
|
+
id="namedview5496"
|
18
|
+
pagecolor="#505050"
|
19
|
+
bordercolor="#eeeeee"
|
20
|
+
borderopacity="1"
|
21
|
+
inkscape:pageshadow="0"
|
22
|
+
inkscape:pageopacity="0"
|
23
|
+
inkscape:pagecheckerboard="0"
|
24
|
+
inkscape:document-units="mm"
|
25
|
+
showgrid="false"
|
26
|
+
units="px"
|
27
|
+
inkscape:zoom="2.1997092"
|
28
|
+
inkscape:cx="47.051674"
|
29
|
+
inkscape:cy="98.876706"
|
30
|
+
inkscape:window-width="1920"
|
31
|
+
inkscape:window-height="1129"
|
32
|
+
inkscape:window-x="-8"
|
33
|
+
inkscape:window-y="-8"
|
34
|
+
inkscape:window-maximized="1"
|
35
|
+
inkscape:current-layer="layer1" />
|
36
|
+
<defs
|
37
|
+
id="defs5491">
|
38
|
+
<linearGradient
|
39
|
+
id="Spectre_Dark"
|
40
|
+
inkscape:swatch="solid"
|
41
|
+
gradientTransform="matrix(4.7460144,0,0,4.7460144,-50.422278,-45.446773)">
|
42
|
+
<stop
|
43
|
+
style="stop-color:#001b41;stop-opacity:1;"
|
44
|
+
offset="0"
|
45
|
+
id="stop935" />
|
46
|
+
</linearGradient>
|
47
|
+
<linearGradient
|
48
|
+
id="Spectre"
|
49
|
+
inkscape:swatch="solid"
|
50
|
+
gradientTransform="translate(3.6978833,7.3957665)">
|
51
|
+
<stop
|
52
|
+
style="stop-color:#0b9dcc;stop-opacity:1;"
|
53
|
+
offset="0"
|
54
|
+
id="stop929" />
|
55
|
+
</linearGradient>
|
56
|
+
</defs>
|
57
|
+
<g
|
58
|
+
inkscape:label="Layer 1"
|
59
|
+
inkscape:groupmode="layer"
|
60
|
+
id="layer1">
|
61
|
+
<path
|
62
|
+
d="M 23.562614,1.8538626 H 2.0855215 A 1.3423183,1.3423183 0 0 0 0.7432002,3.1961811 V 18.632839 a 1.3423183,1.3423183 0 0 0 1.3423213,1.342315 h 7.0471714 v 2.01348 A 0.67115913,0.67115913 0 0 1 8.4615361,22.659792 H 6.1124777 a 0.33558161,0.33558161 0 0 0 0,0.67116 h 5.7048483 a 0.33558161,0.33558161 0 0 0 0,-0.67116 H 9.6226382 a 1.3423183,1.3423183 0 0 0 0.1812166,-0.671158 v -2.01348 h 1.3423172 a 0.33557958,0.33557958 0 0 0 0,-0.671153 H 2.0855241 A 0.67115913,0.67115913 0 0 1 1.4143648,18.632839 V 3.1961811 A 0.67115913,0.67115913 0 0 1 2.0855241,2.5250204 H 23.562621 a 0.67115913,0.67115913 0 0 1 0.671162,0.6711607 v 8.3894869 a 0.33557958,0.33557958 0 0 0 0.671153,0 V 3.1961811 A 1.3423183,1.3423183 0 0 0 23.562614,1.8538626 Z"
|
63
|
+
style="display:inline;fill:url(#Spectre_Dark);fill-opacity:1;stroke-width:0.167791"
|
64
|
+
id="path853" />
|
65
|
+
<g
|
66
|
+
id="g865"
|
67
|
+
style="display:inline"
|
68
|
+
transform="matrix(0.24129238,0,0,0.24129238,1.9407417,-38.899368)">
|
69
|
+
<path
|
70
|
+
style="fill:none;stroke:url(#Spectre);stroke-width:2.75181;stroke-linecap:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
71
|
+
inkscape:connector-curvature="0"
|
72
|
+
class="st0"
|
73
|
+
d="m 87.314438,220.45502 c -2.965446,-1.69357 -4.198358,-7.47409 -6.531567,-12.84322 -2.344591,-5.39532 -5.80024,-10.37523 -13.241437,-10.37523 -14.84627,0 -12.430241,16.45022 -18.715617,18.63643 -6.285375,2.18621 -11.344875,8.86753 -11.344875,15.69946 14.2896,-1.82364 8.286409,9.69604 11.92715,13.32925 4.174521,4.16589 7.891305,0.93451 11.934895,7.69523 3.695179,6.17818 12.014082,6.69916 12.014082,6.69916 0,0 -3.17754,-10.29522 5.345264,-12.54277 12.0242,-3.55261 3.991998,-12.1135 17.745155,-9.35513 -0.654889,-4.27936 0.134141,-11.65066 -9.13305,-16.94318 z"
|
74
|
+
id="path857"
|
75
|
+
sodipodi:nodetypes="sssscsscccs"
|
76
|
+
inkscape:export-filename="C:\Tools\spectre-core\spectre_icon.png"
|
77
|
+
inkscape:export-xdpi="299"
|
78
|
+
inkscape:export-ydpi="299" />
|
79
|
+
<g
|
80
|
+
id="g863"
|
81
|
+
transform="matrix(6.7937703,0,0,6.7937703,24.913612,115.45241)"
|
82
|
+
style="fill:#0b9dcc;fill-opacity:1">
|
83
|
+
<path
|
84
|
+
d="m 5.9963355,15.094538 c 0,0 -0.1905226,0.399828 -0.6815162,0.320321 -0.4909939,-0.0795 -0.6341843,-0.591042 -0.6341843,-0.591042 0,0 0.378481,0.114842 0.6619948,0.167782 0.2835137,0.05294 0.6537059,0.102935 0.6537059,0.102935 z"
|
85
|
+
id="path859"
|
86
|
+
inkscape:connector-curvature="0"
|
87
|
+
sodipodi:nodetypes="czczcc"
|
88
|
+
class="spectre-logo-eye"
|
89
|
+
style="fill:url(#Spectre);fill-opacity:1;stroke-width:0.522545"
|
90
|
+
inkscape:export-filename="C:\Tools\spectre-core\spectre_icon.png"
|
91
|
+
inkscape:export-xdpi="299"
|
92
|
+
inkscape:export-ydpi="299" />
|
93
|
+
<path
|
94
|
+
d="m 8.0112257,14.954736 c 0,0 -0.2622402,0.669385 -0.748107,0.683114 -0.4858668,0.01373 -0.7413854,-0.519393 -0.7413854,-0.519393 0,0 0.391654,0.0016 0.7384379,-0.03607 0.3467838,-0.03767 0.7510545,-0.127651 0.7510545,-0.127651 z"
|
95
|
+
id="path861"
|
96
|
+
inkscape:connector-curvature="0"
|
97
|
+
sodipodi:nodetypes="czczcc"
|
98
|
+
class="spectre-logo-eye"
|
99
|
+
style="fill:url(#Spectre);fill-opacity:1;stroke-width:0.522545"
|
100
|
+
inkscape:export-filename="C:\Tools\spectre-core\spectre_icon.png"
|
101
|
+
inkscape:export-xdpi="299"
|
102
|
+
inkscape:export-ydpi="299" />
|
103
|
+
</g>
|
104
|
+
</g>
|
105
|
+
</g>
|
106
|
+
</svg>
|