test-unit-launchable 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '01920d3a94ad73191d001d98102c60a817c1148356c75b15bc224144eaa7d04f'
4
+ data.tar.gz: 47a02921e804d71a2922775f769335d210dcdc60662a97f1ccf109c92e81acd0
5
+ SHA512:
6
+ metadata.gz: 2bdec3d56533bbd3a146c6b73c01471b6852f0b1c06fa86a8bd88c6788ecd32a282d4bad79e12369f39e192ffbe27cbe7dafb028b514ad90c76c30da7ef76584
7
+ data.tar.gz: 7c4e5e5fbbdcb56bc516eea1bdca2cf44eb13712ebd3fce7b9240c49ef397b37628b29faedc170a4eea34663414068bf37cc5c526c6dba91cbeb112d8e898c79
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Naoto Ono
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # Test::Unit::Launchable
2
+
3
+ test-unit-launchable is a convinient plugin for test-unit that generates a Launchable test report file based on the test results.
4
+
5
+ ## Installation
6
+
7
+ Install the gem and add to the application's Gemfile by executing:
8
+
9
+ $ bundle add test-unit-launchable
10
+
11
+ If bundler is not being used to manage dependencies, install the gem by executing:
12
+
13
+ $ gem install test-unit-launchable
14
+
15
+ ## Usage
16
+
17
+ ```ruby
18
+ require "test/unit/runner/launchable"
19
+ ```
20
+
21
+ ```
22
+ ruby test/example_test.rb --runner=launchable --launchable-test-report-json=report.json
23
+ ```
24
+
25
+ ## CLI options
26
+
27
+ - --launchable-test-report-json=PATH
28
+ - Report test results in [Launchable JSON format](https://www.launchableinc.com/docs/resources/integrations/raw/).
29
+
30
+ ## Development
31
+
32
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test-unit` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
33
+
34
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
35
+
36
+ ## Contributing
37
+
38
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ono-max/test-unit-launchable.
39
+
40
+ ## License
41
+
42
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
+ end
11
+
12
+ task default: :test
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Test
4
+ module Unit
5
+ module Launchable
6
+ VERSION = "0.1.0"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ require "test/unit/autorunner"
2
+
3
+ module Test
4
+ module Unit
5
+ AutoRunner.register_runner(:launchable) do |auto_runner|
6
+ require_relative 'testrunner'
7
+ Test::Unit::UI::Launchable::JSON::TestRunner
8
+ end
9
+
10
+ AutoRunner.setup_option do |auto_runner, opts|
11
+ opts.on("--launchable-test-report-json=PATH", 'Report test results in Launchable JSON format') do |path|
12
+ auto_runner.runner_options[:launchable_test_report] = path
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,349 @@
1
+ require 'json'
2
+ require 'test/unit/ui/testrunnermediator'
3
+ require 'test/unit/ui/console/testrunner'
4
+
5
+ module Test
6
+ module Unit
7
+ module UI
8
+ module Launchable
9
+ module JSON
10
+ class TestRunner < UI::Console::TestRunner
11
+ def initialize(suite, options={})
12
+ super
13
+ @curt_test_case = nil
14
+ @json_stream_writer = nil
15
+ end
16
+
17
+ def attach_to_mediator
18
+ # To output logs to both stderr/stdout and an XML file,
19
+ # `UI::Console::TestRunner#attach_to_mediator` is called here.
20
+ super
21
+
22
+ test_report = @options[:launchable_test_report]
23
+ return unless test_report
24
+
25
+ @json_stream_writer = JSONStreamWriter.new(test_report)
26
+ @mediator.add_listener(::Test::Unit::TestCase::STARTED_OBJECT) do |test|
27
+ @curt_test_case = LaunchableTestCase.new(test)
28
+ end
29
+ @mediator.add_listener(::Test::Unit::TestCase::FINISHED_OBJECT) do |test|
30
+ @curt_test_case.elapsed_time = test.elapsed_time
31
+ @json_stream_writer.open_nested_object do |writer|
32
+ # The test path is a URL-encoded representation.
33
+ # https://github.com/launchableinc/cli/blob/v1.81.0/launchable/testpath.py#L18
34
+ writer.write_key_value("testPath", @curt_test_case.test_path)
35
+ writer.write_key_value("duration", @curt_test_case.elapsed_time)
36
+ writer.write_key_value("status", @curt_test_case.status)
37
+ writer.write_key_value("stderr", @curt_test_case.stderr)
38
+ writer.write_key_value("stdout", nil)
39
+ writer.write_key_value("createdAt", Time.now.to_s)
40
+ end
41
+ @curt_test_case = nil
42
+ end
43
+ @mediator.add_listener(TestResult::FAULT) do |fault|
44
+ @curt_test_case.fault = fault
45
+ end
46
+ @mediator.add_listener(TestRunnerMediator::FINISHED) do
47
+ @json_stream_writer.close
48
+ end
49
+ end
50
+ end
51
+
52
+ class LaunchableTestCase
53
+ attr_reader :method_name, :class_name, :source_location
54
+ attr_accessor :fault, :elapsed_time
55
+
56
+ def initialize(test)
57
+ @method_name = test.method_name
58
+ @class_name = test.class.name
59
+ @failure_msg = ""
60
+ @source_location = test.method(@method_name).source_location.first
61
+ end
62
+
63
+ def status
64
+ case @fault
65
+ when Pending, Omission
66
+ 'TEST_SKIPPED'
67
+ when Error, Failure
68
+ 'TEST_FAILED'
69
+ else
70
+ 'TEST_PASSED'
71
+ end
72
+ end
73
+
74
+ def stderr
75
+ @fault&.message
76
+ end
77
+
78
+ def test_path
79
+ {file: @source_location, class: @class_name, testcase: @method_name}.map{|key, val|
80
+ "#{encode_test_path_component(key)}=#{encode_test_path_component(val)}"
81
+ }.join('#')
82
+ end
83
+
84
+ def encode_test_path_component component
85
+ component.to_s.gsub('%', '%25').gsub('=', '%3D').gsub('#', '%23').gsub('&', '%26')
86
+ end
87
+ end
88
+
89
+ class JSONStreamWriter
90
+ class TestCaseWriter
91
+ def initialize(file, indent)
92
+ @file = file
93
+ @indent = indent
94
+ @file.puts
95
+ @indent += 2
96
+ write_indent
97
+ @file.puts("{")
98
+ @indent += 2
99
+ @writer = KeyValueWriter.new(file, @indent)
100
+ end
101
+
102
+ def write_test_path_components(components)
103
+ @writer.open_array("testPathComponents") do
104
+ components.each {|component|
105
+ @writer.open_nested_object do |obj_writer|
106
+ obj_writer.write_key_value("type", component[:type])
107
+ obj_writer.write_key_value("name", component[:name])
108
+ end
109
+ }
110
+ end
111
+ end
112
+
113
+ def write_duration(duration)
114
+ @writer.write_key_value("duration", duration)
115
+ end
116
+
117
+ def write_status(status)
118
+ @writer.write_key_value("status", status)
119
+ end
120
+
121
+ def write_stdout(stdout)
122
+ @writer.write_key_value("stdout", stdout)
123
+ end
124
+
125
+ def write_stderr(stderr)
126
+ @writer.write_key_value("stderr", stderr)
127
+ end
128
+
129
+ def write_created_at(created_at)
130
+ @writer.write_key_value("createdAt", created_at)
131
+ end
132
+
133
+ def close
134
+ @writer.close
135
+ end
136
+
137
+ def write_indent
138
+ @file.write(" " * @indent)
139
+ end
140
+ end
141
+
142
+ class KeyValueWriter
143
+ def initialize(file, indent)
144
+ @indent = indent
145
+ @file = file
146
+ @is_first_key_val = true
147
+ @is_first_element = true
148
+ end
149
+
150
+ def write_key_value(key, value)
151
+ if @is_first_key_val
152
+ @is_first_key_val = false
153
+ else
154
+ write_comma
155
+ end
156
+ @file.puts
157
+ write_indent
158
+ @file.write(to_json_str(key))
159
+ @file.write(":", " ")
160
+ @file.write(to_json_str(value))
161
+ end
162
+
163
+ def open_nested_object
164
+ @file.puts("{")
165
+ @indent += 2
166
+ @writer = KeyValueWriter.new(file, @indent)
167
+ end
168
+
169
+ def open_nested_object
170
+ if @is_first_element
171
+ @is_first_element = false
172
+ else
173
+ write_comma
174
+ end
175
+ @indent += 2
176
+ @file.puts
177
+ write_indent
178
+ @file.write("{")
179
+ @indent += 2
180
+ yield KeyValueWriter.new(@file, @indent)
181
+ @indent -= 2
182
+ @file.puts
183
+ write_indent
184
+ @file.write("}")
185
+ @is_first_key_val = false
186
+ @indent -= 2
187
+ end
188
+
189
+ def close
190
+ @indent -= 2
191
+ @file.puts
192
+ write_indent
193
+ @file.write("}")
194
+ end
195
+
196
+ def open_array(key)
197
+ if @is_first_key_val
198
+ @is_first_key_val = false
199
+ else
200
+ write_comma
201
+ end
202
+ write_indent
203
+ @file.write(to_json_str(key))
204
+ write_colon
205
+ @file.write(" ")
206
+ @file.write("[")
207
+ yield
208
+ @file.puts
209
+ write_indent
210
+ @file.write("]")
211
+ end
212
+
213
+ def close_array
214
+ @file.puts
215
+ write_indent
216
+ @file.puts("]")
217
+ end
218
+
219
+ private
220
+
221
+ def write_comma
222
+ @file.write(',')
223
+ end
224
+
225
+ def write_indent
226
+ @file.write(" " * @indent)
227
+ end
228
+
229
+ def to_json_str(obj)
230
+ ::JSON.dump(obj)
231
+ end
232
+
233
+ def write_colon
234
+ @file.write(":")
235
+ end
236
+ end
237
+
238
+ class ArrayWriter
239
+ def initialize(file, indent)
240
+ @indent = indent
241
+ @file = file
242
+ @is_first_element = true
243
+ end
244
+
245
+ def open_array(key)
246
+ write_indent
247
+ @file.write(to_json_str(key))
248
+ write_colon
249
+ @file.write(" ")
250
+ @file.write("[")
251
+ end
252
+
253
+ def close_array
254
+ @file.puts
255
+ write_indent
256
+ @file.puts("]")
257
+ end
258
+
259
+ private
260
+
261
+ def write_comma
262
+ @file.write(',')
263
+ end
264
+
265
+ def write_indent
266
+ @file.write(" " * @indent)
267
+ end
268
+
269
+ def write_colon
270
+ @file.write(":")
271
+ end
272
+
273
+ def to_json_str(obj)
274
+ ::JSON.dump(obj)
275
+ end
276
+ end
277
+
278
+ def initialize path
279
+ @file = File.open(path, "w")
280
+ @indent = 2
281
+ @file.puts("{")
282
+ write_indent
283
+ open_array("testCases")
284
+ @file.flush
285
+ @is_first_nested_obj = true
286
+ end
287
+
288
+ def write_test_case
289
+ if @is_first_nested_obj
290
+ @is_first_nested_obj = false
291
+ else
292
+ write_comma
293
+ end
294
+ # @file.puts
295
+ # @indent += 2
296
+ # write_indent
297
+ # @file.puts("{")
298
+ writer = TestCaseWriter.new(@file, @indent)
299
+ yield writer
300
+ # @file.puts
301
+ # write_indent
302
+ # @file.write("}")
303
+ # @indent -= 2
304
+ writer.close
305
+ end
306
+
307
+ def close
308
+ close_array
309
+ @file.puts("}")
310
+ @file.flush
311
+ @file.close
312
+ end
313
+
314
+ private
315
+
316
+ def open_array(key)
317
+ @file.write(to_json_str(key))
318
+ write_colon
319
+ @file.write(" ")
320
+ @file.write("[")
321
+ end
322
+
323
+ def close_array
324
+ @file.puts
325
+ write_indent
326
+ @file.puts("]")
327
+ end
328
+
329
+ def write_indent
330
+ @file.write(" " * @indent)
331
+ end
332
+
333
+ def write_colon
334
+ @file.write(":")
335
+ end
336
+
337
+ def write_comma
338
+ @file.write(',')
339
+ end
340
+
341
+ def to_json_str(obj)
342
+ ::JSON.dump(obj)
343
+ end
344
+ end
345
+ end
346
+ end
347
+ end
348
+ end
349
+ end
@@ -0,0 +1,8 @@
1
+ module Test
2
+ module Unit
3
+ module Launchable
4
+ VERSION: String
5
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
6
+ end
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: test-unit-launchable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Naoto Ono
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-03-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: test-unit
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: test-unit-launchable is a convinient plugin for test-unit that generates
28
+ a Launchable test report file based on the test results.
29
+ email:
30
+ - onoto1998@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - LICENSE.txt
36
+ - README.md
37
+ - Rakefile
38
+ - lib/test/unit/launchable/version.rb
39
+ - lib/test/unit/runner/launchable.rb
40
+ - lib/test/unit/ui/launchable/json/testrunner.rb
41
+ - sig/test/unit/launchable.rbs
42
+ homepage: https://github.com/ono-max/test-unit-launchable
43
+ licenses:
44
+ - MIT
45
+ metadata:
46
+ homepage_uri: https://github.com/ono-max/test-unit-launchable
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: 3.0.0
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubygems_version: 3.3.26
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: test-unit plugin that generates a Launchable test report file
66
+ test_files: []