spectre-core 1.12.4 → 1.14.1

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.
@@ -2,7 +2,7 @@ require_relative '../spectre'
2
2
  require 'date'
3
3
 
4
4
  module Spectre
5
- module Logger
5
+ module Logging
6
6
  module Status
7
7
  OK = '[ok]'
8
8
  FAILED = '[failed]'
@@ -12,6 +12,31 @@ module Spectre
12
12
  DEBUG = '[debug]'
13
13
  end
14
14
 
15
+ class ModuleLogger
16
+ def initialize config, name
17
+ @name = name
18
+ @debug = config['debug']
19
+ @logger = ::Logger.new(config['log_file'], progname: name)
20
+
21
+ @logger.level = @debug ? ::Logger::DEBUG : ::Logger::INFO
22
+ end
23
+
24
+ def info message
25
+ @logger.info(message)
26
+ Logging.add_log(message, :info, @name)
27
+ end
28
+
29
+ def debug message
30
+ @logger.debug(message)
31
+ Logging.add_log(message, :debug, @name) if @debug
32
+ end
33
+
34
+ def warn message
35
+ @logger.warn(message)
36
+ Logging.add_log(message, :warn, @name)
37
+ end
38
+ end
39
+
15
40
  class << self
16
41
  @@debug = false
17
42
  @@logger = []
@@ -93,19 +118,19 @@ module Spectre
93
118
  end
94
119
 
95
120
  def log_info message
96
- add_log(message)
121
+ add_log(message, :info)
97
122
  delegate(:log_info, message)
98
123
  end
99
124
 
100
125
  def log_debug message
101
126
  return unless @@debug
102
127
 
103
- add_log(message)
128
+ add_log(message, :debug)
104
129
  delegate(:log_debug, message)
105
130
  end
106
131
 
107
132
  def log_error spec, exception
108
- add_log(exception)
133
+ add_log(exception, :error)
109
134
  delegate(:log_error, spec, exception)
110
135
  end
111
136
 
@@ -118,9 +143,15 @@ module Spectre
118
143
  end
119
144
 
120
145
  def group desc
121
- Logger.start_group desc
146
+ Logging.start_group desc
122
147
  yield
123
- Logger.end_group desc
148
+ Logging.end_group desc
149
+ end
150
+
151
+ def add_log message, level, logger_name='spectre'
152
+ return unless Spectre::Runner.current
153
+
154
+ Spectre::Runner.current.log.append([DateTime.now, message, level, logger_name])
124
155
  end
125
156
 
126
157
  alias_method :info, :log_info
@@ -135,10 +166,6 @@ module Spectre
135
166
  logger.send(method, *args) if logger.respond_to? method
136
167
  end
137
168
  end
138
-
139
- def add_log message
140
- Spectre::Runner.current.log.append([DateTime.now, message])
141
- end
142
169
  end
143
170
 
144
171
  Spectre.delegate :log, :info, :debug, :group, :separate, to: self
data/lib/spectre/mixin.rb CHANGED
@@ -12,12 +12,12 @@ module Spectre
12
12
 
13
13
  def required params, *keys
14
14
  missing_keys = keys.select { |x| !params.to_h.key? x }
15
- Spectre::Logger.log_debug("required parameters for '#{@__desc}': #{keys.join ', '}")
15
+ Spectre::Logging.log_debug("required parameters for '#{@__desc}': #{keys.join ', '}")
16
16
  raise ArgumentError, "mixin '#{@__desc}' requires #{keys.join ', '}, but only has #{missing_keys.join ', '} given" unless missing_keys.empty?
17
17
  end
18
18
 
19
19
  def optional params, *keys
20
- Spectre::Logger.log_debug("optional parameters for '#{@__desc}': #{keys.join ', '}")
20
+ Spectre::Logging.log_debug("optional parameters for '#{@__desc}': #{keys.join ', '}")
21
21
  params
22
22
  end
23
23
  end
@@ -32,7 +32,7 @@ module Spectre
32
32
  def run desc, with: []
33
33
  raise "no mixin with desc '#{desc}' defined" unless @@mixins.key? desc
34
34
 
35
- Spectre::Logger.log_debug "running mixin '#{desc}'"
35
+ Spectre::Logging.log_debug "running mixin '#{desc}'"
36
36
 
37
37
  params = with || {}
38
38
 
@@ -14,36 +14,34 @@ module Spectre::Reporter
14
14
  run_infos
15
15
  .select { |x| x.error != nil or x.failure != nil }
16
16
  .each_with_index do |run_info, index|
17
- spec = run_info.spec
17
+ report_str += "\n#{index+1}) #{format_title(run_info)}\n"
18
18
 
19
- report_str += "\n#{index+1}) #{format_title(run_info)}\n"
19
+ if run_info.failure
20
+ report_str += " Expected #{run_info.failure.expectation}"
21
+ report_str += " with #{run_info.data}" if run_info.data
20
22
 
21
- if run_info.failure
22
- report_str += " Expected #{run_info.failure.expectation}"
23
- report_str += " with #{run_info.data}" if run_info.data
23
+ report_str += " but it failed"
24
24
 
25
- report_str += " but it failed"
25
+ if run_info.failure.cause
26
+ report_str += "\n with an unexpected error:\n"
27
+ report_str += format_exception(run_info.failure.cause)
26
28
 
27
- if run_info.failure.cause
28
- report_str += "\n with an unexpected error:\n"
29
- report_str += format_exception(run_info.failure.cause)
29
+ elsif run_info.failure.message and not run_info.failure.message.empty?
30
+ report_str += " with:\n #{run_info.failure.message}"
30
31
 
31
- elsif run_info.failure.message and not run_info.failure.message.empty?
32
- report_str += " with:\n #{run_info.failure.message}"
32
+ else
33
+ report_str += '.'
34
+ end
35
+
36
+ report_str += "\n"
37
+ failures += 1
33
38
 
34
39
  else
35
- report_str += '.'
40
+ report_str += " but an unexpected error occurred during run\n"
41
+ report_str += format_exception(run_info.error)
42
+ errors += 1
36
43
  end
37
-
38
- report_str += "\n"
39
- failures += 1
40
-
41
- else
42
- report_str += " but an unexpected error occurred during run\n"
43
- report_str += format_exception(run_info.error)
44
- errors += 1
45
44
  end
46
- end
47
45
 
48
46
  if failures + errors > 0
49
47
  summary = ''
@@ -54,7 +52,6 @@ module Spectre::Reporter
54
52
  summary += "#{run_infos.length} total"
55
53
  print "\n#{summary}\n".red
56
54
  else
57
- summary = ''
58
55
  summary = "\nRun finished successfully"
59
56
  summary += " (#{skipped} skipped)" if skipped > 0
60
57
  print "#{summary}\n".green
data/lib/spectre.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  module Spectre
2
2
  module Version
3
3
  MAJOR = 1
4
- MINOR = 12
5
- TINY = 4
4
+ MINOR = 14
5
+ TINY = 1
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 { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge!(v2, &merger) : v2 }
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, spec_group|
158
- Logger.log_subject subject do
159
- spec_group.group_by { |x| x.context }.each do |context, specs|
160
- Logger.log_context(context) do
161
- runs.concat run_context(context, specs)
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
- if context.__setup_blocks.count > 0
176
- setup_run = run_blocks('setup', context, context.__setup_blocks)
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
- Logger.log_spec(spec, data) do
196
+ Logging.log_spec(spec, data) do
190
197
  runs << run_spec(spec, data)
191
198
  end
192
199
  end
193
200
  else
194
- Logger.log_spec(spec) do
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
- if context.__teardown_blocks.count > 0
201
- runs << run_blocks('teardown', context, context.__teardown_blocks)
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 run_blocks name, context, blocks
209
- ctx = SpecContext.new context.__subject, name
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
- Logger.log_context ctx do
222
+ Logging.log_context(spec.context) do
219
223
  begin
220
- blocks.each do |block|
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
- Logger.log_error spec, e
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
- Logger.log_context before_ctx do
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
- Logger.log_skipped spec, e.message
265
+ Logging.log_skipped(spec, e.message)
264
266
  rescue Interrupt
265
267
  run_info.skipped = true
266
- Logger.log_skipped spec, 'canceled by user'
268
+ Logging.log_skipped(spec, 'canceled by user')
267
269
  rescue Exception => e
268
270
  run_info.error = e
269
- Logger.log_error spec, e
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
- Logger.log_context after_ctx do
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
- Logger.log_error spec, e
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
- # Get the file, where the spec is defined.
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
- @__setup_blocks << block
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
- @__teardown_blocks << block
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 *method_names, to
433
+ Spectre::Delegator.delegate(*method_names, to)
417
434
  end
418
435
 
419
436
  def register &block
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spectre-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.4
4
+ version: 1.14.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christian Neubauer
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-29 00:00:00.000000000 Z
11
+ date: 2022-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ectoplasm
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 1.2.1
19
+ version: 1.2.3
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 1.2.1
26
+ version: 1.2.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: jsonpath
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -49,6 +49,7 @@ files:
49
49
  - exe/spectre
50
50
  - lib/spectre.rb
51
51
  - lib/spectre/assertion.rb
52
+ - lib/spectre/async.rb
52
53
  - lib/spectre/bag.rb
53
54
  - lib/spectre/curl.rb
54
55
  - lib/spectre/diagnostic.rb
@@ -62,17 +63,15 @@ files:
62
63
  - lib/spectre/logger/file.rb
63
64
  - lib/spectre/mixin.rb
64
65
  - lib/spectre/reporter/console.rb
65
- - lib/spectre/reporter/junit.rb
66
66
  - lib/spectre/resources.rb
67
67
  homepage: https://github.com/ionos-spectre/spectre-core
68
68
  licenses:
69
69
  - GPL-3.0-or-later
70
70
  metadata:
71
- allowed_push_host: https://rubygems.org/
72
71
  homepage_uri: https://github.com/ionos-spectre/spectre-core
73
72
  source_code_uri: https://github.com/ionos-spectre/spectre-core
74
73
  changelog_uri: https://github.com/ionos-spectre/spectre-core/blob/master/CHANGELOG.md
75
- post_install_message:
74
+ post_install_message:
76
75
  rdoc_options: []
77
76
  require_paths:
78
77
  - lib
@@ -88,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
87
  version: '0'
89
88
  requirements: []
90
89
  rubygems_version: 3.3.7
91
- signing_key:
90
+ signing_key:
92
91
  specification_version: 4
93
92
  summary: Describe and run automated tests
94
93
  test_files: []
@@ -1,102 +0,0 @@
1
- require 'cgi'
2
-
3
- # https://llg.cubic.org/docs/junit/
4
- # Azure mappings: https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/test/publish-test-results?view=azure-devops&tabs=junit%2Cyaml
5
-
6
- module Spectre::Reporter
7
- class JUnit
8
- def initialize config
9
- @config = config
10
- end
11
-
12
- def report run_infos
13
- now = Time.now.getutc
14
- timestamp = now.strftime('%s')
15
- datetime = now.strftime('%FT%T%:z')
16
-
17
- xml_str = '<?xml version="1.0" encoding="UTF-8" ?>'
18
- xml_str += '<testsuites>'
19
-
20
- suite_id = 0
21
-
22
- run_infos.group_by { |x| x.spec.subject }.each do |subject, run_infos|
23
- failures = run_infos.select { |x| x.failure != nil }
24
- errors = run_infos.select { |x| x.error != nil }
25
- skipped = run_infos.select { |x| x.skipped? }
26
-
27
- 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.to_s + '" failures="' + failures.count.to_s + '" errors="' + errors.count.to_s + '" skipped="' + skipped.count.to_s + '">'
28
- suite_id += 1
29
-
30
- run_infos.each do |run_info|
31
- xml_str += '<testcase classname="' + CGI::escapeHTML(run_info.spec.file.to_s) + '" name="' + CGI::escapeHTML(run_info.spec.desc) + '" timestamp="' + run_info.started.to_s + '" time="' + ('%.3f' % run_info.duration) + '">'
32
-
33
- if run_info.failure and !run_info.failure.cause
34
- failure_message = "Expected #{run_info.failure.expectation}"
35
- failure_message += " with #{run_info.data}" if run_info.data
36
-
37
- if run_info.failure.message
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>'
44
- end
45
-
46
-
47
- if run_info.error or (run_info.failure and run_info.failure.cause)
48
- error = run_info.error || run_info.failure.cause
49
-
50
- type = error.class.name
51
- failure_message = error.message
52
- text = error.backtrace.join "\n"
53
-
54
- xml_str += '<error message="' + CGI::escapeHTML(failure_message.gsub('"', '`')) + '" type="' + type + '">'
55
- xml_str += '<![CDATA[' + text + ']]>'
56
- xml_str += '</error>'
57
- end
58
-
59
-
60
- if run_info.log.count > 0 or run_info.properties.count > 0 or run_info.data
61
- xml_str += '<system-out>'
62
- xml_str += '<![CDATA['
63
-
64
- if run_info.properties.count > 0
65
- run_info.properties.each do |key, val|
66
- xml_str += "#{key}: #{val}\n"
67
- end
68
- end
69
-
70
- if run_info.data
71
- data_str = run_info.data
72
- data_str = run_info.data.inspect unless run_info.data.is_a? String or run_info.data.is_a? Integer
73
- xml_str += "data: #{data_str}\n"
74
- end
75
-
76
- if run_info.log.count > 0
77
- messages = run_info.log.map { |x| "[#{x[0].strftime('%F %T')}] #{x[1]}" }
78
- xml_str += messages.join("\n")
79
- end
80
-
81
- xml_str += ']]>'
82
- xml_str += '</system-out>'
83
- end
84
-
85
- xml_str += '</testcase>'
86
- end
87
-
88
- xml_str += '</testsuite>'
89
- end
90
-
91
- xml_str += '</testsuites>'
92
-
93
- Dir.mkdir @config['out_path'] unless Dir.exist? @config['out_path']
94
-
95
- file_path = File.join(@config['out_path'], "spectre-junit_#{timestamp}.xml")
96
-
97
- File.open(file_path, 'w') do |file|
98
- file.write(xml_str)
99
- end
100
- end
101
- end
102
- end