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.
@@ -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>