turbo_tests2 3.1.7 → 3.1.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e444f1953cfde46e5e7f26987d906fb2defe9a897bc25276976eefcee15e04e7
4
- data.tar.gz: 23a06d24ba5f7af5b2720da6abcad8b22b45b8500b48256facb6486e30cf4cdf
3
+ metadata.gz: fabbd1aadd354e11840e0aaf2ce278c209eb3600f58b8a2ed9eadca74b1428bc
4
+ data.tar.gz: 75ee010bc491d4e4a5b77c0ede26bc748eeba35d89fafdab64e5acd2deb10df2
5
5
  SHA512:
6
- metadata.gz: e965515e3b41e4a9996ba563cb4a3c3c6885d8b0d8b2af925aa3ce499f8225df52faf0364aff49eb25cbeb078d37cbb0ff734034aa64d623e7bdcb9f146d5c71
7
- data.tar.gz: 2a4aaa4fc5e223bf31009da14996ad5262b7eee2e1b1ff0e61adfe78dad90fdd0c70b86c3e2fbc2b3da86ba60ce6d732b39fabb96a587aee9e7599c128b4e2cc
6
+ metadata.gz: 649dc4a8ac38f52c4773432cb404e43b16cbf9a4197c20bb49c01b8774b88b82a5921544e450541e61ffb3ceef3466c65536317c415a8ecd9d07acd05a547b38
7
+ data.tar.gz: c23d6a3c468aee9b3d32879dd8eeaf01b2801b2bad965fb406e4539407cf3f29f4548f377318155d7e8e0dde6e9fa4e879852b3bb8235d161ee7e9d23f8b8025
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,28 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [3.1.9] - 2026-07-14
34
+
35
+ - TAG: [v3.1.9][3.1.9t]
36
+ - COVERAGE: 97.60% -- 692/709 lines in 10 files
37
+ - BRANCH COVERAGE: 89.13% -- 164/184 branches in 10 files
38
+ - 37.08% documented
39
+
40
+ ### Fixed
41
+
42
+ - Buffered non-RSpec worker stdout/stderr so successful parallel runs no longer
43
+ leak interleaved coverage formatter output, while still reporting a single
44
+ concise coverage summary.
45
+ - Prevented invalid UTF-8 bytes in worker output from crashing the parent
46
+ runner on JRuby after the underlying RSpec examples pass.
47
+
48
+ ## [3.1.8] - 2026-07-14
49
+
50
+ - TAG: [v3.1.8][3.1.8t]
51
+ - COVERAGE: 97.40% -- 636/653 lines in 10 files
52
+ - BRANCH COVERAGE: 89.47% -- 136/152 branches in 10 files
53
+ - 37.08% documented
54
+
33
55
  ## [3.1.7] - 2026-07-11
34
56
 
35
57
  - TAG: [v3.1.7][3.1.7t]
@@ -213,7 +235,11 @@ Please file a bug if you notice a violation of semantic versioning.
213
235
 
214
236
  - Initial release
215
237
 
216
- [Unreleased]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.1.7...HEAD
238
+ [Unreleased]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.1.9...HEAD
239
+ [3.1.9]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.1.8...v3.1.9
240
+ [3.1.9t]: https://github.com/galtzo-floss/turbo_tests2/releases/tag/v3.1.9
241
+ [3.1.8]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.1.7...v3.1.8
242
+ [3.1.8t]: https://github.com/galtzo-floss/turbo_tests2/releases/tag/v3.1.8
217
243
  [3.1.7]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.1.6...v3.1.7
218
244
  [3.1.7t]: https://github.com/galtzo-floss/turbo_tests2/releases/tag/v3.1.7
219
245
  [3.1.6]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.1.5...v3.1.6
data/README.md CHANGED
@@ -666,7 +666,7 @@ Thanks for RTFM. ☺️
666
666
  [📌gitmoji]: https://gitmoji.dev
667
667
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
668
668
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
669
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.653-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
669
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.709-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
670
670
  [🔐security]: https://github.com/galtzo-floss/turbo_tests2/blob/main/SECURITY.md
671
671
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
672
672
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -210,8 +210,21 @@ module TurboTests
210
210
  end
211
211
 
212
212
  def output_row(obj)
213
- output.puts "#{ENV.fetch("RSPEC_FORMATTER_OUTPUT_ID", "")}#{obj.to_json}"
213
+ output.puts "#{ENV.fetch("RSPEC_FORMATTER_OUTPUT_ID", "")}#{json_ready(obj).to_json}"
214
214
  output.flush
215
215
  end
216
+
217
+ def json_ready(obj)
218
+ case obj
219
+ when Hash
220
+ obj.transform_values { |value| json_ready(value) }
221
+ when Array
222
+ obj.map { |value| json_ready(value) }
223
+ when String
224
+ obj.dup.force_encoding(Encoding::UTF_8).scrub
225
+ else
226
+ obj
227
+ end
228
+ end
216
229
  end
217
230
  end
@@ -135,6 +135,8 @@ module TurboTests
135
135
  @threads = []
136
136
  @wait_threads = []
137
137
  @exited_process_ids = []
138
+ @worker_output = Hash.new { |hash, process_id| hash[process_id] = {stdout: +"", stderr: +""} }
139
+ @worker_output_mutex = Mutex.new
138
140
  @error = false
139
141
  @print_failed_group = opts[:print_failed_group]
140
142
  end
@@ -158,6 +160,9 @@ module TurboTests
158
160
  }
159
161
 
160
162
  ParallelTests.with_pid_file do
163
+ exit_status = nil
164
+ report_coverage = false
165
+
161
166
  @reporter.report(tests_in_groups) do |_reporter|
162
167
  old_signal = Signal.trap(:INT) { handle_interrupt }
163
168
 
@@ -174,13 +179,20 @@ module TurboTests
174
179
 
175
180
  Signal.trap(:INT, old_signal)
176
181
 
177
- if @reporter.failed_examples.empty? && @wait_threads.map(&:value).all?(&:success?)
178
- 0
182
+ statuses = @wait_threads.map(&:value)
183
+
184
+ if @reporter.failed_examples.empty? && statuses.all?(&:success?)
185
+ report_coverage = true
186
+ exit_status = 0
179
187
  else
188
+ flush_worker_output
180
189
  # From https://github.com/galtzo-floss/turbo_tests2/pull/20/
181
- @wait_threads.map { |thread| thread.value.exitstatus }.max
190
+ exit_status = statuses.map(&:exitstatus).max
182
191
  end
183
192
  end
193
+
194
+ flush_coverage_summary if report_coverage
195
+ exit_status
184
196
  end
185
197
  end
186
198
 
@@ -297,15 +309,17 @@ module TurboTests
297
309
  stdout_thread =
298
310
  Thread.new do
299
311
  begin
312
+ output_id = env["RSPEC_FORMATTER_OUTPUT_ID"].b
300
313
  stdout.each_line do |line|
301
- result = line.split(env["RSPEC_FORMATTER_OUTPUT_ID"])
314
+ result = line.b.split(output_id)
302
315
 
303
316
  initial = result.shift
304
- print(initial) unless initial.empty?
317
+ append_worker_output(process_id, :stdout, initial) unless initial.empty?
305
318
 
306
319
  message = result.shift
307
320
  next unless message
308
321
 
322
+ message = message.dup.force_encoding(Encoding::UTF_8).scrub
309
323
  message = JSON.parse(message, symbolize_names: true)
310
324
 
311
325
  message[:process_id] = process_id
@@ -320,14 +334,14 @@ module TurboTests
320
334
  # rubocop:enable ThreadSafety/NewThread
321
335
  @threads << stdout_thread
322
336
 
323
- stderr_thread = start_copy_thread(stderr, $stderr)
337
+ stderr_thread = start_copy_thread(stderr, process_id, :stderr)
324
338
  @threads << stderr_thread
325
339
 
326
340
  # rubocop:disable ThreadSafety/NewThread
327
341
  @threads << Thread.new do
328
342
  begin
329
343
  status = wait_thr.value
330
- @messages << {type: "error"} unless status.success?
344
+ @messages << {type: "error", process_id: process_id} unless status.success?
331
345
  @messages << {type: "exit", process_id: process_id}
332
346
  ensure
333
347
  stop_reader_thread(stdout_thread, stdout)
@@ -353,7 +367,7 @@ module TurboTests
353
367
  ParallelTests::Pids.new(pid_file_path).delete(pid) if pid && pid_file_path
354
368
  end
355
369
 
356
- def start_copy_thread(src, dst)
370
+ def start_copy_thread(src, process_id, stream)
357
371
  # rubocop:disable ThreadSafety/NewThread
358
372
  Thread.new do
359
373
  # rubocop:enable ThreadSafety/NewThread
@@ -366,12 +380,75 @@ module TurboTests
366
380
  rescue IOError
367
381
  break
368
382
  else
369
- dst.write(msg)
383
+ append_worker_output(process_id, stream, msg)
370
384
  end
371
385
  end
372
386
  end
373
387
  end
374
388
 
389
+ def append_worker_output(process_id, stream, msg)
390
+ return if msg.empty?
391
+
392
+ msg = msg.dup.force_encoding(Encoding::UTF_8).scrub
393
+ @worker_output_mutex.synchronize do
394
+ @worker_output[process_id][stream] << msg
395
+ end
396
+
397
+ io = (stream == :stderr) ? $stderr : $stdout
398
+ io.write(msg) if @verbose
399
+ end
400
+
401
+ def flush_worker_output
402
+ output_by_process = @worker_output_mutex.synchronize do
403
+ @worker_output.transform_values(&:dup)
404
+ end
405
+
406
+ output_by_process.each do |process_id, streams|
407
+ streams.each do |stream, output|
408
+ next if output.empty?
409
+
410
+ io = (stream == :stderr) ? $stderr : $stdout
411
+ io.puts
412
+ io.puts("TurboTests worker #{process_id} #{stream}:")
413
+ io.write(output)
414
+ io.puts unless output.end_with?("\n")
415
+ end
416
+ end
417
+ end
418
+
419
+ def flush_coverage_summary
420
+ line_coverage = nil
421
+ branch_coverage = nil
422
+ @worker_output_mutex.synchronize do
423
+ @worker_output.each_value do |streams|
424
+ streams.each_value do |output|
425
+ output.each_line do |line|
426
+ stripped = line.strip
427
+ line_coverage = coverage_line("Line", stripped, line_coverage)
428
+ branch_coverage = coverage_line("Branch", stripped, branch_coverage)
429
+ end
430
+ end
431
+ end
432
+ end
433
+
434
+ return unless line_coverage || branch_coverage
435
+
436
+ puts
437
+ puts("Coverage:")
438
+ puts(line_coverage) if line_coverage
439
+ puts(branch_coverage) if branch_coverage
440
+ end
441
+
442
+ def coverage_line(kind, line, current)
443
+ return line if line.start_with?("#{kind} Coverage:")
444
+ return current if current&.start_with?("#{kind} Coverage:")
445
+
446
+ match = line.match(/\A#{kind} coverage:\s*(\d+)\s*\/\s*(\d+)\s*\(([^)]+)\)\z/i)
447
+ return current unless match
448
+
449
+ "#{kind} Coverage: #{match[3]} (#{match[1]} / #{match[2]})"
450
+ end
451
+
375
452
  def stop_reader_thread(thread, io)
376
453
  return if thread.join(0.1)
377
454
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module TurboTests
4
4
  module Version
5
- VERSION = "3.1.7"
5
+ VERSION = "3.1.9"
6
6
  end
7
7
  VERSION = Version::VERSION # Traditional Constant Location
8
8
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbo_tests2
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.7
4
+ version: 3.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Illia
@@ -90,7 +90,7 @@ dependencies:
90
90
  version: '1.1'
91
91
  - - ">="
92
92
  - !ruby/object:Gem::Version
93
- version: 1.1.13
93
+ version: 1.1.14
94
94
  type: :runtime
95
95
  prerelease: false
96
96
  version_requirements: !ruby/object:Gem::Requirement
@@ -100,7 +100,7 @@ dependencies:
100
100
  version: '1.1'
101
101
  - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: 1.1.13
103
+ version: 1.1.14
104
104
  - !ruby/object:Gem::Dependency
105
105
  name: kettle-dev
106
106
  requirement: !ruby/object:Gem::Requirement
@@ -110,7 +110,7 @@ dependencies:
110
110
  version: '2.3'
111
111
  - - ">="
112
112
  - !ruby/object:Gem::Version
113
- version: 2.3.1
113
+ version: 2.3.4
114
114
  type: :development
115
115
  prerelease: false
116
116
  version_requirements: !ruby/object:Gem::Requirement
@@ -120,7 +120,7 @@ dependencies:
120
120
  version: '2.3'
121
121
  - - ">="
122
122
  - !ruby/object:Gem::Version
123
- version: 2.3.1
123
+ version: 2.3.4
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: bundler-audit
126
126
  requirement: !ruby/object:Gem::Requirement
@@ -232,7 +232,7 @@ dependencies:
232
232
  version: '1.0'
233
233
  - - ">="
234
234
  - !ruby/object:Gem::Version
235
- version: 1.0.5
235
+ version: 1.0.6
236
236
  type: :development
237
237
  prerelease: false
238
238
  version_requirements: !ruby/object:Gem::Requirement
@@ -242,7 +242,7 @@ dependencies:
242
242
  version: '1.0'
243
243
  - - ">="
244
244
  - !ruby/object:Gem::Version
245
- version: 1.0.5
245
+ version: 1.0.6
246
246
  - !ruby/object:Gem::Dependency
247
247
  name: gitmoji-regex
248
248
  requirement: !ruby/object:Gem::Requirement
@@ -312,10 +312,10 @@ licenses:
312
312
  - MIT
313
313
  metadata:
314
314
  homepage_uri: https://turbo-tests2.galtzo.com
315
- source_code_uri: https://github.com/galtzo-floss/turbo_tests2/tree/v3.1.7
316
- changelog_uri: https://github.com/galtzo-floss/turbo_tests2/blob/v3.1.7/CHANGELOG.md
315
+ source_code_uri: https://github.com/galtzo-floss/turbo_tests2/tree/v3.1.9
316
+ changelog_uri: https://github.com/galtzo-floss/turbo_tests2/blob/v3.1.9/CHANGELOG.md
317
317
  bug_tracker_uri: https://github.com/galtzo-floss/turbo_tests2/issues
318
- documentation_uri: https://www.rubydoc.info/gems/turbo_tests2/3.1.7
318
+ documentation_uri: https://www.rubydoc.info/gems/turbo_tests2/3.1.9
319
319
  funding_uri: https://github.com/sponsors/pboling
320
320
  wiki_uri: https://github.com/galtzo-floss/turbo_tests2/wiki
321
321
  news_uri: https://www.railsbling.com/tags/turbo_tests2
@@ -345,7 +345,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
345
345
  - !ruby/object:Gem::Version
346
346
  version: '0'
347
347
  requirements: []
348
- rubygems_version: 4.0.10
348
+ rubygems_version: 4.0.16
349
349
  specification_version: 4
350
350
  summary: "\U0001F680 RSpec parallel test runner built on `parallel_tests`, with incremental
351
351
  summarized output"
metadata.gz.sig CHANGED
Binary file