spectre-core 1.12.4 → 1.13.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.
@@ -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%:z')
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, 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? }
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 += '<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 + '">'
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
- 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) + '">'
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
- 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>'
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 += '<error message="' + CGI::escapeHTML(failure_message.gsub('"', '`')) + '" type="' + type + '">'
55
- xml_str += '<![CDATA[' + text + ']]>'
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.inspect unless run_info.data.is_a? String or run_info.data.is_a? Integer
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.open(file_path, 'w') do |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 = 12
5
- TINY = 4
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 { |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
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>