turbo_tests2 3.1.8 → 3.1.10

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: 896b2cd3a1a1e517516e76797c8a6a9783d1883d43a215086c165ecb72eea59c
4
- data.tar.gz: ce168afe9a512e7ab9d10cc165d034e2a9d0e8cbe735583ea0c4d7742134ff4b
3
+ metadata.gz: 1897469552c29056b84010fd5991b4465c76c41e1a66c6c1381dcf3ac88af695
4
+ data.tar.gz: cdbeee85dd4055a61a4202f721b0f394395bd91db75e5994d4e80590f37ddbe7
5
5
  SHA512:
6
- metadata.gz: 24ec7b6ddde8980013440ccdc0792ba033698470f73469dd726028778bcfc2afaf29e146c421ec924475b1937c2a7253e43bc8e193fb2cdd695ad953e3a009ad
7
- data.tar.gz: f26102397a81ae27a5518451a8be811d4346674e7b98c3cbfb692a45f58422ce5a2c4090bf3aa13d0a52d7000f654848295e37a3e0ef73987ddcc2383bd7a5e8
6
+ metadata.gz: ef33ca0fe4ebcc40e26195844a5d2a2cefa62c677f38e129b2b2fa407c6a8ecb904837ee4d2f3960e1edea7b03d289e4c12b6b619eb76970ea39fb992c920e8e
7
+ data.tar.gz: 83893ce9174430d692795cc45213c85bfcb159d35401279df0692b4072af6a54339ed9a79c533b191be6c2171cce51b0b8f5522cdaa85ce0e530a3d2545b32a8
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -28,11 +28,36 @@ Please file a bug if you notice a violation of semantic versioning.
28
28
 
29
29
  ### Fixed
30
30
 
31
+ ### Security
32
+
33
+ ## [3.1.10] - 2026-07-15
34
+
35
+ - TAG: [v3.1.10][3.1.10t]
36
+ - COVERAGE: 97.65% -- 706/723 lines in 10 files
37
+ - BRANCH COVERAGE: 88.95% -- 169/190 branches in 10 files
38
+ - 36.67% documented
39
+
40
+ ### Fixed
41
+
42
+ - No-argument runs now use RSpec configuration for file discovery, including
43
+ `.rspec` `--pattern` settings, instead of assuming a top-level `spec/`
44
+ directory.
45
+
46
+ ## [3.1.9] - 2026-07-14
47
+
48
+ - TAG: [v3.1.9][3.1.9t]
49
+ - COVERAGE: 97.60% -- 692/709 lines in 10 files
50
+ - BRANCH COVERAGE: 89.13% -- 164/184 branches in 10 files
51
+ - 37.08% documented
52
+
53
+ ### Fixed
54
+
55
+ - Buffered non-RSpec worker stdout/stderr so successful parallel runs no longer
56
+ leak interleaved coverage formatter output, while still reporting a single
57
+ concise coverage summary.
31
58
  - Prevented invalid UTF-8 bytes in worker output from crashing the parent
32
59
  runner on JRuby after the underlying RSpec examples pass.
33
60
 
34
- ### Security
35
-
36
61
  ## [3.1.8] - 2026-07-14
37
62
 
38
63
  - TAG: [v3.1.8][3.1.8t]
@@ -223,7 +248,11 @@ Please file a bug if you notice a violation of semantic versioning.
223
248
 
224
249
  - Initial release
225
250
 
226
- [Unreleased]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.1.8...HEAD
251
+ [Unreleased]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.1.10...HEAD
252
+ [3.1.10]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.1.9...v3.1.10
253
+ [3.1.10t]: https://github.com/galtzo-floss/turbo_tests2/releases/tag/v3.1.10
254
+ [3.1.9]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.1.8...v3.1.9
255
+ [3.1.9t]: https://github.com/galtzo-floss/turbo_tests2/releases/tag/v3.1.9
227
256
  [3.1.8]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.1.7...v3.1.8
228
257
  [3.1.8t]: https://github.com/galtzo-floss/turbo_tests2/releases/tag/v3.1.8
229
258
  [3.1.7]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.1.6...v3.1.7
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.723-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
@@ -142,7 +142,7 @@ module TurboTests
142
142
 
143
143
  invoke_rake_hook("setup")
144
144
 
145
- files = @argv.empty? ? ["spec"] : @argv
145
+ files = @argv.empty? ? nil : @argv
146
146
  parallel_options = {}
147
147
 
148
148
  exitstatus = TurboTests::Runner.run(
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "json"
4
4
  require "parallel_tests/rspec/runner"
5
+ require "rspec/core"
5
6
  require "tempfile"
6
7
 
7
8
  require_relative "../utils/hash_extension"
@@ -23,7 +24,8 @@ module TurboTests
23
24
  end
24
25
 
25
26
  def run(opts = {})
26
- files = opts[:files]
27
+ default_file_discovery = !opts.key?(:files) || opts[:files].nil?
28
+ files = default_file_discovery ? rspec_configured_files_to_run : opts[:files]
27
29
  formatters = opts[:formatters]
28
30
  tags = opts[:tags]
29
31
  parallel_options = opts[:parallel_options] || {}
@@ -41,7 +43,7 @@ module TurboTests
41
43
  print_failed_group = opts.fetch(:print_failed_group, false)
42
44
  nice = opts.fetch(:nice, false)
43
45
 
44
- use_runtime_info = files == ["spec"]
46
+ use_runtime_info = default_file_discovery
45
47
 
46
48
  if example_status_log
47
49
  runtime_log = runtime_log_from_example_status(example_status_log)
@@ -103,6 +105,16 @@ module TurboTests
103
105
  def generate_seed
104
106
  (Random.new_seed % 65_535).to_s
105
107
  end
108
+
109
+ def rspec_configured_files_to_run
110
+ configuration = RSpec::Core::Configuration.new
111
+ RSpec::Core::ConfigurationOptions.new([]).configure(configuration)
112
+ root = "#{Dir.pwd}/"
113
+ configuration.files_to_run.map do |path|
114
+ path = path.to_s
115
+ path.start_with?(root) ? path.delete_prefix(root) : path
116
+ end
117
+ end
106
118
  end
107
119
 
108
120
  def initialize(**opts)
@@ -135,16 +147,25 @@ module TurboTests
135
147
  @threads = []
136
148
  @wait_threads = []
137
149
  @exited_process_ids = []
150
+ @worker_output = Hash.new { |hash, process_id| hash[process_id] = {stdout: +"", stderr: +""} }
151
+ @worker_output_mutex = Mutex.new
138
152
  @error = false
139
153
  @print_failed_group = opts[:print_failed_group]
140
154
  end
141
155
 
142
156
  def run
157
+ tests_with_size = ParallelTests::RSpec::Runner.tests_with_size(@files, {})
143
158
  @num_processes = [
144
159
  ParallelTests.determine_number_of_processes(@count),
145
- ParallelTests::RSpec::Runner.tests_with_size(@files, {}).size
160
+ tests_with_size.size
146
161
  ].min
147
162
 
163
+ if @num_processes.zero?
164
+ @tests_in_groups = []
165
+ @reporter.report([]) { |_reporter| }
166
+ return 0
167
+ end
168
+
148
169
  tests_in_groups =
149
170
  ParallelTests::RSpec::Runner.tests_in_groups(
150
171
  @files,
@@ -158,6 +179,9 @@ module TurboTests
158
179
  }
159
180
 
160
181
  ParallelTests.with_pid_file do
182
+ exit_status = nil
183
+ report_coverage = false
184
+
161
185
  @reporter.report(tests_in_groups) do |_reporter|
162
186
  old_signal = Signal.trap(:INT) { handle_interrupt }
163
187
 
@@ -174,13 +198,20 @@ module TurboTests
174
198
 
175
199
  Signal.trap(:INT, old_signal)
176
200
 
177
- if @reporter.failed_examples.empty? && @wait_threads.map(&:value).all?(&:success?)
178
- 0
201
+ statuses = @wait_threads.map(&:value)
202
+
203
+ if @reporter.failed_examples.empty? && statuses.all?(&:success?)
204
+ report_coverage = true
205
+ exit_status = 0
179
206
  else
207
+ flush_worker_output
180
208
  # From https://github.com/galtzo-floss/turbo_tests2/pull/20/
181
- @wait_threads.map { |thread| thread.value.exitstatus }.max
209
+ exit_status = statuses.map(&:exitstatus).max
182
210
  end
183
211
  end
212
+
213
+ flush_coverage_summary if report_coverage
214
+ exit_status
184
215
  end
185
216
  end
186
217
 
@@ -302,7 +333,7 @@ module TurboTests
302
333
  result = line.b.split(output_id)
303
334
 
304
335
  initial = result.shift
305
- print(initial) unless initial.empty?
336
+ append_worker_output(process_id, :stdout, initial) unless initial.empty?
306
337
 
307
338
  message = result.shift
308
339
  next unless message
@@ -322,14 +353,14 @@ module TurboTests
322
353
  # rubocop:enable ThreadSafety/NewThread
323
354
  @threads << stdout_thread
324
355
 
325
- stderr_thread = start_copy_thread(stderr, $stderr)
356
+ stderr_thread = start_copy_thread(stderr, process_id, :stderr)
326
357
  @threads << stderr_thread
327
358
 
328
359
  # rubocop:disable ThreadSafety/NewThread
329
360
  @threads << Thread.new do
330
361
  begin
331
362
  status = wait_thr.value
332
- @messages << {type: "error"} unless status.success?
363
+ @messages << {type: "error", process_id: process_id} unless status.success?
333
364
  @messages << {type: "exit", process_id: process_id}
334
365
  ensure
335
366
  stop_reader_thread(stdout_thread, stdout)
@@ -355,7 +386,7 @@ module TurboTests
355
386
  ParallelTests::Pids.new(pid_file_path).delete(pid) if pid && pid_file_path
356
387
  end
357
388
 
358
- def start_copy_thread(src, dst)
389
+ def start_copy_thread(src, process_id, stream)
359
390
  # rubocop:disable ThreadSafety/NewThread
360
391
  Thread.new do
361
392
  # rubocop:enable ThreadSafety/NewThread
@@ -368,10 +399,73 @@ module TurboTests
368
399
  rescue IOError
369
400
  break
370
401
  else
371
- dst.write(msg)
402
+ append_worker_output(process_id, stream, msg)
403
+ end
404
+ end
405
+ end
406
+ end
407
+
408
+ def append_worker_output(process_id, stream, msg)
409
+ return if msg.empty?
410
+
411
+ msg = msg.dup.force_encoding(Encoding::UTF_8).scrub
412
+ @worker_output_mutex.synchronize do
413
+ @worker_output[process_id][stream] << msg
414
+ end
415
+
416
+ io = (stream == :stderr) ? $stderr : $stdout
417
+ io.write(msg) if @verbose
418
+ end
419
+
420
+ def flush_worker_output
421
+ output_by_process = @worker_output_mutex.synchronize do
422
+ @worker_output.transform_values(&:dup)
423
+ end
424
+
425
+ output_by_process.each do |process_id, streams|
426
+ streams.each do |stream, output|
427
+ next if output.empty?
428
+
429
+ io = (stream == :stderr) ? $stderr : $stdout
430
+ io.puts
431
+ io.puts("TurboTests worker #{process_id} #{stream}:")
432
+ io.write(output)
433
+ io.puts unless output.end_with?("\n")
434
+ end
435
+ end
436
+ end
437
+
438
+ def flush_coverage_summary
439
+ line_coverage = nil
440
+ branch_coverage = nil
441
+ @worker_output_mutex.synchronize do
442
+ @worker_output.each_value do |streams|
443
+ streams.each_value do |output|
444
+ output.each_line do |line|
445
+ stripped = line.strip
446
+ line_coverage = coverage_line("Line", stripped, line_coverage)
447
+ branch_coverage = coverage_line("Branch", stripped, branch_coverage)
448
+ end
372
449
  end
373
450
  end
374
451
  end
452
+
453
+ return unless line_coverage || branch_coverage
454
+
455
+ puts
456
+ puts("Coverage:")
457
+ puts(line_coverage) if line_coverage
458
+ puts(branch_coverage) if branch_coverage
459
+ end
460
+
461
+ def coverage_line(kind, line, current)
462
+ return line if line.start_with?("#{kind} Coverage:")
463
+ return current if current&.start_with?("#{kind} Coverage:")
464
+
465
+ match = line.match(/\A#{kind} coverage:\s*(\d+)\s*\/\s*(\d+)\s*\(([^)]+)\)\z/i)
466
+ return current unless match
467
+
468
+ "#{kind} Coverage: #{match[3]} (#{match[1]} / #{match[2]})"
375
469
  end
376
470
 
377
471
  def stop_reader_thread(thread, io)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module TurboTests
4
4
  module Version
5
- VERSION = "3.1.8"
5
+ VERSION = "3.1.10"
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.8
4
+ version: 3.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Illia
@@ -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.8
316
- changelog_uri: https://github.com/galtzo-floss/turbo_tests2/blob/v3.1.8/CHANGELOG.md
315
+ source_code_uri: https://github.com/galtzo-floss/turbo_tests2/tree/v3.1.10
316
+ changelog_uri: https://github.com/galtzo-floss/turbo_tests2/blob/v3.1.10/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.8
318
+ documentation_uri: https://www.rubydoc.info/gems/turbo_tests2/3.1.10
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
metadata.gz.sig CHANGED
Binary file