pax_global_header 0000666 0000000 0000000 00000000064 13213373207 0014513 g ustar 00root root 0000000 0000000 52 comment=977de8de743a391e3b82cad0aa5b94a7d283a207
cmath-1.0.0/ 0000775 0000000 0000000 00000000000 13213373207 0012605 5 ustar 00root root 0000000 0000000 cmath-1.0.0/.gitignore 0000664 0000000 0000000 00000000127 13213373207 0014575 0 ustar 00root root 0000000 0000000 /.bundle/
/.yardoc
/Gemfile.lock
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/
cmath-1.0.0/.travis.yml 0000664 0000000 0000000 00000000146 13213373207 0014717 0 ustar 00root root 0000000 0000000 sudo: false
language: ruby
rvm:
- 2.3.5
- 2.4.2
- ruby-head
before_install: gem install bundler
cmath-1.0.0/Gemfile 0000664 0000000 0000000 00000000132 13213373207 0014074 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
# Specify your gem's dependencies in cmath.gemspec
gemspec
cmath-1.0.0/LICENSE.txt 0000664 0000000 0000000 00000002402 13213373207 0014426 0 ustar 00root root 0000000 0000000 Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
cmath-1.0.0/README.md 0000664 0000000 0000000 00000003411 13213373207 0014063 0 ustar 00root root 0000000 0000000 # CMath
[](https://travis-ci.org/ruby/cmath)
Trigonometric and transcendental functions for complex numbers.
CMath is a library that provides trigonometric and transcendental functions for complex numbers. The functions in this module accept integers, floating-point numbers or complex numbers as arguments.
Note that the selection of functions is similar, but not identical, to that in module math. The reason for having two modules is that some users aren't interested in complex numbers, and perhaps don't even know what they are. They would rather have Math.sqrt(-1) raise an exception than return a complex number.
For more information you can see Complex class.
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'cmath'
```
And then execute:
$ bundle
Or install it yourself as:
$ gem install cmath
## Usage
To start using this library, simply require cmath library:
```
require "cmath"
```
## Development
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
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 tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
## Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/cmath.
## License
The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause).
cmath-1.0.0/Rakefile 0000664 0000000 0000000 00000000324 13213373207 0014251 0 ustar 00root root 0000000 0000000 require "bundler/gem_tasks"
require "rake/testtask"
Rake::TestTask.new(:test) do |t|
t.libs << "test" << "test/lib"
t.libs << "lib"
t.test_files = FileList['test/**/test_*.rb']
end
task :default => :test
cmath-1.0.0/bin/ 0000775 0000000 0000000 00000000000 13213373207 0013355 5 ustar 00root root 0000000 0000000 cmath-1.0.0/bin/console 0000775 0000000 0000000 00000000524 13213373207 0014746 0 ustar 00root root 0000000 0000000 #!/usr/bin/env ruby
require "bundler/setup"
require "cmath"
# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.
# (If you use this, don't forget to add pry to your Gemfile!)
# require "pry"
# Pry.start
require "irb"
IRB.start(__FILE__)
cmath-1.0.0/bin/setup 0000775 0000000 0000000 00000000203 13213373207 0014436 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx
bundle install
# Do any other automated setup that you need to do here
cmath-1.0.0/cmath.gemspec 0000664 0000000 0000000 00000001714 13213373207 0015251 0 ustar 00root root 0000000 0000000 # coding: utf-8
# frozen_string_literal: true
Gem::Specification.new do |spec|
spec.name = "cmath"
spec.version = "1.0.0"
spec.date = '2017-12-11'
spec.authors = ["Tadayoshi Funaba"]
spec.email = [nil]
spec.summary = "Provides Trigonometric and Transcendental functions for complex numbers"
spec.description = "CMath is a library that provides trigonometric and transcendental functions for complex numbers. The functions in this module accept integers, floating-point numbers or complex numbers as arguments."
spec.homepage = "https://github.com/ruby/cmath"
spec.license = "BSD-2-Clause"
spec.files = "lib/cmath.rb"
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
spec.required_ruby_version = ">= 2.3.0"
spec.add_development_dependency "bundler"
spec.add_development_dependency "rake"
end
cmath-1.0.0/lib/ 0000775 0000000 0000000 00000000000 13213373207 0013353 5 ustar 00root root 0000000 0000000 cmath-1.0.0/lib/cmath.rb 0000664 0000000 0000000 00000022750 13213373207 0015002 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
##
# = Trigonometric and transcendental functions for complex numbers.
#
# CMath is a library that provides trigonometric and transcendental
# functions for complex numbers. The functions in this module accept
# integers, floating-point numbers or complex numbers as arguments.
#
# Note that the selection of functions is similar, but not identical,
# to that in module math. The reason for having two modules is that
# some users aren't interested in complex numbers, and perhaps don't
# even know what they are. They would rather have Math.sqrt(-1) raise
# an exception than return a complex number.
#
# For more information you can see Complex class.
#
# == Usage
#
# To start using this library, simply require cmath library:
#
# require "cmath"
module CMath
include Math
# Backup of Math is needed because mathn.rb replaces Math with CMath.
RealMath = Math # :nodoc:
private_constant :RealMath
%w[
exp
log
log2
log10
sqrt
cbrt
sin
cos
tan
sinh
cosh
tanh
asin
acos
atan
atan2
asinh
acosh
atanh
].each do |meth|
define_method(meth + '!') do |*args, &block|
warn("CMath##{meth}! is deprecated; use CMath##{meth} or Math##{meth}") if $VERBOSE
RealMath.send(meth, *args, &block)
end
end
##
# Math::E raised to the +z+ power
#
# CMath.exp(1.i * Math::PI) #=> (-1.0+1.2246467991473532e-16i)
def exp(z)
begin
if z.real?
RealMath.exp(z)
else
ere = RealMath.exp(z.real)
Complex(ere * RealMath.cos(z.imag),
ere * RealMath.sin(z.imag))
end
rescue NoMethodError
handle_no_method_error
end
end
##
# Returns the natural logarithm of Complex. If a second argument is given,
# it will be the base of logarithm.
#
# CMath.log(1 + 4i) #=> (1.416606672028108+1.3258176636680326i)
# CMath.log(1 + 4i, 10) #=> (0.6152244606891369+0.5757952953408879i)
def log(z, b=::Math::E)
begin
if z.real? && z >= 0 && b >= 0
RealMath.log(z, b)
else
Complex(RealMath.log(z.abs), z.arg) / log(b)
end
rescue NoMethodError
handle_no_method_error
end
end
##
# Returns the base 2 logarithm of +z+
#
# CMath.log2(-1) => (0.0+4.532360141827194i)
def log2(z)
begin
if z.real? and z >= 0
RealMath.log2(z)
else
log(z) / RealMath.log(2)
end
rescue NoMethodError
handle_no_method_error
end
end
##
# Returns the base 10 logarithm of +z+
#
# CMath.log10(-1) #=> (0.0+1.3643763538418412i)
def log10(z)
begin
if z.real? and z >= 0
RealMath.log10(z)
else
log(z) / RealMath.log(10)
end
rescue NoMethodError
handle_no_method_error
end
end
##
# Returns the non-negative square root of Complex.
#
# CMath.sqrt(-1 + 0i) #=> 0.0+1.0i
def sqrt(z)
begin
if z.real?
if z < 0
Complex(0, RealMath.sqrt(-z))
else
RealMath.sqrt(z)
end
else
if z.imag < 0 ||
(z.imag == 0 && z.imag.to_s[0] == '-')
sqrt(z.conjugate).conjugate
else
r = z.abs
x = z.real
Complex(RealMath.sqrt((r + x) / 2.0), RealMath.sqrt((r - x) / 2.0))
end
end
rescue NoMethodError
handle_no_method_error
end
end
##
# Returns the principal value of the cube root of +z+
#
# CMath.cbrt(1 + 4i) #=> (1.449461632813119+0.6858152562177092i)
def cbrt(z)
z ** (1.0/3)
end
##
# Returns the sine of +z+, where +z+ is given in radians
#
# CMath.sin(1 + 1i) #=> (1.2984575814159773+0.6349639147847361i)
def sin(z)
begin
if z.real?
RealMath.sin(z)
else
Complex(RealMath.sin(z.real) * RealMath.cosh(z.imag),
RealMath.cos(z.real) * RealMath.sinh(z.imag))
end
rescue NoMethodError
handle_no_method_error
end
end
##
# Returns the cosine of +z+, where +z+ is given in radians
#
# CMath.cos(1 + 1i) #=> (0.8337300251311491-0.9888977057628651i)
def cos(z)
begin
if z.real?
RealMath.cos(z)
else
Complex(RealMath.cos(z.real) * RealMath.cosh(z.imag),
-RealMath.sin(z.real) * RealMath.sinh(z.imag))
end
rescue NoMethodError
handle_no_method_error
end
end
##
# Returns the tangent of +z+, where +z+ is given in radians
#
# CMath.tan(1 + 1i) #=> (0.27175258531951174+1.0839233273386943i)
def tan(z)
begin
if z.real?
RealMath.tan(z)
else
sin(z) / cos(z)
end
rescue NoMethodError
handle_no_method_error
end
end
##
# Returns the hyperbolic sine of +z+, where +z+ is given in radians
#
# CMath.sinh(1 + 1i) #=> (0.6349639147847361+1.2984575814159773i)
def sinh(z)
begin
if z.real?
RealMath.sinh(z)
else
Complex(RealMath.sinh(z.real) * RealMath.cos(z.imag),
RealMath.cosh(z.real) * RealMath.sin(z.imag))
end
rescue NoMethodError
handle_no_method_error
end
end
##
# Returns the hyperbolic cosine of +z+, where +z+ is given in radians
#
# CMath.cosh(1 + 1i) #=> (0.8337300251311491+0.9888977057628651i)
def cosh(z)
begin
if z.real?
RealMath.cosh(z)
else
Complex(RealMath.cosh(z.real) * RealMath.cos(z.imag),
RealMath.sinh(z.real) * RealMath.sin(z.imag))
end
rescue NoMethodError
handle_no_method_error
end
end
##
# Returns the hyperbolic tangent of +z+, where +z+ is given in radians
#
# CMath.tanh(1 + 1i) #=> (1.0839233273386943+0.27175258531951174i)
def tanh(z)
begin
if z.real?
RealMath.tanh(z)
else
sinh(z) / cosh(z)
end
rescue NoMethodError
handle_no_method_error
end
end
##
# Returns the arc sine of +z+
#
# CMath.asin(1 + 1i) #=> (0.6662394324925153+1.0612750619050355i)
def asin(z)
begin
if z.real? and z >= -1 and z <= 1
RealMath.asin(z)
else
(-1.0).i * log(1.0.i * z + sqrt(1.0 - z * z))
end
rescue NoMethodError
handle_no_method_error
end
end
##
# Returns the arc cosine of +z+
#
# CMath.acos(1 + 1i) #=> (0.9045568943023813-1.0612750619050357i)
def acos(z)
begin
if z.real? and z >= -1 and z <= 1
RealMath.acos(z)
else
(-1.0).i * log(z + 1.0.i * sqrt(1.0 - z * z))
end
rescue NoMethodError
handle_no_method_error
end
end
##
# Returns the arc tangent of +z+
#
# CMath.atan(1 + 1i) #=> (1.0172219678978514+0.4023594781085251i)
def atan(z)
begin
if z.real?
RealMath.atan(z)
else
1.0.i * log((1.0.i + z) / (1.0.i - z)) / 2.0
end
rescue NoMethodError
handle_no_method_error
end
end
##
# returns the arc tangent of +y+ divided by +x+ using the signs of +y+ and
# +x+ to determine the quadrant
#
# CMath.atan2(1 + 1i, 0) #=> (1.5707963267948966+0.0i)
def atan2(y,x)
begin
if y.real? and x.real?
RealMath.atan2(y,x)
else
(-1.0).i * log((x + 1.0.i * y) / sqrt(x * x + y * y))
end
rescue NoMethodError
handle_no_method_error
end
end
##
# returns the inverse hyperbolic sine of +z+
#
# CMath.asinh(1 + 1i) #=> (1.0612750619050357+0.6662394324925153i)
def asinh(z)
begin
if z.real?
RealMath.asinh(z)
else
log(z + sqrt(1.0 + z * z))
end
rescue NoMethodError
handle_no_method_error
end
end
##
# returns the inverse hyperbolic cosine of +z+
#
# CMath.acosh(1 + 1i) #=> (1.0612750619050357+0.9045568943023813i)
def acosh(z)
begin
if z.real? and z >= 1
RealMath.acosh(z)
else
log(z + sqrt(z * z - 1.0))
end
rescue NoMethodError
handle_no_method_error
end
end
##
# returns the inverse hyperbolic tangent of +z+
#
# CMath.atanh(1 + 1i) #=> (0.4023594781085251+1.0172219678978514i)
def atanh(z)
begin
if z.real? and z >= -1 and z <= 1
RealMath.atanh(z)
else
log((1.0 + z) / (1.0 - z)) / 2.0
end
rescue NoMethodError
handle_no_method_error
end
end
module_function :exp!
module_function :exp
module_function :log!
module_function :log
module_function :log2!
module_function :log2
module_function :log10!
module_function :log10
module_function :sqrt!
module_function :sqrt
module_function :cbrt!
module_function :cbrt
module_function :sin!
module_function :sin
module_function :cos!
module_function :cos
module_function :tan!
module_function :tan
module_function :sinh!
module_function :sinh
module_function :cosh!
module_function :cosh
module_function :tanh!
module_function :tanh
module_function :asin!
module_function :asin
module_function :acos!
module_function :acos
module_function :atan!
module_function :atan
module_function :atan2!
module_function :atan2
module_function :asinh!
module_function :asinh
module_function :acosh!
module_function :acosh
module_function :atanh!
module_function :atanh
module_function :frexp
module_function :ldexp
module_function :hypot
module_function :erf
module_function :erfc
module_function :gamma
module_function :lgamma
private
def handle_no_method_error # :nodoc:
if $!.name == :real?
raise TypeError, "Numeric Number required"
else
raise
end
end
module_function :handle_no_method_error
end
cmath-1.0.0/test/ 0000775 0000000 0000000 00000000000 13213373207 0013564 5 ustar 00root root 0000000 0000000 cmath-1.0.0/test/lib/ 0000775 0000000 0000000 00000000000 13213373207 0014332 5 ustar 00root root 0000000 0000000 cmath-1.0.0/test/lib/envutil.rb 0000664 0000000 0000000 00000020067 13213373207 0016352 0 ustar 00root root 0000000 0000000 # -*- coding: us-ascii -*-
# frozen_string_literal: false
require "open3"
require "timeout"
require_relative "find_executable"
begin
require 'rbconfig'
rescue LoadError
end
begin
require "rbconfig/sizeof"
rescue LoadError
end
module EnvUtil
def rubybin
if ruby = ENV["RUBY"]
return ruby
end
ruby = "ruby"
exeext = RbConfig::CONFIG["EXEEXT"]
rubyexe = (ruby + exeext if exeext and !exeext.empty?)
3.times do
if File.exist? ruby and File.executable? ruby and !File.directory? ruby
return File.expand_path(ruby)
end
if rubyexe and File.exist? rubyexe and File.executable? rubyexe
return File.expand_path(rubyexe)
end
ruby = File.join("..", ruby)
end
if defined?(RbConfig.ruby)
RbConfig.ruby
else
"ruby"
end
end
module_function :rubybin
LANG_ENVS = %w"LANG LC_ALL LC_CTYPE"
DEFAULT_SIGNALS = Signal.list
DEFAULT_SIGNALS.delete("TERM") if /mswin|mingw/ =~ RUBY_PLATFORM
class << self
attr_accessor :subprocess_timeout_scale
end
def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr = false,
encoding: nil, timeout: 10, reprieve: 1, timeout_error: Timeout::Error,
stdout_filter: nil, stderr_filter: nil,
signal: :TERM,
rubybin: EnvUtil.rubybin,
**opt)
if scale = EnvUtil.subprocess_timeout_scale
timeout *= scale if timeout
reprieve *= scale if reprieve
end
in_c, in_p = IO.pipe
out_p, out_c = IO.pipe if capture_stdout
err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout
opt[:in] = in_c
opt[:out] = out_c if capture_stdout
opt[:err] = capture_stderr == :merge_to_stdout ? out_c : err_c if capture_stderr
if encoding
out_p.set_encoding(encoding) if out_p
err_p.set_encoding(encoding) if err_p
end
c = "C"
child_env = {}
LANG_ENVS.each {|lc| child_env[lc] = c}
if Array === args and Hash === args.first
child_env.update(args.shift)
end
args = [args] if args.kind_of?(String)
pid = spawn(child_env, rubybin, *args, **opt)
in_c.close
out_c.close if capture_stdout
err_c.close if capture_stderr && capture_stderr != :merge_to_stdout
if block_given?
return yield in_p, out_p, err_p, pid
else
th_stdout = Thread.new { out_p.read } if capture_stdout
th_stderr = Thread.new { err_p.read } if capture_stderr && capture_stderr != :merge_to_stdout
in_p.write stdin_data.to_str unless stdin_data.empty?
in_p.close
if (!th_stdout || th_stdout.join(timeout)) && (!th_stderr || th_stderr.join(timeout))
timeout_error = nil
else
signals = Array(signal).select do |sig|
DEFAULT_SIGNALS[sig.to_s] or
DEFAULT_SIGNALS[Signal.signame(sig)] rescue false
end
signals |= [:ABRT, :KILL]
case pgroup = opt[:pgroup]
when 0, true
pgroup = -pid
when nil, false
pgroup = pid
end
while signal = signals.shift
begin
Process.kill signal, pgroup
rescue Errno::EINVAL
next
rescue Errno::ESRCH
break
end
if signals.empty? or !reprieve
Process.wait(pid)
else
begin
Timeout.timeout(reprieve) {Process.wait(pid)}
rescue Timeout::Error
end
end
end
status = $?
end
stdout = th_stdout.value if capture_stdout
stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout
out_p.close if capture_stdout
err_p.close if capture_stderr && capture_stderr != :merge_to_stdout
status ||= Process.wait2(pid)[1]
stdout = stdout_filter.call(stdout) if stdout_filter
stderr = stderr_filter.call(stderr) if stderr_filter
if timeout_error
bt = caller_locations
msg = "execution of #{bt.shift.label} expired"
msg = Test::Unit::Assertions::FailDesc[status, msg, [stdout, stderr].join("\n")].()
raise timeout_error, msg, bt.map(&:to_s)
end
return stdout, stderr, status
end
ensure
[th_stdout, th_stderr].each do |th|
th.kill if th
end
[in_c, in_p, out_c, out_p, err_c, err_p].each do |io|
io&.close
end
[th_stdout, th_stderr].each do |th|
th.join if th
end
end
module_function :invoke_ruby
alias rubyexec invoke_ruby
class << self
alias rubyexec invoke_ruby
end
def verbose_warning
class << (stderr = "")
alias write <<
end
stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true
yield stderr
return $stderr
ensure
stderr, $stderr, $VERBOSE = $stderr, stderr, verbose
end
module_function :verbose_warning
def default_warning
verbose, $VERBOSE = $VERBOSE, false
yield
ensure
$VERBOSE = verbose
end
module_function :default_warning
def suppress_warning
verbose, $VERBOSE = $VERBOSE, nil
yield
ensure
$VERBOSE = verbose
end
module_function :suppress_warning
def under_gc_stress(stress = true)
stress, GC.stress = GC.stress, stress
yield
ensure
GC.stress = stress
end
module_function :under_gc_stress
def with_default_external(enc)
verbose, $VERBOSE = $VERBOSE, nil
origenc, Encoding.default_external = Encoding.default_external, enc
$VERBOSE = verbose
yield
ensure
verbose, $VERBOSE = $VERBOSE, nil
Encoding.default_external = origenc
$VERBOSE = verbose
end
module_function :with_default_external
def with_default_internal(enc)
verbose, $VERBOSE = $VERBOSE, nil
origenc, Encoding.default_internal = Encoding.default_internal, enc
$VERBOSE = verbose
yield
ensure
verbose, $VERBOSE = $VERBOSE, nil
Encoding.default_internal = origenc
$VERBOSE = verbose
end
module_function :with_default_internal
def labeled_module(name, &block)
Module.new do
singleton_class.class_eval {define_method(:to_s) {name}; alias inspect to_s}
class_eval(&block) if block
end
end
module_function :labeled_module
def labeled_class(name, superclass = Object, &block)
Class.new(superclass) do
singleton_class.class_eval {define_method(:to_s) {name}; alias inspect to_s}
class_eval(&block) if block
end
end
module_function :labeled_class
if /darwin/ =~ RUBY_PLATFORM
DIAGNOSTIC_REPORTS_PATH = File.expand_path("~/Library/Logs/DiagnosticReports")
DIAGNOSTIC_REPORTS_TIMEFORMAT = '%Y-%m-%d-%H%M%S'
@ruby_install_name = RbConfig::CONFIG['RUBY_INSTALL_NAME']
def self.diagnostic_reports(signame, pid, now)
return unless %w[ABRT QUIT SEGV ILL TRAP].include?(signame)
cmd = File.basename(rubybin)
cmd = @ruby_install_name if "ruby-runner#{RbConfig::CONFIG["EXEEXT"]}" == cmd
path = DIAGNOSTIC_REPORTS_PATH
timeformat = DIAGNOSTIC_REPORTS_TIMEFORMAT
pat = "#{path}/#{cmd}_#{now.strftime(timeformat)}[-_]*.crash"
first = true
30.times do
first ? (first = false) : sleep(0.1)
Dir.glob(pat) do |name|
log = File.read(name) rescue next
if /\AProcess:\s+#{cmd} \[#{pid}\]$/ =~ log
File.unlink(name)
File.unlink("#{path}/.#{File.basename(name)}.plist") rescue nil
return log
end
end
end
nil
end
else
def self.diagnostic_reports(signame, pid, now)
end
end
def self.gc_stress_to_class?
unless defined?(@gc_stress_to_class)
_, _, status = invoke_ruby(["-e""exit GC.respond_to?(:add_stress_to_class)"])
@gc_stress_to_class = status.success?
end
@gc_stress_to_class
end
end
if defined?(RbConfig)
module RbConfig
@ruby = EnvUtil.rubybin
class << self
undef ruby if method_defined?(:ruby)
attr_reader :ruby
end
dir = File.dirname(ruby)
name = File.basename(ruby, CONFIG['EXEEXT'])
CONFIG['bindir'] = dir
CONFIG['ruby_install_name'] = name
CONFIG['RUBY_INSTALL_NAME'] = name
Gem::ConfigMap[:bindir] = dir if defined?(Gem::ConfigMap)
end
end
cmath-1.0.0/test/lib/find_executable.rb 0000664 0000000 0000000 00000001104 13213373207 0017774 0 ustar 00root root 0000000 0000000 # frozen_string_literal: false
require "rbconfig"
module EnvUtil
def find_executable(cmd, *args)
exts = RbConfig::CONFIG["EXECUTABLE_EXTS"].split | [RbConfig::CONFIG["EXEEXT"]]
ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
next if path.empty?
path = File.join(path, cmd)
exts.each do |ext|
cmdline = [path + ext, *args]
begin
return cmdline if yield(IO.popen(cmdline, "r", err: [:child, :out], &:read))
rescue
next
end
end
end
nil
end
module_function :find_executable
end
cmath-1.0.0/test/lib/leakchecker.rb 0000664 0000000 0000000 00000012003 13213373207 0017114 0 ustar 00root root 0000000 0000000 # frozen_string_literal: false
class LeakChecker
def initialize
@fd_info = find_fds
@tempfile_info = find_tempfiles
@thread_info = find_threads
@env_info = find_env
end
def check(test_name)
leaks = [
check_fd_leak(test_name),
check_thread_leak(test_name),
check_tempfile_leak(test_name),
check_env(test_name)
]
GC.start if leaks.any?
end
def find_fds
if IO.respond_to?(:console) and (m = IO.method(:console)).arity.nonzero?
m[:close]
end
fd_dir = "/proc/self/fd"
if File.directory?(fd_dir)
fds = Dir.open(fd_dir) {|d|
a = d.grep(/\A\d+\z/, &:to_i)
if d.respond_to? :fileno
a -= [d.fileno]
end
a
}
fds.sort
else
[]
end
end
def check_fd_leak(test_name)
leaked = false
live1 = @fd_info
live2 = find_fds
fd_closed = live1 - live2
if !fd_closed.empty?
fd_closed.each {|fd|
puts "Closed file descriptor: #{test_name}: #{fd}"
}
end
fd_leaked = live2 - live1
if !fd_leaked.empty?
leaked = true
h = {}
ObjectSpace.each_object(IO) {|io|
inspect = io.inspect
begin
autoclose = io.autoclose?
fd = io.fileno
rescue IOError # closed IO object
next
end
(h[fd] ||= []) << [io, autoclose, inspect]
}
fd_leaked.each {|fd|
str = ''
if h[fd]
str << ' :'
h[fd].map {|io, autoclose, inspect|
s = ' ' + inspect
s << "(not-autoclose)" if !autoclose
s
}.sort.each {|s|
str << s
}
end
puts "Leaked file descriptor: #{test_name}: #{fd}#{str}"
}
#system("lsof -p #$$") if !fd_leaked.empty?
h.each {|fd, list|
next if list.length <= 1
if 1 < list.count {|io, autoclose, inspect| autoclose }
str = list.map {|io, autoclose, inspect| " #{inspect}" + (autoclose ? "(autoclose)" : "") }.sort.join
puts "Multiple autoclose IO object for a file descriptor:#{str}"
end
}
end
@fd_info = live2
return leaked
end
def extend_tempfile_counter
return if defined? LeakChecker::TempfileCounter
m = Module.new {
@count = 0
class << self
attr_accessor :count
end
def new(data)
LeakChecker::TempfileCounter.count += 1
super(data)
end
}
LeakChecker.const_set(:TempfileCounter, m)
class << Tempfile::Remover
prepend LeakChecker::TempfileCounter
end
end
def find_tempfiles(prev_count=-1)
return [prev_count, []] unless defined? Tempfile
extend_tempfile_counter
count = TempfileCounter.count
if prev_count == count
[prev_count, []]
else
tempfiles = ObjectSpace.each_object(Tempfile).find_all {|t|
t.instance_variable_defined?(:@tmpfile) and t.path
}
[count, tempfiles]
end
end
def check_tempfile_leak(test_name)
return false unless defined? Tempfile
count1, initial_tempfiles = @tempfile_info
count2, current_tempfiles = find_tempfiles(count1)
leaked = false
tempfiles_leaked = current_tempfiles - initial_tempfiles
if !tempfiles_leaked.empty?
leaked = true
list = tempfiles_leaked.map {|t| t.inspect }.sort
list.each {|str|
puts "Leaked tempfile: #{test_name}: #{str}"
}
tempfiles_leaked.each {|t| t.close! }
end
@tempfile_info = [count2, initial_tempfiles]
return leaked
end
def find_threads
Thread.list.find_all {|t|
t != Thread.current && t.alive?
}
end
def check_thread_leak(test_name)
live1 = @thread_info
live2 = find_threads
thread_finished = live1 - live2
leaked = false
if !thread_finished.empty?
list = thread_finished.map {|t| t.inspect }.sort
list.each {|str|
puts "Finished thread: #{test_name}: #{str}"
}
end
thread_leaked = live2 - live1
if !thread_leaked.empty?
leaked = true
list = thread_leaked.map {|t| t.inspect }.sort
list.each {|str|
puts "Leaked thread: #{test_name}: #{str}"
}
end
@thread_info = live2
return leaked
end
def find_env
ENV.to_h
end
def check_env(test_name)
old_env = @env_info
new_env = ENV.to_h
return false if old_env == new_env
(old_env.keys | new_env.keys).sort.each {|k|
if old_env.has_key?(k)
if new_env.has_key?(k)
if old_env[k] != new_env[k]
puts "Environment variable changed: #{test_name} : #{k.inspect} changed : #{old_env[k].inspect} -> #{new_env[k].inspect}"
end
else
puts "Environment variable changed: #{test_name} : #{k.inspect} deleted"
end
else
if new_env.has_key?(k)
puts "Environment variable changed: #{test_name} : #{k.inspect} added"
else
flunk "unreachable"
end
end
}
@env_info = new_env
return true
end
def puts(*a)
MiniTest::Unit.output.puts(*a)
end
end
cmath-1.0.0/test/lib/minitest/ 0000775 0000000 0000000 00000000000 13213373207 0016166 5 ustar 00root root 0000000 0000000 cmath-1.0.0/test/lib/minitest/autorun.rb 0000664 0000000 0000000 00000000320 13213373207 0020203 0 ustar 00root root 0000000 0000000 # encoding: utf-8
# frozen_string_literal: false
begin
require 'rubygems'
gem 'minitest'
rescue Gem::LoadError
# do nothing
end
require 'minitest/unit'
require 'minitest/mock'
MiniTest::Unit.autorun
cmath-1.0.0/test/lib/minitest/mock.rb 0000664 0000000 0000000 00000013163 13213373207 0017450 0 ustar 00root root 0000000 0000000 # encoding: utf-8
# frozen_string_literal: false
class MockExpectationError < StandardError; end # :nodoc:
##
# A simple and clean mock object framework.
module MiniTest # :nodoc:
##
# All mock objects are an instance of Mock
class Mock
alias :__respond_to? :respond_to?
skip_methods = %w(object_id respond_to_missing? inspect === to_s)
instance_methods.each do |m|
undef_method m unless skip_methods.include?(m.to_s) || m =~ /^__/
end
def initialize # :nodoc:
@expected_calls = Hash.new { |calls, name| calls[name] = [] }
@actual_calls = Hash.new { |calls, name| calls[name] = [] }
end
##
# Expect that method +name+ is called, optionally with +args+ or a
# +blk+, and returns +retval+.
#
# @mock.expect(:meaning_of_life, 42)
# @mock.meaning_of_life # => 42
#
# @mock.expect(:do_something_with, true, [some_obj, true])
# @mock.do_something_with(some_obj, true) # => true
#
# @mock.expect(:do_something_else, true) do |a1, a2|
# a1 == "buggs" && a2 == :bunny
# end
#
# +args+ is compared to the expected args using case equality (ie, the
# '===' operator), allowing for less specific expectations.
#
# @mock.expect(:uses_any_string, true, [String])
# @mock.uses_any_string("foo") # => true
# @mock.verify # => true
#
# @mock.expect(:uses_one_string, true, ["foo"]
# @mock.uses_one_string("bar") # => true
# @mock.verify # => raises MockExpectationError
def expect(name, retval, args=[], &blk)
if block_given?
raise ArgumentError, "args ignored when block given" unless args.empty?
@expected_calls[name] << { :retval => retval, :block => blk }
else
raise ArgumentError, "args must be an array" unless Array === args
@expected_calls[name] << { :retval => retval, :args => args }
end
self
end
def __call name, data # :nodoc:
case data
when Hash then
"#{name}(#{data[:args].inspect[1..-2]}) => #{data[:retval].inspect}"
else
data.map { |d| __call name, d }.join ", "
end
end
##
# Verify that all methods were called as expected. Raises
# +MockExpectationError+ if the mock object was not called as
# expected.
def verify
@expected_calls.each do |name, calls|
calls.each do |expected|
msg1 = "expected #{__call name, expected}"
msg2 = "#{msg1}, got [#{__call name, @actual_calls[name]}]"
raise MockExpectationError, msg2 if
@actual_calls.has_key?(name) and
not @actual_calls[name].include?(expected)
raise MockExpectationError, msg1 unless
@actual_calls.has_key?(name) and
@actual_calls[name].include?(expected)
end
end
true
end
def method_missing(sym, *args) # :nodoc:
unless @expected_calls.has_key?(sym) then
raise NoMethodError, "unmocked method %p, expected one of %p" %
[sym, @expected_calls.keys.sort_by(&:to_s)]
end
index = @actual_calls[sym].length
expected_call = @expected_calls[sym][index]
unless expected_call then
raise MockExpectationError, "No more expects available for %p: %p" %
[sym, args]
end
expected_args, retval, val_block =
expected_call.values_at(:args, :retval, :block)
if val_block then
raise MockExpectationError, "mocked method %p failed block w/ %p" %
[sym, args] unless val_block.call(args)
# keep "verify" happy
@actual_calls[sym] << expected_call
return retval
end
if expected_args.size != args.size then
raise ArgumentError, "mocked method %p expects %d arguments, got %d" %
[sym, expected_args.size, args.size]
end
fully_matched = expected_args.zip(args).all? { |mod, a|
mod === a or mod == a
}
unless fully_matched then
raise MockExpectationError, "mocked method %p called with unexpected arguments %p" %
[sym, args]
end
@actual_calls[sym] << {
:retval => retval,
:args => expected_args.zip(args).map { |mod, a| mod === a ? mod : a }
}
retval
end
def respond_to?(sym, include_private = false) # :nodoc:
return true if @expected_calls.has_key?(sym.to_sym)
return __respond_to?(sym, include_private)
end
end
end
class Object # :nodoc:
##
# Add a temporary stubbed method replacing +name+ for the duration
# of the +block+. If +val_or_callable+ responds to #call, then it
# returns the result of calling it, otherwise returns the value
# as-is. Cleans up the stub at the end of the +block+. The method
# +name+ must exist before stubbing.
#
# def test_stale_eh
# obj_under_test = Something.new
# refute obj_under_test.stale?
#
# Time.stub :now, Time.at(0) do
# assert obj_under_test.stale?
# end
# end
def stub name, val_or_callable, &block
new_name = "__minitest_stub__#{name}"
metaclass = class << self; self; end
if respond_to? name and not methods.map(&:to_s).include? name.to_s then
metaclass.send :define_method, name do |*args|
super(*args)
end
end
metaclass.send :alias_method, new_name, name
metaclass.send :define_method, name do |*args|
if val_or_callable.respond_to? :call then
val_or_callable.call(*args)
else
val_or_callable
end
end
yield self
ensure
metaclass.send :undef_method, name
metaclass.send :alias_method, name, new_name
metaclass.send :undef_method, new_name
end
end
cmath-1.0.0/test/lib/minitest/unit.rb 0000664 0000000 0000000 00000106611 13213373207 0017477 0 ustar 00root root 0000000 0000000 # encoding: utf-8
# frozen_string_literal: false
require "optparse"
require "rbconfig"
require "leakchecker"
##
# Minimal (mostly drop-in) replacement for test-unit.
#
# :include: README.txt
module MiniTest
def self.const_missing name # :nodoc:
case name
when :MINI_DIR then
msg = "MiniTest::MINI_DIR was removed. Don't violate other's internals."
warn "WAR\NING: #{msg}"
warn "WAR\NING: Used by #{caller.first}."
const_set :MINI_DIR, "bad value"
else
super
end
end
##
# Assertion base class
class Assertion < Exception; end
##
# Assertion raised when skipping a test
class Skip < Assertion; end
class << self
##
# Filter object for backtraces.
attr_accessor :backtrace_filter
end
class BacktraceFilter # :nodoc:
def filter bt
return ["No backtrace"] unless bt
new_bt = []
unless $DEBUG then
bt.each do |line|
break if line =~ /lib\/minitest/
new_bt << line
end
new_bt = bt.reject { |line| line =~ /lib\/minitest/ } if new_bt.empty?
new_bt = bt.dup if new_bt.empty?
else
new_bt = bt.dup
end
new_bt
end
end
self.backtrace_filter = BacktraceFilter.new
def self.filter_backtrace bt # :nodoc:
backtrace_filter.filter bt
end
##
# MiniTest Assertions. All assertion methods accept a +msg+ which is
# printed if the assertion fails.
module Assertions
##
# Returns the diff command to use in #diff. Tries to intelligently
# figure out what diff to use.
def self.diff
@diff = if (RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ &&
system("diff.exe", __FILE__, __FILE__)) then
"diff.exe -u"
elsif Minitest::Unit::Guard.maglev? then # HACK
"diff -u"
elsif system("gdiff", __FILE__, __FILE__)
"gdiff -u" # solaris and kin suck
elsif system("diff", __FILE__, __FILE__)
"diff -u"
else
nil
end unless defined? @diff
@diff
end
##
# Set the diff command to use in #diff.
def self.diff= o
@diff = o
end
##
# Returns a diff between +exp+ and +act+. If there is no known
# diff command or if it doesn't make sense to diff the output
# (single line, short output), then it simply returns a basic
# comparison between the two.
def diff exp, act
require "tempfile"
expect = mu_pp_for_diff exp
butwas = mu_pp_for_diff act
result = nil
need_to_diff =
MiniTest::Assertions.diff &&
(expect.include?("\n") ||
butwas.include?("\n") ||
expect.size > 30 ||
butwas.size > 30 ||
expect == butwas)
return "Expected: #{mu_pp exp}\n Actual: #{mu_pp act}" unless
need_to_diff
tempfile_a = nil
tempfile_b = nil
Tempfile.open("expect") do |a|
tempfile_a = a
a.puts expect
a.flush
Tempfile.open("butwas") do |b|
tempfile_b = b
b.puts butwas
b.flush
result = `#{MiniTest::Assertions.diff} #{a.path} #{b.path}`
result.sub!(/^\-\-\- .+/, "--- expected")
result.sub!(/^\+\+\+ .+/, "+++ actual")
if result.empty? then
klass = exp.class
result = [
"No visible difference in the #{klass}#inspect output.\n",
"You should look at the implementation of #== on ",
"#{klass} or its members.\n",
expect,
].join
end
end
end
result
ensure
tempfile_a.close! if tempfile_a
tempfile_b.close! if tempfile_b
end
##
# This returns a human-readable version of +obj+. By default
# #inspect is called. You can override this to use #pretty_print
# if you want.
def mu_pp obj
s = obj.inspect
s = s.encode Encoding.default_external if defined? Encoding
s
end
##
# This returns a diff-able human-readable version of +obj+. This
# differs from the regular mu_pp because it expands escaped
# newlines and makes hex-values generic (like object_ids). This
# uses mu_pp to do the first pass and then cleans it up.
def mu_pp_for_diff obj
mu_pp(obj).gsub(/\\n/, "\n").gsub(/:0x[a-fA-F0-9]{4,}/m, ':0xXXXXXX')
end
def _assertions= n # :nodoc:
@_assertions = n
end
def _assertions # :nodoc:
@_assertions ||= 0
end
##
# Fails unless +test+ is a true value.
def assert test, msg = nil
msg ||= "Failed assertion, no message given."
self._assertions += 1
unless test then
msg = msg.call if Proc === msg
raise MiniTest::Assertion, msg
end
true
end
##
# Fails unless +obj+ is empty.
def assert_empty obj, msg = nil
msg = message(msg) { "Expected #{mu_pp(obj)} to be empty" }
assert_respond_to obj, :empty?
assert obj.empty?, msg
end
##
# Fails unless exp == act printing the difference between
# the two, if possible.
#
# If there is no visible difference but the assertion fails, you
# should suspect that your #== is buggy, or your inspect output is
# missing crucial details.
#
# For floats use assert_in_delta.
#
# See also: MiniTest::Assertions.diff
def assert_equal exp, act, msg = nil
msg = message(msg, "") { diff exp, act }
assert exp == act, msg
end
##
# For comparing Floats. Fails unless +exp+ and +act+ are within +delta+
# of each other.
#
# assert_in_delta Math::PI, (22.0 / 7.0), 0.01
def assert_in_delta exp, act, delta = 0.001, msg = nil
n = (exp - act).abs
msg = message(msg) {
"Expected |#{exp} - #{act}| (#{n}) to be <= #{delta}"
}
assert delta >= n, msg
end
##
# For comparing Floats. Fails unless +exp+ and +act+ have a relative
# error less than +epsilon+.
def assert_in_epsilon a, b, epsilon = 0.001, msg = nil
assert_in_delta a, b, [a.abs, b.abs].min * epsilon, msg
end
##
# Fails unless +collection+ includes +obj+.
def assert_includes collection, obj, msg = nil
msg = message(msg) {
"Expected #{mu_pp(collection)} to include #{mu_pp(obj)}"
}
assert_respond_to collection, :include?
assert collection.include?(obj), msg
end
##
# Fails unless +obj+ is an instance of +cls+.
def assert_instance_of cls, obj, msg = nil
msg = message(msg) {
"Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}"
}
assert obj.instance_of?(cls), msg
end
##
# Fails unless +obj+ is a kind of +cls+.
def assert_kind_of cls, obj, msg = nil # TODO: merge with instance_of
msg = message(msg) {
"Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" }
assert obj.kind_of?(cls), msg
end
##
# Fails unless +matcher+ =~ +obj+.
def assert_match matcher, obj, msg = nil
msg = message(msg) { "Expected #{mu_pp matcher} to match #{mu_pp obj}" }
assert_respond_to matcher, :"=~"
matcher = Regexp.new Regexp.escape matcher if String === matcher
assert matcher =~ obj, msg
end
##
# Fails unless +obj+ is nil
def assert_nil obj, msg = nil
msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" }
assert obj.nil?, msg
end
##
# For testing with binary operators.
#
# assert_operator 5, :<=, 4
def assert_operator o1, op, o2 = (predicate = true; nil), msg = nil
return assert_predicate o1, op, msg if predicate
msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" }
assert o1.__send__(op, o2), msg
end
##
# Fails if stdout or stderr do not output the expected results.
# Pass in nil if you don't care about that streams output. Pass in
# "" if you require it to be silent. Pass in a regexp if you want
# to pattern match.
#
# NOTE: this uses #capture_io, not #capture_subprocess_io.
#
# See also: #assert_silent
def assert_output stdout = nil, stderr = nil
out, err = capture_io do
yield
end
err_msg = Regexp === stderr ? :assert_match : :assert_equal if stderr
out_msg = Regexp === stdout ? :assert_match : :assert_equal if stdout
y = send err_msg, stderr, err, "In stderr" if err_msg
x = send out_msg, stdout, out, "In stdout" if out_msg
(!stdout || x) && (!stderr || y)
end
##
# For testing with predicates.
#
# assert_predicate str, :empty?
#
# This is really meant for specs and is front-ended by assert_operator:
#
# str.must_be :empty?
def assert_predicate o1, op, msg = nil
msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op}" }
assert o1.__send__(op), msg
end
##
# Fails unless the block raises one of +exp+. Returns the
# exception matched so you can check the message, attributes, etc.
def assert_raises *exp
msg = "#{exp.pop}.\n" if String === exp.last
begin
yield
rescue MiniTest::Skip => e
return e if exp.include? MiniTest::Skip
raise e
rescue Exception => e
expected = exp.any? { |ex|
if ex.instance_of? Module then
e.kind_of? ex
else
e.instance_of? ex
end
}
assert expected, proc {
exception_details(e, "#{msg}#{mu_pp(exp)} exception expected, not")
}
return e
end
exp = exp.first if exp.size == 1
flunk "#{msg}#{mu_pp(exp)} expected but nothing was raised."
end
##
# Fails unless +obj+ responds to +meth+.
def assert_respond_to obj, meth, msg = nil
msg = message(msg) {
"Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
}
assert obj.respond_to?(meth), msg
end
##
# Fails unless +exp+ and +act+ are #equal?
def assert_same exp, act, msg = nil
msg = message(msg) {
data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
"Expected %s (oid=%d) to be the same as %s (oid=%d)" % data
}
assert exp.equal?(act), msg
end
##
# +send_ary+ is a receiver, message and arguments.
#
# Fails unless the call returns a true value
# TODO: I should prolly remove this from specs
def assert_send send_ary, m = nil
recv, msg, *args = send_ary
m = message(m) {
"Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" }
assert recv.__send__(msg, *args), m
end
##
# Fails if the block outputs anything to stderr or stdout.
#
# See also: #assert_output
def assert_silent
assert_output "", "" do
yield
end
end
##
# Fails unless the block throws +sym+
def assert_throws sym, msg = nil
default = "Expected #{mu_pp(sym)} to have been thrown"
caught = true
catch(sym) do
begin
yield
rescue ThreadError => e # wtf?!? 1.8 + threads == suck
default += ", not \:#{e.message[/uncaught throw \`(\w+?)\'/, 1]}"
rescue ArgumentError => e # 1.9 exception
default += ", not #{e.message.split(/ /).last}"
rescue NameError => e # 1.8 exception
default += ", not #{e.name.inspect}"
end
caught = false
end
assert caught, message(msg) { default }
end
##
# Captures $stdout and $stderr into strings:
#
# out, err = capture_io do
# puts "Some info"
# warn "You did a bad thing"
# end
#
# assert_match %r%info%, out
# assert_match %r%bad%, err
#
# NOTE: For efficiency, this method uses StringIO and does not
# capture IO for subprocesses. Use #capture_subprocess_io for
# that.
def capture_io
require 'stringio'
captured_stdout, captured_stderr = StringIO.new, StringIO.new
synchronize do
orig_stdout, orig_stderr = $stdout, $stderr
$stdout, $stderr = captured_stdout, captured_stderr
begin
yield
ensure
$stdout = orig_stdout
$stderr = orig_stderr
end
end
return captured_stdout.string, captured_stderr.string
end
##
# Captures $stdout and $stderr into strings, using Tempfile to
# ensure that subprocess IO is captured as well.
#
# out, err = capture_subprocess_io do
# system "echo Some info"
# system "echo You did a bad thing 1>&2"
# end
#
# assert_match %r%info%, out
# assert_match %r%bad%, err
#
# NOTE: This method is approximately 10x slower than #capture_io so
# only use it when you need to test the output of a subprocess.
def capture_subprocess_io
require 'tempfile'
captured_stdout, captured_stderr = Tempfile.new("out"), Tempfile.new("err")
synchronize do
orig_stdout, orig_stderr = $stdout.dup, $stderr.dup
$stdout.reopen captured_stdout
$stderr.reopen captured_stderr
begin
yield
$stdout.rewind
$stderr.rewind
[captured_stdout.read, captured_stderr.read]
ensure
$stdout.reopen orig_stdout
$stderr.reopen orig_stderr
orig_stdout.close
orig_stderr.close
captured_stdout.close!
captured_stderr.close!
end
end
end
##
# Returns details for exception +e+
def exception_details e, msg
[
"#{msg}",
"Class: <#{e.class}>",
"Message: <#{e.message.inspect}>",
"---Backtrace---",
"#{MiniTest::filter_backtrace(e.backtrace).join("\n")}",
"---------------",
].join "\n"
end
##
# Fails with +msg+
def flunk msg = nil
msg ||= "Epic Fail!"
assert false, msg
end
##
# Returns a proc that will output +msg+ along with the default message.
def message msg = nil, ending = ".", &default
proc {
msg = msg.call.chomp(".") if Proc === msg
custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty?
"#{custom_message}#{default.call}#{ending}"
}
end
##
# used for counting assertions
def pass msg = nil
assert true
end
##
# Fails if +test+ is a true value
def refute test, msg = nil
msg ||= "Failed refutation, no message given"
not assert(! test, msg)
end
##
# Fails if +obj+ is empty.
def refute_empty obj, msg = nil
msg = message(msg) { "Expected #{mu_pp(obj)} to not be empty" }
assert_respond_to obj, :empty?
refute obj.empty?, msg
end
##
# Fails if exp == act.
#
# For floats use refute_in_delta.
def refute_equal exp, act, msg = nil
msg = message(msg) {
"Expected #{mu_pp(act)} to not be equal to #{mu_pp(exp)}"
}
refute exp == act, msg
end
##
# For comparing Floats. Fails if +exp+ is within +delta+ of +act+.
#
# refute_in_delta Math::PI, (22.0 / 7.0)
def refute_in_delta exp, act, delta = 0.001, msg = nil
n = (exp - act).abs
msg = message(msg) {
"Expected |#{exp} - #{act}| (#{n}) to not be <= #{delta}"
}
refute delta >= n, msg
end
##
# For comparing Floats. Fails if +exp+ and +act+ have a relative error
# less than +epsilon+.
def refute_in_epsilon a, b, epsilon = 0.001, msg = nil
refute_in_delta a, b, a * epsilon, msg
end
##
# Fails if +collection+ includes +obj+.
def refute_includes collection, obj, msg = nil
msg = message(msg) {
"Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}"
}
assert_respond_to collection, :include?
refute collection.include?(obj), msg
end
##
# Fails if +obj+ is an instance of +cls+.
def refute_instance_of cls, obj, msg = nil
msg = message(msg) {
"Expected #{mu_pp(obj)} to not be an instance of #{cls}"
}
refute obj.instance_of?(cls), msg
end
##
# Fails if +obj+ is a kind of +cls+.
def refute_kind_of cls, obj, msg = nil # TODO: merge with instance_of
msg = message(msg) { "Expected #{mu_pp(obj)} to not be a kind of #{cls}" }
refute obj.kind_of?(cls), msg
end
##
# Fails if +matcher+ =~ +obj+.
def refute_match matcher, obj, msg = nil
msg = message(msg) {"Expected #{mu_pp matcher} to not match #{mu_pp obj}"}
assert_respond_to matcher, :"=~"
matcher = Regexp.new Regexp.escape matcher if String === matcher
refute matcher =~ obj, msg
end
##
# Fails if +obj+ is nil.
def refute_nil obj, msg = nil
msg = message(msg) { "Expected #{mu_pp(obj)} to not be nil" }
refute obj.nil?, msg
end
##
# Fails if +o1+ is not +op+ +o2+. Eg:
#
# refute_operator 1, :>, 2 #=> pass
# refute_operator 1, :<, 2 #=> fail
def refute_operator o1, op, o2 = (predicate = true; nil), msg = nil
return refute_predicate o1, op, msg if predicate
msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}"}
refute o1.__send__(op, o2), msg
end
##
# For testing with predicates.
#
# refute_predicate str, :empty?
#
# This is really meant for specs and is front-ended by refute_operator:
#
# str.wont_be :empty?
def refute_predicate o1, op, msg = nil
msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op}" }
refute o1.__send__(op), msg
end
##
# Fails if +obj+ responds to the message +meth+.
def refute_respond_to obj, meth, msg = nil
msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" }
refute obj.respond_to?(meth), msg
end
##
# Fails if +exp+ is the same (by object identity) as +act+.
def refute_same exp, act, msg = nil
msg = message(msg) {
data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
"Expected %s (oid=%d) to not be the same as %s (oid=%d)" % data
}
refute exp.equal?(act), msg
end
##
# Skips the current test. Gets listed at the end of the run but
# doesn't cause a failure exit code.
def skip msg = nil, bt = caller
msg ||= "Skipped, no message given"
@skip = true
raise MiniTest::Skip, msg, bt
end
##
# Was this testcase skipped? Meant for #teardown.
def skipped?
defined?(@skip) and @skip
end
##
# Takes a block and wraps it with the runner's shared mutex.
def synchronize
Minitest::Unit.runner.synchronize do
yield
end
end
end
class Unit # :nodoc:
VERSION = "4.7.5" # :nodoc:
attr_accessor :report, :failures, :errors, :skips # :nodoc:
attr_accessor :assertion_count # :nodoc:
attr_writer :test_count # :nodoc:
attr_accessor :start_time # :nodoc:
attr_accessor :help # :nodoc:
attr_accessor :verbose # :nodoc:
attr_writer :options # :nodoc:
##
# :attr:
#
# if true, installs an "INFO" signal handler (only available to BSD and
# OS X users) which prints diagnostic information about the test run.
#
# This is auto-detected by default but may be overridden by custom
# runners.
attr_accessor :info_signal
##
# Lazy accessor for options.
def options
@options ||= {}
end
@@installed_at_exit ||= false
@@out = $stdout
@@after_tests = []
##
# A simple hook allowing you to run a block of code after _all_ of
# the tests are done. Eg:
#
# MiniTest::Unit.after_tests { p $debugging_info }
def self.after_tests &block
@@after_tests << block
end
##
# Registers MiniTest::Unit to run tests at process exit
def self.autorun
at_exit {
# don't run if there was a non-exit exception
next if $! and not $!.kind_of? SystemExit
# the order here is important. The at_exit handler must be
# installed before anyone else gets a chance to install their
# own, that way we can be assured that our exit will be last
# to run (at_exit stacks).
exit_code = nil
at_exit {
@@after_tests.reverse_each(&:call)
exit false if exit_code && exit_code != 0
}
exit_code = MiniTest::Unit.new.run ARGV
} unless @@installed_at_exit
@@installed_at_exit = true
end
##
# Returns the stream to use for output.
def self.output
@@out
end
##
# Sets MiniTest::Unit to write output to +stream+. $stdout is the default
# output
def self.output= stream
@@out = stream
end
##
# Tells MiniTest::Unit to delegate to +runner+, an instance of a
# MiniTest::Unit subclass, when MiniTest::Unit#run is called.
def self.runner= runner
@@runner = runner
end
##
# Returns the MiniTest::Unit subclass instance that will be used
# to run the tests. A MiniTest::Unit instance is the default
# runner.
def self.runner
@@runner ||= self.new
end
##
# Return all plugins' run methods (methods that start with "run_").
def self.plugins
@@plugins ||= (["run_tests"] +
public_instance_methods(false).
grep(/^run_/).map { |s| s.to_s }).uniq
end
##
# Return the IO for output.
def output
self.class.output
end
def puts *a # :nodoc:
output.puts(*a)
end
def print *a # :nodoc:
output.print(*a)
end
def test_count # :nodoc:
@test_count ||= 0
end
##
# Runner for a given +type+ (eg, test vs bench).
def _run_anything type
suites = TestCase.send "#{type}_suites"
return if suites.empty?
puts
puts "# Running #{type}s:"
puts
@test_count, @assertion_count = 0, 0
test_count = assertion_count = 0
sync = output.respond_to? :"sync=" # stupid emacs
old_sync, output.sync = output.sync, true if sync
count = 0
begin
start = Time.now
results = _run_suites suites, type
@test_count = results.inject(0) { |sum, (tc, _)| sum + tc }
@assertion_count = results.inject(0) { |sum, (_, ac)| sum + ac }
test_count += @test_count
assertion_count += @assertion_count
t = Time.now - start
count += 1
unless @repeat_count
puts
puts
end
puts "Finished%s %ss in %.6fs, %.4f tests/s, %.4f assertions/s.\n" %
[(@repeat_count ? "(#{count}/#{@repeat_count}) " : ""), type,
t, @test_count.fdiv(t), @assertion_count.fdiv(t)]
end while @repeat_count && count < @repeat_count && report.empty?
output.sync = old_sync if sync
report.each_with_index do |msg, i|
puts "\n%3d) %s" % [i + 1, msg]
end
puts
@test_count = test_count
@assertion_count = assertion_count
status
end
##
# Runs all the +suites+ for a given +type+.
#
def _run_suites suites, type
suites.map { |suite| _run_suite suite, type }
end
##
# Run a single +suite+ for a given +type+.
def _run_suite suite, type
header = "#{type}_suite_header"
puts send(header, suite) if respond_to? header
filter = options[:filter] || '/./'
filter = Regexp.new $1 if filter =~ /\/(.*)\//
all_test_methods = suite.send "#{type}_methods"
filtered_test_methods = all_test_methods.find_all { |m|
filter === m || filter === "#{suite}##{m}"
}
leakchecker = LeakChecker.new
assertions = filtered_test_methods.map { |method|
inst = suite.new method
inst._assertions = 0
print "#{suite}##{method} = " if @verbose
start_time = Time.now if @verbose
result = inst.run self
print "%.2f s = " % (Time.now - start_time) if @verbose
print result
puts if @verbose
$stdout.flush
leakchecker.check("#{inst.class}\##{inst.__name__}")
inst._assertions
}
return assertions.size, assertions.inject(0) { |sum, n| sum + n }
end
##
# Record the result of a single test. Makes it very easy to gather
# information. Eg:
#
# class StatisticsRecorder < MiniTest::Unit
# def record suite, method, assertions, time, error
# # ... record the results somewhere ...
# end
# end
#
# MiniTest::Unit.runner = StatisticsRecorder.new
#
# NOTE: record might be sent more than once per test. It will be
# sent once with the results from the test itself. If there is a
# failure or error in teardown, it will be sent again with the
# error or failure.
def record suite, method, assertions, time, error
end
def location e # :nodoc:
last_before_assertion = ""
e.backtrace.reverse_each do |s|
break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/
last_before_assertion = s
end
last_before_assertion.sub(/:in .*$/, '')
end
##
# Writes status for failed test +meth+ in +klass+ which finished with
# exception +e+
def puke klass, meth, e
e = case e
when MiniTest::Skip then
@skips += 1
return "S" unless @verbose
"Skipped:\n#{klass}##{meth} [#{location e}]:\n#{e.message}\n"
when MiniTest::Assertion then
@failures += 1
"Failure:\n#{klass}##{meth} [#{location e}]:\n#{e.message}\n"
else
@errors += 1
bt = MiniTest::filter_backtrace(e.backtrace).join "\n "
"Error:\n#{klass}##{meth}:\n#{e.class}: #{e.message.b}\n #{bt}\n"
end
@report << e
e[0, 1]
end
def initialize # :nodoc:
@report = []
@errors = @failures = @skips = 0
@verbose = false
@mutex = Thread::Mutex.new
@info_signal = Signal.list['INFO']
@repeat_count = nil
end
def synchronize # :nodoc:
if @mutex then
@mutex.synchronize { yield }
else
yield
end
end
def process_args args = [] # :nodoc:
options = {}
orig_args = args.dup
OptionParser.new do |opts|
opts.banner = 'minitest options:'
opts.version = MiniTest::Unit::VERSION
opts.on '-h', '--help', 'Display this help.' do
puts opts
exit
end
opts.on '-s', '--seed SEED', Integer, "Sets random seed" do |m|
options[:seed] = m.to_i
end
opts.on '-v', '--verbose', "Verbose. Show progress processing files." do
options[:verbose] = true
end
opts.on '-n', '--name PATTERN', "Filter test names on pattern (e.g. /foo/)" do |a|
options[:filter] = a
end
opts.parse! args
orig_args -= args
end
unless options[:seed] then
srand
options[:seed] = srand % 0xFFFF
orig_args << "--seed" << options[:seed].to_s
end
srand options[:seed]
self.verbose = options[:verbose]
@help = orig_args.map { |s| s =~ /[\s|&<>$()]/ ? s.inspect : s }.join " "
options
end
##
# Begins the full test run. Delegates to +runner+'s #_run method.
def run args = []
self.class.runner._run(args)
end
##
# Top level driver, controls all output and filtering.
def _run args = []
args = process_args args # ARGH!! blame test/unit process_args
self.options.merge! args
puts "Run options: #{help}"
self.class.plugins.each do |plugin|
send plugin
break unless report.empty?
end
return failures + errors if self.test_count > 0 # or return nil...
rescue Interrupt
abort 'Interrupted'
end
##
# Runs test suites matching +filter+.
def run_tests
_run_anything :test
end
##
# Writes status to +io+
def status io = self.output
format = "%d tests, %d assertions, %d failures, %d errors, %d skips"
io.puts format % [test_count, assertion_count, failures, errors, skips]
end
##
# Provides a simple set of guards that you can use in your tests
# to skip execution if it is not applicable. These methods are
# mixed into TestCase as both instance and class methods so you
# can use them inside or outside of the test methods.
#
# def test_something_for_mri
# skip "bug 1234" if jruby?
# # ...
# end
#
# if windows? then
# # ... lots of test methods ...
# end
module Guard
##
# Is this running on jruby?
def jruby? platform = RUBY_PLATFORM
"java" == platform
end
##
# Is this running on mri?
def maglev? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
"maglev" == platform
end
module_function :maglev?
##
# Is this running on mri?
def mri? platform = RUBY_DESCRIPTION
/^ruby/ =~ platform
end
##
# Is this running on rubinius?
def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
"rbx" == platform
end
##
# Is this running on windows?
def windows? platform = RUBY_PLATFORM
/mswin|mingw/ =~ platform
end
end
##
# Provides before/after hooks for setup and teardown. These are
# meant for library writers, NOT for regular test authors. See
# #before_setup for an example.
module LifecycleHooks
##
# Runs before every test, after setup. This hook is meant for
# libraries to extend minitest. It is not meant to be used by
# test developers.
#
# See #before_setup for an example.
def after_setup; end
##
# Runs before every test, before setup. This hook is meant for
# libraries to extend minitest. It is not meant to be used by
# test developers.
#
# As a simplistic example:
#
# module MyMinitestPlugin
# def before_setup
# super
# # ... stuff to do before setup is run
# end
#
# def after_setup
# # ... stuff to do after setup is run
# super
# end
#
# def before_teardown
# super
# # ... stuff to do before teardown is run
# end
#
# def after_teardown
# # ... stuff to do after teardown is run
# super
# end
# end
#
# class MiniTest::Unit::TestCase
# include MyMinitestPlugin
# end
def before_setup; end
##
# Runs after every test, before teardown. This hook is meant for
# libraries to extend minitest. It is not meant to be used by
# test developers.
#
# See #before_setup for an example.
def before_teardown; end
##
# Runs after every test, after teardown. This hook is meant for
# libraries to extend minitest. It is not meant to be used by
# test developers.
#
# See #before_setup for an example.
def after_teardown; end
end
##
# Subclass TestCase to create your own tests. Typically you'll want a
# TestCase subclass per implementation class.
#
# See MiniTest::Assertions
class TestCase
include LifecycleHooks
include Guard
extend Guard
attr_reader :__name__ # :nodoc:
PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException,
Interrupt, SystemExit] # :nodoc:
##
# Runs the tests reporting the status to +runner+
def run runner
trap "INFO" do
runner.report.each_with_index do |msg, i|
warn "\n%3d) %s" % [i + 1, msg]
end
warn ''
time = runner.start_time ? Time.now - runner.start_time : 0
warn "Current Test: %s#%s %.2fs" % [self.class, self.__name__, time]
runner.status $stderr
end if runner.info_signal
start_time = Time.now
result = ""
begin
@passed = nil
self.before_setup
self.setup
self.after_setup
self.run_test self.__name__
result = "." unless io?
time = Time.now - start_time
runner.record self.class, self.__name__, self._assertions, time, nil
@passed = true
rescue *PASSTHROUGH_EXCEPTIONS
raise
rescue Exception => e
@passed = Skip === e
time = Time.now - start_time
runner.record self.class, self.__name__, self._assertions, time, e
result = runner.puke self.class, self.__name__, e
ensure
%w{ before_teardown teardown after_teardown }.each do |hook|
begin
self.send hook
rescue *PASSTHROUGH_EXCEPTIONS
raise
rescue Exception => e
@passed = false
runner.record self.class, self.__name__, self._assertions, time, e
result = runner.puke self.class, self.__name__, e
end
end
trap 'INFO', 'DEFAULT' if runner.info_signal
end
result
end
alias :run_test :__send__
def initialize name # :nodoc:
@__name__ = name
@__io__ = nil
@passed = nil
@@current = self # FIX: make thread local
end
def self.current # :nodoc:
@@current # FIX: make thread local
end
##
# Return the output IO object
def io
@__io__ = true
MiniTest::Unit.output
end
##
# Have we hooked up the IO yet?
def io?
@__io__
end
def self.reset # :nodoc:
@@test_suites = {}
end
reset
##
# Make diffs for this TestCase use #pretty_inspect so that diff
# in assert_equal can be more details. NOTE: this is much slower
# than the regular inspect but much more usable for complex
# objects.
def self.make_my_diffs_pretty!
require 'pp'
define_method :mu_pp do |o|
o.pretty_inspect
end
end
def self.inherited klass # :nodoc:
@@test_suites[klass] = true
super
end
def self.test_order # :nodoc:
:random
end
def self.test_suites # :nodoc:
@@test_suites.keys.sort_by { |ts| ts.name.to_s }
end
def self.test_methods # :nodoc:
methods = public_instance_methods(true).grep(/^test/).map { |m| m.to_s }
case self.test_order
when :parallel
max = methods.size
ParallelEach.new methods.sort.sort_by { rand max }
when :random then
max = methods.size
methods.sort.sort_by { rand max }
when :alpha, :sorted then
methods.sort
else
raise "Unknown test_order: #{self.test_order.inspect}"
end
end
##
# Returns true if the test passed.
def passed?
@passed
end
##
# Runs before every test. Use this to set up before each test
# run.
def setup; end
##
# Runs after every test. Use this to clean up after each test
# run.
def teardown; end
include MiniTest::Assertions
end # class TestCase
end # class Unit
Test = Unit::TestCase
end # module MiniTest
Minitest = MiniTest # :nodoc: because ugh... I typo this all the time
cmath-1.0.0/test/lib/test/ 0000775 0000000 0000000 00000000000 13213373207 0015311 5 ustar 00root root 0000000 0000000 cmath-1.0.0/test/lib/test/unit.rb 0000664 0000000 0000000 00000102110 13213373207 0016610 0 ustar 00root root 0000000 0000000 # frozen_string_literal: false
begin
gem 'minitest', '< 5.0.0' if defined? Gem
rescue Gem::LoadError
end
require 'minitest/unit'
require 'test/unit/assertions'
require_relative '../envutil'
require 'test/unit/testcase'
require 'optparse'
# See Test::Unit
module Test
##
# Test::Unit is an implementation of the xUnit testing framework for Ruby.
#
# If you are writing new test code, please use MiniTest instead of Test::Unit.
#
# Test::Unit has been left in the standard library to support legacy test
# suites.
module Unit
TEST_UNIT_IMPLEMENTATION = 'test/unit compatibility layer using minitest' # :nodoc:
module RunCount # :nodoc: all
@@run_count = 0
def self.have_run?
@@run_count.nonzero?
end
def run(*)
@@run_count += 1
super
end
def run_once
return if have_run?
return if $! # don't run if there was an exception
yield
end
module_function :run_once
end
module Options # :nodoc: all
def initialize(*, &block)
@init_hook = block
@options = nil
super(&nil)
end
def option_parser
@option_parser ||= OptionParser.new
end
def process_args(args = [])
return @options if @options
orig_args = args.dup
options = {}
opts = option_parser
setup_options(opts, options)
opts.parse!(args)
orig_args -= args
args = @init_hook.call(args, options) if @init_hook
non_options(args, options)
@run_options = orig_args
@help = orig_args.map { |s| s =~ /[\s|&<>$()]/ ? s.inspect : s }.join " "
@options = options
end
private
def setup_options(opts, options)
opts.separator 'minitest options:'
opts.version = MiniTest::Unit::VERSION
opts.on '-h', '--help', 'Display this help.' do
puts opts
exit
end
opts.on '-s', '--seed SEED', Integer, "Sets random seed" do |m|
options[:seed] = m
end
opts.on '-v', '--verbose', "Verbose. Show progress processing files." do
options[:verbose] = true
self.verbose = options[:verbose]
end
opts.on '-n', '--name PATTERN', "Filter test method names on pattern: /REGEXP/, !/REGEXP/ or STRING" do |a|
(options[:filter] ||= []) << a
end
opts.on '--test-order=random|alpha|sorted', [:random, :alpha, :sorted] do |a|
MiniTest::Unit::TestCase.test_order = a
end
end
def non_options(files, options)
filter = options[:filter]
if filter
pos_pat = /\A\/(.*)\/\z/
neg_pat = /\A!\/(.*)\/\z/
negative, positive = filter.partition {|s| neg_pat =~ s}
if positive.empty?
filter = nil
elsif negative.empty? and positive.size == 1 and pos_pat !~ positive[0]
filter = positive[0]
else
filter = Regexp.union(*positive.map! {|s| Regexp.new(s[pos_pat, 1] || "\\A#{Regexp.quote(s)}\\z")})
end
unless negative.empty?
negative = Regexp.union(*negative.map! {|s| Regexp.new(s[neg_pat, 1])})
filter = /\A(?=.*#{filter})(?!.*#{negative})/
end
if Regexp === filter
# bypass conversion in minitest
def filter.=~(other) # :nodoc:
super unless Regexp === other
end
end
options[:filter] = filter
end
true
end
end
module Parallel # :nodoc: all
def process_args(args = [])
return @options if @options
options = super
if @options[:parallel]
@files = args
end
options
end
def non_options(files, options)
@jobserver = nil
if !options[:parallel] and
/(?:\A|\s)--jobserver-(?:auth|fds)=(\d+),(\d+)/ =~ ENV["MAKEFLAGS"]
begin
r = IO.for_fd($1.to_i(10), "rb", autoclose: false)
w = IO.for_fd($2.to_i(10), "wb", autoclose: false)
rescue
r.close if r
nil
else
@jobserver = [r, w]
options[:parallel] ||= 1
end
end
super
end
def status(*args)
result = super
raise @interrupt if @interrupt
result
end
private
def setup_options(opts, options)
super
opts.separator "parallel test options:"
options[:retry] = true
opts.on '-j N', '--jobs N', /\A(t)?(\d+)\z/, "Allow run tests with N jobs at once" do |_, t, a|
options[:testing] = true & t # For testing
options[:parallel] = a.to_i
end
opts.on '--separate', "Restart job process after one testcase has done" do
options[:parallel] ||= 1
options[:separate] = true
end
opts.on '--retry', "Retry running testcase when --jobs specified" do
options[:retry] = true
end
opts.on '--no-retry', "Disable --retry" do
options[:retry] = false
end
opts.on '--ruby VAL', "Path to ruby; It'll have used at -j option" do |a|
options[:ruby] = a.split(/ /).reject(&:empty?)
end
end
class Worker
def self.launch(ruby,args=[])
io = IO.popen([*ruby, "-W1",
"#{File.dirname(__FILE__)}/unit/parallel.rb",
*args], "rb+")
new(io, io.pid, :waiting)
end
attr_reader :quit_called
def initialize(io, pid, status)
@io = io
@pid = pid
@status = status
@file = nil
@real_file = nil
@loadpath = []
@hooks = {}
@quit_called = false
end
def puts(*args)
@io.puts(*args)
end
def run(task,type)
@file = File.basename(task, ".rb")
@real_file = task
begin
puts "loadpath #{[Marshal.dump($:-@loadpath)].pack("m0")}"
@loadpath = $:.dup
puts "run #{task} #{type}"
@status = :prepare
rescue Errno::EPIPE
died
rescue IOError
raise unless /stream closed|closed stream/ =~ $!.message
died
end
end
def hook(id,&block)
@hooks[id] ||= []
@hooks[id] << block
self
end
def read
res = (@status == :quit) ? @io.read : @io.gets
res && res.chomp
end
def close
@io.close unless @io.closed?
self
rescue IOError
end
def quit
return if @io.closed?
@quit_called = true
@io.puts "quit"
end
def kill
Process.kill(:KILL, @pid)
rescue Errno::ESRCH
end
def died(*additional)
@status = :quit
@io.close
status = $?
if status and status.signaled?
additional[0] ||= SignalException.new(status.termsig)
end
call_hook(:dead,*additional)
end
def to_s
if @file and @status != :ready
"#{@pid}=#{@file}"
else
"#{@pid}:#{@status.to_s.ljust(7)}"
end
end
attr_reader :io, :pid
attr_accessor :status, :file, :real_file, :loadpath
private
def call_hook(id,*additional)
@hooks[id] ||= []
@hooks[id].each{|hook| hook[self,additional] }
self
end
end
def after_worker_down(worker, e=nil, c=false)
return unless @options[:parallel]
return if @interrupt
if @jobserver
@jobserver[1] << @job_tokens
@job_tokens.clear
end
warn e if e
real_file = worker.real_file and warn "running file: #{real_file}"
@need_quit = true
warn ""
warn "Some worker was crashed. It seems ruby interpreter's bug"
warn "or, a bug of test/unit/parallel.rb. try again without -j"
warn "option."
warn ""
STDERR.flush
exit c
end
def after_worker_quit(worker)
return unless @options[:parallel]
return if @interrupt
worker.close
if @jobserver and !@job_tokens.empty?
@jobserver[1] << @job_tokens.slice!(0)
end
@workers.delete(worker)
@dead_workers << worker
@ios = @workers.map(&:io)
end
def launch_worker
begin
worker = Worker.launch(@options[:ruby], @run_options)
rescue => e
abort "ERROR: Failed to launch job process - #{e.class}: #{e.message}"
end
worker.hook(:dead) do |w,info|
after_worker_quit w
after_worker_down w, *info if !info.empty? && !worker.quit_called
end
@workers << worker
@ios << worker.io
@workers_hash[worker.io] = worker
worker
end
def delete_worker(worker)
@workers_hash.delete worker.io
@workers.delete worker
@ios.delete worker.io
end
def quit_workers
return if @workers.empty?
@workers.reject! do |worker|
begin
Timeout.timeout(1) do
worker.quit
end
rescue Errno::EPIPE
rescue Timeout::Error
end
worker.close
end
return if @workers.empty?
begin
Timeout.timeout(0.2 * @workers.size) do
Process.waitall
end
rescue Timeout::Error
@workers.each do |worker|
worker.kill
end
@worker.clear
end
end
FakeClass = Struct.new(:name)
def fake_class(name)
(@fake_classes ||= {})[name] ||= FakeClass.new(name)
end
def deal(io, type, result, rep, shutting_down = false)
worker = @workers_hash[io]
cmd = worker.read
cmd.sub!(/\A\.+/, '') if cmd # read may return nil
case cmd
when ''
# just only dots, ignore
when /^okay$/
worker.status = :running
when /^ready(!)?$/
bang = $1
worker.status = :ready
unless task = @tasks.shift
worker.quit
return nil
end
if @options[:separate] and not bang
worker.quit
worker = add_worker
end
worker.run(task, type)
@test_count += 1
jobs_status(worker)
when /^done (.+?)$/
begin
r = Marshal.load($1.unpack("m")[0])
rescue
print "unknown object: #{$1.unpack("m")[0].dump}"
return true
end
result << r[0..1] unless r[0..1] == [nil,nil]
rep << {file: worker.real_file, report: r[2], result: r[3], testcase: r[5]}
$:.push(*r[4]).uniq!
jobs_status(worker) if @options[:job_status] == :replace
return true
when /^record (.+?)$/
begin
r = Marshal.load($1.unpack("m")[0])
rescue => e
print "unknown record: #{e.message} #{$1.unpack("m")[0].dump}"
return true
end
record(fake_class(r[0]), *r[1..-1])
when /^p (.+?)$/
del_jobs_status
print $1.unpack("m")[0]
jobs_status(worker) if @options[:job_status] == :replace
when /^after (.+?)$/
@warnings << Marshal.load($1.unpack("m")[0])
when /^bye (.+?)$/
after_worker_down worker, Marshal.load($1.unpack("m")[0])
when /^bye$/, nil
if shutting_down || worker.quit_called
after_worker_quit worker
else
after_worker_down worker
end
else
print "unknown command: #{cmd.dump}\n"
end
return false
end
def _run_parallel suites, type, result
if @options[:parallel] < 1
warn "Error: parameter of -j option should be greater than 0."
return
end
# Require needed things for parallel running
require 'thread'
require 'timeout'
@tasks = @files.dup # Array of filenames.
@need_quit = false
@dead_workers = [] # Array of dead workers.
@warnings = []
@total_tests = @tasks.size.to_s(10)
rep = [] # FIXME: more good naming
@workers = [] # Array of workers.
@workers_hash = {} # out-IO => worker
@ios = [] # Array of worker IOs
@job_tokens = String.new(encoding: Encoding::ASCII_8BIT) if @jobserver
begin
[@tasks.size, @options[:parallel]].min.times {launch_worker}
while _io = IO.select(@ios)[0]
break if _io.any? do |io|
@need_quit or
(deal(io, type, result, rep).nil? and
!@workers.any? {|x| [:running, :prepare].include? x.status})
end
if @jobserver and @job_tokens and !@tasks.empty? and !@workers.any? {|x| x.status == :ready}
t = @jobserver[0].read_nonblock([@tasks.size, @options[:parallel]].min, exception: false)
if String === t
@job_tokens << t
t.size.times {launch_worker}
end
end
end
rescue Interrupt => ex
@interrupt = ex
return result
ensure
if @interrupt
@ios.select!{|x| @workers_hash[x].status == :running }
while !@ios.empty? && (__io = IO.select(@ios,[],[],10))
__io[0].reject! {|io| deal(io, type, result, rep, true)}
end
end
quit_workers
unless @interrupt || !@options[:retry] || @need_quit
parallel = @options[:parallel]
@options[:parallel] = false
suites, rep = rep.partition {|r| r[:testcase] && r[:file] && r[:report].any? {|e| !e[2].is_a?(MiniTest::Skip)}}
suites.map {|r| r[:file]}.uniq.each {|file| require file}
suites.map! {|r| eval("::"+r[:testcase])}
del_status_line or puts
unless suites.empty?
puts "\n""Retrying..."
_run_suites(suites, type)
end
@options[:parallel] = parallel
end
unless @options[:retry]
del_status_line or puts
end
unless rep.empty?
rep.each do |r|
r[:report].each do |f|
puke(*f) if f
end
end
if @options[:retry]
@errors += rep.map{|x| x[:result][0] }.inject(:+)
@failures += rep.map{|x| x[:result][1] }.inject(:+)
@skips += rep.map{|x| x[:result][2] }.inject(:+)
end
end
unless @warnings.empty?
warn ""
@warnings.uniq! {|w| w[1].message}
@warnings.each do |w|
warn "#{w[0]}: #{w[1].message} (#{w[1].class})"
end
warn ""
end
end
end
def _run_suites suites, type
_prepare_run(suites, type)
@interrupt = nil
result = []
GC.start
if @options[:parallel]
_run_parallel suites, type, result
else
suites.each {|suite|
begin
result << _run_suite(suite, type)
rescue Interrupt => e
@interrupt = e
break
end
}
end
del_status_line
result
end
end
module Skipping # :nodoc: all
def failed(s)
super if !s or @options[:hide_skip]
end
private
def setup_options(opts, options)
super
opts.separator "skipping options:"
options[:hide_skip] = true
opts.on '-q', '--hide-skip', 'Hide skipped tests' do
options[:hide_skip] = true
end
opts.on '--show-skip', 'Show skipped tests' do
options[:hide_skip] = false
end
end
private
def _run_suites(suites, type)
result = super
report.reject!{|r| r.start_with? "Skipped:" } if @options[:hide_skip]
report.sort_by!{|r| r.start_with?("Skipped:") ? 0 : \
(r.start_with?("Failure:") ? 1 : 2) }
failed(nil)
result
end
end
module Statistics
def update_list(list, rec, max)
if i = list.empty? ? 0 : list.bsearch_index {|*a| yield(*a)}
list[i, 0] = [rec]
list[max..-1] = [] if list.size >= max
end
end
def record(suite, method, assertions, time, error)
if @options.values_at(:longest, :most_asserted).any?
@tops ||= {}
rec = [suite.name, method, assertions, time, error]
if max = @options[:longest]
update_list(@tops[:longest] ||= [], rec, max) {|_,_,_,t,_|t