Skip to content

Commit afb09e9

Browse files
authored
Merge pull request #42 from nobu/update-testlib
Update test/lib
2 parents ba3bd6f + 84e39f3 commit afb09e9

File tree

11 files changed

+847
-540
lines changed

11 files changed

+847
-540
lines changed

test/lib/colorize.rb

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# frozen-string-literal: true
2+
3+
class Colorize
4+
def initialize(color = nil, opts = ((_, color = color, nil)[0] if Hash === color))
5+
@colors = @reset = nil
6+
if color or (color == nil && STDOUT.tty?)
7+
if (/\A\e\[.*m\z/ =~ IO.popen("tput smso", "r", :err => IO::NULL, &:read) rescue nil)
8+
@beg = "\e["
9+
colors = (colors = ENV['TEST_COLORS']) ? Hash[colors.scan(/(\w+)=([^:\n]*)/)] : {}
10+
if opts and colors_file = opts[:colors_file]
11+
begin
12+
File.read(colors_file).scan(/(\w+)=([^:\n]*)/) do |n, c|
13+
colors[n] ||= c
14+
end
15+
rescue Errno::ENOENT
16+
end
17+
end
18+
@colors = colors
19+
@reset = "#{@beg}m"
20+
end
21+
end
22+
self
23+
end
24+
25+
DEFAULTS = {
26+
"pass"=>"32", "fail"=>"31;1", "skip"=>"33;1",
27+
"black"=>"30", "red"=>"31", "green"=>"32", "yellow"=>"33",
28+
"blue"=>"34", "magenta"=>"35", "cyan"=>"36", "white"=>"37",
29+
"bold"=>"1", "underline"=>"4", "reverse"=>"7",
30+
}
31+
32+
def decorate(str, name)
33+
if @colors and color = (@colors[name] || DEFAULTS[name])
34+
"#{@beg}#{color}m#{str}#{@reset}"
35+
else
36+
str
37+
end
38+
end
39+
40+
DEFAULTS.each_key do |name|
41+
define_method(name) {|str|
42+
decorate(str, name)
43+
}
44+
end
45+
end
46+
47+
if $0 == __FILE__
48+
colorize = Colorize.new
49+
col = ARGV.shift
50+
ARGV.each {|str| puts colorize.decorate(str, col)}
51+
end

test/lib/envutil.rb

Lines changed: 122 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: us-ascii -*-
2-
# frozen_string_literal: false
2+
# frozen_string_literal: true
33
require "open3"
44
require "timeout"
55
require_relative "find_executable"
@@ -42,20 +42,79 @@ def rubybin
4242
DEFAULT_SIGNALS = Signal.list
4343
DEFAULT_SIGNALS.delete("TERM") if /mswin|mingw/ =~ RUBY_PLATFORM
4444

45+
RUBYLIB = ENV["RUBYLIB"]
46+
4547
class << self
46-
attr_accessor :subprocess_timeout_scale
48+
attr_accessor :timeout_scale
49+
attr_reader :original_internal_encoding, :original_external_encoding,
50+
:original_verbose
51+
52+
def capture_global_values
53+
@original_internal_encoding = Encoding.default_internal
54+
@original_external_encoding = Encoding.default_external
55+
@original_verbose = $VERBOSE
56+
end
57+
end
58+
59+
def apply_timeout_scale(t)
60+
if scale = EnvUtil.timeout_scale
61+
t * scale
62+
else
63+
t
64+
end
65+
end
66+
module_function :apply_timeout_scale
67+
68+
def timeout(sec, klass = nil, message = nil, &blk)
69+
return yield(sec) if sec == nil or sec.zero?
70+
sec = apply_timeout_scale(sec)
71+
Timeout.timeout(sec, klass, message, &blk)
72+
end
73+
module_function :timeout
74+
75+
def terminate(pid, signal = :TERM, pgroup = nil, reprieve = 1)
76+
reprieve = apply_timeout_scale(reprieve) if reprieve
77+
78+
signals = Array(signal).select do |sig|
79+
DEFAULT_SIGNALS[sig.to_s] or
80+
DEFAULT_SIGNALS[Signal.signame(sig)] rescue false
81+
end
82+
signals |= [:ABRT, :KILL]
83+
case pgroup
84+
when 0, true
85+
pgroup = -pid
86+
when nil, false
87+
pgroup = pid
88+
end
89+
while signal = signals.shift
90+
begin
91+
Process.kill signal, pgroup
92+
rescue Errno::EINVAL
93+
next
94+
rescue Errno::ESRCH
95+
break
96+
end
97+
if signals.empty? or !reprieve
98+
Process.wait(pid)
99+
else
100+
begin
101+
Timeout.timeout(reprieve) {Process.wait(pid)}
102+
rescue Timeout::Error
103+
end
104+
end
105+
end
106+
$?
47107
end
108+
module_function :terminate
48109

49110
def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr = false,
50111
encoding: nil, timeout: 10, reprieve: 1, timeout_error: Timeout::Error,
51112
stdout_filter: nil, stderr_filter: nil,
52113
signal: :TERM,
53-
rubybin: EnvUtil.rubybin,
114+
rubybin: EnvUtil.rubybin, precommand: nil,
54115
**opt)
55-
if scale = EnvUtil.subprocess_timeout_scale
56-
timeout *= scale if timeout
57-
reprieve *= scale if reprieve
58-
end
116+
timeout = apply_timeout_scale(timeout)
117+
59118
in_c, in_p = IO.pipe
60119
out_p, out_c = IO.pipe if capture_stdout
61120
err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout
@@ -72,8 +131,11 @@ def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr =
72131
if Array === args and Hash === args.first
73132
child_env.update(args.shift)
74133
end
134+
if RUBYLIB and lib = child_env["RUBYLIB"]
135+
child_env["RUBYLIB"] = [lib, RUBYLIB].join(File::PATH_SEPARATOR)
136+
end
75137
args = [args] if args.kind_of?(String)
76-
pid = spawn(child_env, rubybin, *args, **opt)
138+
pid = spawn(child_env, *precommand, rubybin, *args, **opt)
77139
in_c.close
78140
out_c.close if capture_stdout
79141
err_c.close if capture_stderr && capture_stderr != :merge_to_stdout
@@ -87,35 +149,8 @@ def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr =
87149
if (!th_stdout || th_stdout.join(timeout)) && (!th_stderr || th_stderr.join(timeout))
88150
timeout_error = nil
89151
else
90-
signals = Array(signal).select do |sig|
91-
DEFAULT_SIGNALS[sig.to_s] or
92-
DEFAULT_SIGNALS[Signal.signame(sig)] rescue false
93-
end
94-
signals |= [:ABRT, :KILL]
95-
case pgroup = opt[:pgroup]
96-
when 0, true
97-
pgroup = -pid
98-
when nil, false
99-
pgroup = pid
100-
end
101-
while signal = signals.shift
102-
begin
103-
Process.kill signal, pgroup
104-
rescue Errno::EINVAL
105-
next
106-
rescue Errno::ESRCH
107-
break
108-
end
109-
if signals.empty? or !reprieve
110-
Process.wait(pid)
111-
else
112-
begin
113-
Timeout.timeout(reprieve) {Process.wait(pid)}
114-
rescue Timeout::Error
115-
end
116-
end
117-
end
118-
status = $?
152+
status = terminate(pid, signal, opt[:pgroup], reprieve)
153+
terminated = Time.now
119154
end
120155
stdout = th_stdout.value if capture_stdout
121156
stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout
@@ -126,8 +161,8 @@ def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr =
126161
stderr = stderr_filter.call(stderr) if stderr_filter
127162
if timeout_error
128163
bt = caller_locations
129-
msg = "execution of #{bt.shift.label} expired"
130-
msg = Test::Unit::Assertions::FailDesc[status, msg, [stdout, stderr].join("\n")].()
164+
msg = "execution of #{bt.shift.label} expired timeout (#{timeout} sec)"
165+
msg = failure_description(status, terminated, msg, [stdout, stderr].join("\n"))
131166
raise timeout_error, msg, bt.map(&:to_s)
132167
end
133168
return stdout, stderr, status
@@ -151,30 +186,33 @@ class << self
151186
end
152187

153188
def verbose_warning
154-
class << (stderr = "")
155-
alias write <<
189+
class << (stderr = "".dup)
190+
alias write concat
191+
def flush; end
156192
end
157-
stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true
193+
stderr, $stderr = $stderr, stderr
194+
$VERBOSE = true
158195
yield stderr
159196
return $stderr
160197
ensure
161-
stderr, $stderr, $VERBOSE = $stderr, stderr, verbose
198+
stderr, $stderr = $stderr, stderr
199+
$VERBOSE = EnvUtil.original_verbose
162200
end
163201
module_function :verbose_warning
164202

165203
def default_warning
166-
verbose, $VERBOSE = $VERBOSE, false
204+
$VERBOSE = false
167205
yield
168206
ensure
169-
$VERBOSE = verbose
207+
$VERBOSE = EnvUtil.original_verbose
170208
end
171209
module_function :default_warning
172210

173211
def suppress_warning
174-
verbose, $VERBOSE = $VERBOSE, nil
212+
$VERBOSE = nil
175213
yield
176214
ensure
177-
$VERBOSE = verbose
215+
$VERBOSE = EnvUtil.original_verbose
178216
end
179217
module_function :suppress_warning
180218

@@ -187,26 +225,18 @@ def under_gc_stress(stress = true)
187225
module_function :under_gc_stress
188226

189227
def with_default_external(enc)
190-
verbose, $VERBOSE = $VERBOSE, nil
191-
origenc, Encoding.default_external = Encoding.default_external, enc
192-
$VERBOSE = verbose
228+
suppress_warning { Encoding.default_external = enc }
193229
yield
194230
ensure
195-
verbose, $VERBOSE = $VERBOSE, nil
196-
Encoding.default_external = origenc
197-
$VERBOSE = verbose
231+
suppress_warning { Encoding.default_external = EnvUtil.original_external_encoding }
198232
end
199233
module_function :with_default_external
200234

201235
def with_default_internal(enc)
202-
verbose, $VERBOSE = $VERBOSE, nil
203-
origenc, Encoding.default_internal = Encoding.default_internal, enc
204-
$VERBOSE = verbose
236+
suppress_warning { Encoding.default_internal = enc }
205237
yield
206238
ensure
207-
verbose, $VERBOSE = $VERBOSE, nil
208-
Encoding.default_internal = origenc
209-
$VERBOSE = verbose
239+
suppress_warning { Encoding.default_internal = EnvUtil.original_internal_encoding }
210240
end
211241
module_function :with_default_internal
212242

@@ -257,6 +287,37 @@ def self.diagnostic_reports(signame, pid, now)
257287
end
258288
end
259289

290+
def self.failure_description(status, now, message = "", out = "")
291+
pid = status.pid
292+
if signo = status.termsig
293+
signame = Signal.signame(signo)
294+
sigdesc = "signal #{signo}"
295+
end
296+
log = diagnostic_reports(signame, pid, now)
297+
if signame
298+
sigdesc = "SIG#{signame} (#{sigdesc})"
299+
end
300+
if status.coredump?
301+
sigdesc = "#{sigdesc} (core dumped)"
302+
end
303+
full_message = ''.dup
304+
message = message.call if Proc === message
305+
if message and !message.empty?
306+
full_message << message << "\n"
307+
end
308+
full_message << "pid #{pid}"
309+
full_message << " exit #{status.exitstatus}" if status.exited?
310+
full_message << " killed by #{sigdesc}" if sigdesc
311+
if out and !out.empty?
312+
full_message << "\n" << out.b.gsub(/^/, '| ')
313+
full_message.sub!(/(?<!\n)\z/, "\n")
314+
end
315+
if log
316+
full_message << "Diagnostic reports:\n" << log.b.gsub(/^/, '| ')
317+
end
318+
full_message
319+
end
320+
260321
def self.gc_stress_to_class?
261322
unless defined?(@gc_stress_to_class)
262323
_, _, status = invoke_ruby(["-e""exit GC.respond_to?(:add_stress_to_class)"])
@@ -274,10 +335,8 @@ class << self
274335
attr_reader :ruby
275336
end
276337
dir = File.dirname(ruby)
277-
name = File.basename(ruby, CONFIG['EXEEXT'])
278338
CONFIG['bindir'] = dir
279-
CONFIG['ruby_install_name'] = name
280-
CONFIG['RUBY_INSTALL_NAME'] = name
281-
Gem::ConfigMap[:bindir] = dir if defined?(Gem::ConfigMap)
282339
end
283340
end
341+
342+
EnvUtil.capture_global_values

test/lib/find_executable.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# frozen_string_literal: false
1+
# frozen_string_literal: true
22
require "rbconfig"
33

44
module EnvUtil

0 commit comments

Comments
 (0)