test-unit-ruby-core 1.0.7 → 1.0.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: 2fbe8678b64c96aecfb825b2a2544e7089a681be164521d259880d07e5cf0589
4
- data.tar.gz: 2726f59cb0cf549b49a1250d11324fe26f2eb93eb685740086bed65491b3f00f
3
+ metadata.gz: 3c827aeceb3fd1980fbc22e68e631c888f61852201f5a71d222137dccec7813e
4
+ data.tar.gz: f39f342ed03b29005052935840fca12eef139092dc6a9f30d53621e3947fa8d4
5
5
  SHA512:
6
- metadata.gz: 3880a3106697e03f423822c456d1753755078378106d0e4bbfc7a2bbe7305a4860897aae9716dd77ab33a7b9503ef484beaa9a06bcdabd4bfa72f3036a191582
7
- data.tar.gz: 9626368354be4eecb5c13a0d0fac687cd2c0ad8179315e899f1d27d564cd95b958ef07eea561d98102d362c56b49a08fac761c1e1dce7045afd7f84006aeddd3
6
+ metadata.gz: 38241758387cdd981ea6864ecab402c39d725ad38aea3b27835f73037c856a9a6c4b0792f671696d07f4ec9bfcf909d5c53a3dca31cd3076eb166d74d66e633d
7
+ data.tar.gz: 03e2d05f411ba5ccd86b1a82cb0aead6766ad13150a51c7d543d9a7fe266931c7744a562cce85f12a6c9c90317e481fdba70f7fd8a9d1a3ab30a815db5c85adb
@@ -97,11 +97,12 @@ module Test
97
97
  end
98
98
 
99
99
  def assert_in_out_err(args, test_stdin = "", test_stdout = [], test_stderr = [], message = nil,
100
- success: nil, **opt)
100
+ success: nil, failed: nil, **opt)
101
101
  args = Array(args).dup
102
102
  args.insert((Hash === args[0] ? 1 : 0), '--disable=gems')
103
103
  stdout, stderr, status = EnvUtil.invoke_ruby(args, test_stdin, true, true, **opt)
104
- desc = FailDesc[status, message, stderr]
104
+ desc = failed[status, message, stderr] if failed
105
+ desc ||= FailDesc[status, message, stderr]
105
106
  if block_given?
106
107
  raise "test_stdout ignored, use block only or without block" if test_stdout != []
107
108
  raise "test_stderr ignored, use block only or without block" if test_stderr != []
@@ -495,14 +496,13 @@ eom
495
496
  case expected
496
497
  when String
497
498
  assert = :assert_equal
498
- when Regexp
499
- assert = :assert_match
500
499
  else
501
- raise TypeError, "Expected #{expected.inspect} to be a kind of String or Regexp, not #{expected.class}"
500
+ assert_respond_to(expected, :===)
501
+ assert = :assert_match
502
502
  end
503
503
 
504
504
  ex = m = nil
505
- EnvUtil.with_default_internal(expected.encoding) do
505
+ EnvUtil.with_default_internal(of: expected) do
506
506
  ex = assert_raise(exception, msg || proc {"Exception(#{exception}) with message matches to #{expected.inspect}"}) do
507
507
  yield
508
508
  end
@@ -520,6 +520,43 @@ eom
520
520
  ex
521
521
  end
522
522
 
523
+ # :call-seq:
524
+ # assert_raise_kind_of(*args, &block)
525
+ #
526
+ #Tests if the given block raises one of the given exceptions or
527
+ #sub exceptions of the given exceptions. If the last argument
528
+ #is a String, it will be used as the error message.
529
+ #
530
+ # assert_raise do #Fails, no Exceptions are raised
531
+ # end
532
+ #
533
+ # assert_raise SystemCallErr do
534
+ # Dir.chdir(__FILE__) #Raises Errno::ENOTDIR, so assertion succeeds
535
+ # end
536
+ def assert_raise_kind_of(*exp, &b)
537
+ case exp.last
538
+ when String, Proc
539
+ msg = exp.pop
540
+ end
541
+
542
+ begin
543
+ yield
544
+ rescue Test::Unit::PendedError => e
545
+ raise e unless exp.include? Test::Unit::PendedError
546
+ rescue *exp => e
547
+ pass
548
+ rescue Exception => e
549
+ flunk(message(msg) {"#{mu_pp(exp)} family exception expected, not #{mu_pp(e)}"})
550
+ ensure
551
+ unless e
552
+ exp = exp.first if exp.size == 1
553
+
554
+ flunk(message(msg) {"#{mu_pp(exp)} family expected but nothing was raised"})
555
+ end
556
+ end
557
+ e
558
+ end
559
+
523
560
  TEST_DIR = File.join(__dir__, "test/unit") #:nodoc:
524
561
 
525
562
  # :call-seq:
@@ -639,7 +676,7 @@ eom
639
676
 
640
677
  def assert_warning(pat, msg = nil)
641
678
  result = nil
642
- stderr = EnvUtil.with_default_internal(pat.encoding) {
679
+ stderr = EnvUtil.with_default_internal(of: pat) {
643
680
  EnvUtil.verbose_warning {
644
681
  result = yield
645
682
  }
@@ -653,17 +690,15 @@ eom
653
690
  assert_warning(*args) {$VERBOSE = false; yield}
654
691
  end
655
692
 
656
- def assert_deprecated_warning(mesg = /deprecated/)
693
+ def assert_deprecated_warning(mesg = /deprecated/, &block)
657
694
  assert_warning(mesg) do
658
- Warning[:deprecated] = true if Warning.respond_to?(:[]=)
659
- yield
695
+ EnvUtil.deprecation_warning(&block)
660
696
  end
661
697
  end
662
698
 
663
- def assert_deprecated_warn(mesg = /deprecated/)
699
+ def assert_deprecated_warn(mesg = /deprecated/, &block)
664
700
  assert_warn(mesg) do
665
- Warning[:deprecated] = true if Warning.respond_to?(:[]=)
666
- yield
701
+ EnvUtil.deprecation_warning(&block)
667
702
  end
668
703
  end
669
704
 
@@ -867,6 +902,82 @@ eom
867
902
  token = "\e[7;1m#{$$.to_s}:#{Time.now.strftime('%s.%L')}:#{rand(0x10000).to_s(16)}:\e[m"
868
903
  return token.dump, Regexp.quote(token)
869
904
  end
905
+
906
+ # Platform predicates
907
+
908
+ def self.mswin?
909
+ defined?(@mswin) ? @mswin : @mswin = RUBY_PLATFORM.include?('mswin')
910
+ end
911
+ private def mswin?
912
+ CoreAssertions.mswin?
913
+ end
914
+
915
+ def self.mingw?
916
+ defined?(@mingw) ? @mingw : @mingw = RUBY_PLATFORM.include?('mingw')
917
+ end
918
+ private def mingw?
919
+ CoreAssertions.mingw?
920
+ end
921
+
922
+ module_function def windows?
923
+ mswin? or mingw?
924
+ end
925
+
926
+ def self.version_compare(expected, actual)
927
+ expected.zip(actual).each {|e, a| z = (e <=> a); return z if z.nonzero?}
928
+ 0
929
+ end
930
+
931
+ def self.version_match?(expected, actual)
932
+ if !actual
933
+ false
934
+ elsif expected.empty?
935
+ true
936
+ elsif expected.size == 1 and Range === (range = expected.first)
937
+ b, e = range.begin, range.end
938
+ return false if b and (c = version_compare(Array(b), actual)) > 0
939
+ return false if e and (c = version_compare(Array(e), actual)) < 0
940
+ return false if e and range.exclude_end? and c == 0
941
+ true
942
+ else
943
+ version_compare(expected, actual).zero?
944
+ end
945
+ end
946
+
947
+ def self.linux?(*ver)
948
+ unless defined?(@linux)
949
+ @linux = RUBY_PLATFORM.include?('linux') && `uname -r`.scan(/\d+/).map(&:to_i)
950
+ end
951
+ version_match? ver, @linux
952
+ end
953
+ private def linux?(*ver)
954
+ CoreAssertions.linux?(*ver)
955
+ end
956
+
957
+ def self.glibc?(*ver)
958
+ unless defined?(@glibc)
959
+ libc = `/usr/bin/ldd /bin/sh`[/^\s*libc.*=> *\K\S*/]
960
+ if libc and /version (\d+)\.(\d+)\.$/ =~ IO.popen([libc], &:read)[]
961
+ @glibc = [$1.to_i, $2.to_i]
962
+ else
963
+ @glibc = false
964
+ end
965
+ end
966
+ version_match? ver, @glibc
967
+ end
968
+ private def glibc?(*ver)
969
+ CoreAssertions.glibc?(*ver)
970
+ end
971
+
972
+ def self.macos?(*ver)
973
+ unless defined?(@macos)
974
+ @macos = RUBY_PLATFORM.include?('darwin') && `sw_vers -productVersion`.scan(/\d+/).map(&:to_i)
975
+ end
976
+ version_match? ver, @macos
977
+ end
978
+ private def macos?(*ver)
979
+ CoreAssertions.macos?(*ver)
980
+ end
870
981
  end
871
982
  end
872
983
  end
data/lib/envutil.rb CHANGED
@@ -79,6 +79,70 @@ module EnvUtil
79
79
  end
80
80
  module_function :timeout
81
81
 
82
+ class Debugger
83
+ @list = []
84
+
85
+ attr_accessor :name
86
+
87
+ def self.register(name, &block)
88
+ @list << new(name, &block)
89
+ end
90
+
91
+ def initialize(name, &block)
92
+ @name = name
93
+ instance_eval(&block)
94
+ end
95
+
96
+ def usable?; false; end
97
+
98
+ def start(pid, *args) end
99
+
100
+ def dump(pid, timeout: 60, reprieve: timeout&.div(4))
101
+ dpid = start(pid, *command_file(File.join(__dir__, "dump.#{name}")), out: :err)
102
+ rescue Errno::ENOENT
103
+ return
104
+ else
105
+ return unless dpid
106
+ [[timeout, :TERM], [reprieve, :KILL]].find do |t, sig|
107
+ return EnvUtil.timeout(t) {Process.wait(dpid)}
108
+ rescue Timeout::Error
109
+ Process.kill(sig, dpid)
110
+ end
111
+ true
112
+ end
113
+
114
+ # sudo -n: --non-interactive
115
+ PRECOMMAND = (%[sudo -n] if /darwin/ =~ RUBY_PLATFORM)
116
+
117
+ def spawn(*args, **opts)
118
+ super(*PRECOMMAND, *args, **opts)
119
+ end
120
+
121
+ register("gdb") do
122
+ class << self
123
+ def usable?; system(*%w[gdb --batch --quiet --nx -ex exit]); end
124
+ def start(pid, *args, **opts)
125
+ spawn(*%W[gdb --batch --quiet --pid #{pid}], *args, **opts)
126
+ end
127
+ def command_file(file) "--command=#{file}"; end
128
+ end
129
+ end
130
+
131
+ register("lldb") do
132
+ class << self
133
+ def usable?; system(*%w[lldb -Q --no-lldbinit -o exit]); end
134
+ def start(pid, *args, **opts)
135
+ spawn(*%W[lldb --batch -Q --attach-pid #{pid}], *args, **opts)
136
+ end
137
+ def command_file(file) ["--source", file]; end
138
+ end
139
+ end
140
+
141
+ def self.search
142
+ @debugger ||= @list.find(&:usable?)
143
+ end
144
+ end
145
+
82
146
  def terminate(pid, signal = :TERM, pgroup = nil, reprieve = 1)
83
147
  reprieve = apply_timeout_scale(reprieve) if reprieve
84
148
 
@@ -94,17 +158,12 @@ module EnvUtil
94
158
  pgroup = pid
95
159
  end
96
160
 
97
- lldb = true if /darwin/ =~ RUBY_PLATFORM
98
-
161
+ dumped = false
99
162
  while signal = signals.shift
100
163
 
101
- if lldb and [:ABRT, :KILL].include?(signal)
102
- lldb = false
103
- # sudo -n: --non-interactive
104
- # lldb -p: attach
105
- # -o: run command
106
- system(*%W[sudo -n lldb -p #{pid} --batch -o bt\ all -o call\ rb_vmdebug_stack_dump_all_threads() -o quit])
107
- true
164
+ if !dumped and [:ABRT, :KILL].include?(signal)
165
+ Debugger.search&.dump(pid)
166
+ dumped = true
108
167
  end
109
168
 
110
169
  begin
@@ -165,6 +224,11 @@ module EnvUtil
165
224
  }
166
225
 
167
226
  args = [args] if args.kind_of?(String)
227
+ # use the same parser as current ruby
228
+ if (args.none? { |arg| arg.start_with?("--parser=") } and
229
+ /^ +--parser=/ =~ IO.popen([rubybin, "--help"], &:read))
230
+ args = ["--parser=#{current_parser}"] + args
231
+ end
168
232
  pid = spawn(child_env, *precommand, rubybin, *args, opt)
169
233
  in_c.close
170
234
  out_c&.close
@@ -212,6 +276,12 @@ module EnvUtil
212
276
  end
213
277
  module_function :invoke_ruby
214
278
 
279
+ def current_parser
280
+ features = RUBY_DESCRIPTION[%r{\)\K [-+*/%._0-9a-zA-Z ]*(?=\[[-+*/%._0-9a-zA-Z]+\]\z)}]
281
+ features&.split&.include?("+PRISM") ? "prism" : "parse.y"
282
+ end
283
+ module_function :current_parser
284
+
215
285
  def verbose_warning
216
286
  class << (stderr = "".dup)
217
287
  alias write concat
@@ -228,6 +298,21 @@ module EnvUtil
228
298
  end
229
299
  module_function :verbose_warning
230
300
 
301
+ if defined?(Warning.[]=)
302
+ def deprecation_warning
303
+ previous_deprecated = Warning[:deprecated]
304
+ Warning[:deprecated] = true
305
+ yield
306
+ ensure
307
+ Warning[:deprecated] = previous_deprecated
308
+ end
309
+ else
310
+ def deprecation_warning
311
+ yield
312
+ end
313
+ end
314
+ module_function :deprecation_warning
315
+
231
316
  def default_warning
232
317
  $VERBOSE = false
233
318
  yield
@@ -254,11 +339,15 @@ module EnvUtil
254
339
 
255
340
  def under_gc_compact_stress(val = :empty, &block)
256
341
  raise "compaction doesn't work well on s390x. Omit the test in the caller." if RUBY_PLATFORM =~ /s390x/ # https://github.com/ruby/ruby/pull/5077
257
- auto_compact = GC.auto_compact
258
- GC.auto_compact = val
342
+
343
+ if GC.respond_to?(:auto_compact)
344
+ auto_compact = GC.auto_compact
345
+ GC.auto_compact = val
346
+ end
347
+
259
348
  under_gc_stress(&block)
260
349
  ensure
261
- GC.auto_compact = auto_compact
350
+ GC.auto_compact = auto_compact if GC.respond_to?(:auto_compact)
262
351
  end
263
352
  module_function :under_gc_compact_stress
264
353
 
@@ -270,7 +359,8 @@ module EnvUtil
270
359
  end
271
360
  module_function :without_gc
272
361
 
273
- def with_default_external(enc)
362
+ def with_default_external(enc = nil, of: nil)
363
+ enc = of.encoding if defined?(of.encoding)
274
364
  suppress_warning { Encoding.default_external = enc }
275
365
  yield
276
366
  ensure
@@ -278,7 +368,8 @@ module EnvUtil
278
368
  end
279
369
  module_function :with_default_external
280
370
 
281
- def with_default_internal(enc)
371
+ def with_default_internal(enc = nil, of: nil)
372
+ enc = of.encoding if defined?(of.encoding)
282
373
  suppress_warning { Encoding.default_internal = enc }
283
374
  yield
284
375
  ensure
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+ begin
3
+ require '-test-/memory_status.so'
4
+ rescue LoadError
5
+ end
6
+
7
+ module Memory
8
+ keys = []
9
+
10
+ case
11
+ when File.exist?(procfile = "/proc/self/status") && (pat = /^Vm(\w+):\s+(\d+)/) =~ (data = File.binread(procfile))
12
+ PROC_FILE = procfile
13
+ VM_PAT = pat
14
+ def self.read_status
15
+ File.foreach(PROC_FILE, encoding: Encoding::ASCII_8BIT) do |l|
16
+ yield($1.downcase.intern, $2.to_i * 1024) if VM_PAT =~ l
17
+ end
18
+ end
19
+
20
+ data.scan(pat) {|k, v| keys << k.downcase.intern}
21
+
22
+ when /mswin|mingw/ =~ RUBY_PLATFORM
23
+ keys.push(:size, :rss, :peak)
24
+
25
+ begin
26
+ require 'fiddle/import'
27
+ require 'fiddle/types'
28
+ rescue LoadError
29
+ # Fallback to PowerShell command to get memory information for current process
30
+ def self.read_status
31
+ cmd = [
32
+ "powershell.exe", "-NoProfile", "-Command",
33
+ "Get-Process -Id #{$$} | " \
34
+ "% { Write-Output $_.PagedMemorySize64 $_.WorkingSet64 $_.PeakWorkingSet64 }"
35
+ ]
36
+
37
+ IO.popen(cmd, "r", err: [:child, :out]) do |out|
38
+ if /^(\d+)\n(\d+)\n(\d+)$/ =~ out.read
39
+ yield :size, $1.to_i
40
+ yield :rss, $2.to_i
41
+ yield :peak, $3.to_i
42
+ end
43
+ end
44
+ end
45
+ else
46
+ module Win32
47
+ extend Fiddle::Importer
48
+ dlload "kernel32.dll", "psapi.dll"
49
+ include Fiddle::Win32Types
50
+ typealias "SIZE_T", "size_t"
51
+
52
+ PROCESS_MEMORY_COUNTERS = struct [
53
+ "DWORD cb",
54
+ "DWORD PageFaultCount",
55
+ "SIZE_T PeakWorkingSetSize",
56
+ "SIZE_T WorkingSetSize",
57
+ "SIZE_T QuotaPeakPagedPoolUsage",
58
+ "SIZE_T QuotaPagedPoolUsage",
59
+ "SIZE_T QuotaPeakNonPagedPoolUsage",
60
+ "SIZE_T QuotaNonPagedPoolUsage",
61
+ "SIZE_T PagefileUsage",
62
+ "SIZE_T PeakPagefileUsage",
63
+ ]
64
+
65
+ typealias "PPROCESS_MEMORY_COUNTERS", "PROCESS_MEMORY_COUNTERS*"
66
+
67
+ extern "HANDLE GetCurrentProcess()", :stdcall
68
+ extern "BOOL GetProcessMemoryInfo(HANDLE, PPROCESS_MEMORY_COUNTERS, DWORD)", :stdcall
69
+
70
+ module_function
71
+ def memory_info
72
+ size = PROCESS_MEMORY_COUNTERS.size
73
+ data = PROCESS_MEMORY_COUNTERS.malloc
74
+ data.cb = size
75
+ data if GetProcessMemoryInfo(GetCurrentProcess(), data, size)
76
+ end
77
+ end
78
+
79
+ def self.read_status
80
+ if info = Win32.memory_info
81
+ yield :size, info.PagefileUsage
82
+ yield :rss, info.WorkingSetSize
83
+ yield :peak, info.PeakWorkingSetSize
84
+ end
85
+ end
86
+ end
87
+ when (require_relative 'find_executable'
88
+ pat = /^\s*(\d+)\s+(\d+)$/
89
+ pscmd = EnvUtil.find_executable("ps", "-ovsz=", "-orss=", "-p", $$.to_s) {|out| pat =~ out})
90
+ pscmd.pop
91
+ PAT = pat
92
+ PSCMD = pscmd
93
+
94
+ keys << :size << :rss
95
+ def self.read_status
96
+ if PAT =~ IO.popen(PSCMD + [$$.to_s], "r", err: [:child, :out], &:read)
97
+ yield :size, $1.to_i*1024
98
+ yield :rss, $2.to_i*1024
99
+ end
100
+ end
101
+ else
102
+ def self.read_status
103
+ raise NotImplementedError, "unsupported platform"
104
+ end
105
+ end
106
+
107
+ if !keys.empty?
108
+ Status = Struct.new(*keys)
109
+ end
110
+ end unless defined?(Memory::Status)
111
+
112
+ if defined?(Memory::Status)
113
+ class Memory::Status
114
+ def _update
115
+ Memory.read_status do |key, val|
116
+ self[key] = val
117
+ end
118
+ self
119
+ end unless method_defined?(:_update)
120
+
121
+ Header = members.map {|k| k.to_s.upcase.rjust(6)}.join('')
122
+ Format = "%6d"
123
+
124
+ def initialize
125
+ _update
126
+ end
127
+
128
+ def to_s
129
+ status = each_pair.map {|n,v|
130
+ "#{n}:#{v}"
131
+ }
132
+ "{#{status.join(",")}}"
133
+ end
134
+
135
+ def self.parse(str)
136
+ status = allocate
137
+ str.scan(/(?:\A\{|\G,)(#{members.join('|')}):(\d+)(?=,|\}\z)/) do
138
+ status[$1] = $2.to_i
139
+ end
140
+ status
141
+ end
142
+ end
143
+
144
+ # On some platforms (e.g. Solaris), libc malloc does not return
145
+ # freed memory to OS because of efficiency, and linking with extra
146
+ # malloc library is needed to detect memory leaks.
147
+ #
148
+ case RUBY_PLATFORM
149
+ when /solaris2\.(?:9|[1-9][0-9])/i # Solaris 9, 10, 11,...
150
+ bits = [nil].pack('p').size == 8 ? 64 : 32
151
+ if ENV['LD_PRELOAD'].to_s.empty? &&
152
+ ENV["LD_PRELOAD_#{bits}"].to_s.empty? &&
153
+ (ENV['UMEM_OPTIONS'].to_s.empty? ||
154
+ ENV['UMEM_OPTIONS'] == 'backend=mmap') then
155
+ envs = {
156
+ 'LD_PRELOAD' => 'libumem.so',
157
+ 'UMEM_OPTIONS' => 'backend=mmap'
158
+ }
159
+ args = [
160
+ envs,
161
+ "--disable=gems",
162
+ "-v", "-",
163
+ ]
164
+ _, err, status = EnvUtil.invoke_ruby(args, "exit(0)", true, true)
165
+ if status.exitstatus == 0 && err.to_s.empty? then
166
+ Memory::NO_MEMORY_LEAK_ENVS = envs
167
+ end
168
+ end
169
+ end #case RUBY_PLATFORM
170
+
171
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test-unit-ruby-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hiroshi SHIBATA
8
8
  - Nobu Nakada
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2025-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: test-unit
@@ -35,6 +35,7 @@ files:
35
35
  - lib/core_assertions.rb
36
36
  - lib/envutil.rb
37
37
  - lib/find_executable.rb
38
+ - lib/memory_status.rb
38
39
  homepage: https://github.com/ruby/test-unit-ruby-core
39
40
  licenses:
40
41
  - Ruby
@@ -56,7 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
56
57
  - !ruby/object:Gem::Version
57
58
  version: '0'
58
59
  requirements: []
59
- rubygems_version: 3.7.0.dev
60
+ rubygems_version: 3.6.7
60
61
  specification_version: 4
61
62
  summary: Additional test assertions for Ruby standard libraries.
62
63
  test_files: []