pax_global_header00006660000000000000000000000064132133732070014513gustar00rootroot0000000000000052 comment=977de8de743a391e3b82cad0aa5b94a7d283a207 cmath-1.0.0/000077500000000000000000000000001321337320700126055ustar00rootroot00000000000000cmath-1.0.0/.gitignore000066400000000000000000000001271321337320700145750ustar00rootroot00000000000000/.bundle/ /.yardoc /Gemfile.lock /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /tmp/ cmath-1.0.0/.travis.yml000066400000000000000000000001461321337320700147170ustar00rootroot00000000000000sudo: false language: ruby rvm: - 2.3.5 - 2.4.2 - ruby-head before_install: gem install bundler cmath-1.0.0/Gemfile000066400000000000000000000001321321337320700140740ustar00rootroot00000000000000source 'https://rubygems.org' # Specify your gem's dependencies in cmath.gemspec gemspec cmath-1.0.0/LICENSE.txt000066400000000000000000000024021321337320700144260ustar00rootroot00000000000000Copyright (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.md000066400000000000000000000034111321337320700140630ustar00rootroot00000000000000# CMath [![Build Status](https://travis-ci.org/ruby/cmath.svg?branch=master)](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/Rakefile000066400000000000000000000003241321337320700142510ustar00rootroot00000000000000require "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/000077500000000000000000000000001321337320700133555ustar00rootroot00000000000000cmath-1.0.0/bin/console000077500000000000000000000005241321337320700147460ustar00rootroot00000000000000#!/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/setup000077500000000000000000000002031321337320700144360ustar00rootroot00000000000000#!/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.gemspec000066400000000000000000000017141321337320700152510ustar00rootroot00000000000000# 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/000077500000000000000000000000001321337320700133535ustar00rootroot00000000000000cmath-1.0.0/lib/cmath.rb000066400000000000000000000227501321337320700150020ustar00rootroot00000000000000# 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/000077500000000000000000000000001321337320700135645ustar00rootroot00000000000000cmath-1.0.0/test/lib/000077500000000000000000000000001321337320700143325ustar00rootroot00000000000000cmath-1.0.0/test/lib/envutil.rb000066400000000000000000000200671321337320700163520ustar00rootroot00000000000000# -*- 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.rb000066400000000000000000000011041321337320700177740ustar00rootroot00000000000000# 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.rb000066400000000000000000000120031321337320700171140ustar00rootroot00000000000000# 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/000077500000000000000000000000001321337320700161665ustar00rootroot00000000000000cmath-1.0.0/test/lib/minitest/autorun.rb000066400000000000000000000003201321337320700202030ustar00rootroot00000000000000# 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.rb000066400000000000000000000131631321337320700174500ustar00rootroot00000000000000# 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.rb000066400000000000000000001066111321337320700174770ustar00rootroot00000000000000# 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/000077500000000000000000000000001321337320700153115ustar00rootroot00000000000000cmath-1.0.0/test/lib/test/unit.rb000066400000000000000000001021101321337320700166100ustar00rootroot00000000000000# 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 0 end $stdout.flush if flush @status_line_size = 0 end def add_status(line) @status_line_size ||= 0 if @options[:job_status] == :replace line = line[0...(terminal_width-@status_line_size)] end print line @status_line_size += line.size end def jobs_status(worker) return if !@options[:job_status] or @options[:verbose] if @options[:job_status] == :replace status_line = @workers.map(&:to_s).join(" ") else status_line = worker.to_s end update_status(status_line) or (puts; nil) end def del_jobs_status return unless @options[:job_status] == :replace && @status_line_size.nonzero? del_status_line end def output (@output ||= nil) || super end def _prepare_run(suites, type) options[:job_status] ||= :replace if @tty && !@verbose case options[:color] when :always color = true when :auto, nil color = (@tty || @options[:job_status] == :replace) && /dumb/ !~ ENV["TERM"] else color = false end if color # dircolors-like style colors = (colors = ENV['TEST_COLORS']) ? Hash[colors.scan(/(\w+)=([^:\n]*)/)] : {} begin File.read(File.join(__dir__, "../../colors")).scan(/(\w+)=([^:\n]*)/) do |n, c| colors[n] ||= c end rescue end @passed_color = "\e[;#{colors["pass"] || "32"}m" @failed_color = "\e[;#{colors["fail"] || "31"}m" @skipped_color = "\e[;#{colors["skip"] || "33"}m" @reset_color = "\e[m" else @passed_color = @failed_color = @skipped_color = @reset_color = "" end if color or @options[:job_status] == :replace @verbose = !options[:parallel] end @output = Output.new(self) unless @options[:testing] filter = options[:filter] type = "#{type}_methods" total = if filter suites.inject(0) {|n, suite| n + suite.send(type).grep(filter).size} else suites.inject(0) {|n, suite| n + suite.send(type).size} end @test_count = 0 @total_tests = total.to_s(10) end def new_test(s) @test_count += 1 update_status(s) end def update_status(s) count = @test_count.to_s(10).rjust(@total_tests.size) del_status_line(false) print(@passed_color) add_status("[#{count}/#{@total_tests}]") print(@reset_color) add_status(" #{s}") $stdout.print "\r" if @options[:job_status] == :replace and !@verbose $stdout.flush end def _print(s); $stdout.print(s); end def succeed; del_status_line; end def failed(s) return if s and @options[:job_status] != :replace sep = "\n" @report_count ||= 0 report.each do |msg| if msg.start_with? "Skipped:" if @options[:hide_skip] del_status_line next end color = @skipped_color else color = @failed_color end msg = msg.split(/$/, 2) $stdout.printf("%s%s%3d) %s%s%s\n", sep, color, @report_count += 1, msg[0], @reset_color, msg[1]) sep = nil end report.clear end def initialize super @tty = $stdout.tty? end def run(*args) result = super puts "\nruby -v: #{RUBY_DESCRIPTION}" result end private def setup_options(opts, options) super opts.separator "status line options:" options[:job_status] = nil opts.on '--jobs-status [TYPE]', [:normal, :replace, :none], "Show status of jobs every file; Disabled when --jobs isn't specified." do |type| options[:job_status] = (type || :normal if type != :none) end opts.on '--color[=WHEN]', [:always, :never, :auto], "colorize the output. WHEN defaults to 'always'", "or can be 'never' or 'auto'." do |c| options[:color] = c || :always end opts.on '--tty[=WHEN]', [:yes, :no], "force to output tty control. WHEN defaults to 'yes'", "or can be 'no'." do |c| @tty = c != :no end end class Output < Struct.new(:runner) # :nodoc: all def puts(*a) $stdout.puts(*a) unless a.empty? end def respond_to_missing?(*a) $stdout.respond_to?(*a) end def method_missing(*a, &b) $stdout.__send__(*a, &b) end def print(s) case s when /\A(.*\#.*) = \z/ runner.new_test($1) when /\A(.* s) = \z/ runner.add_status(" = #$1") when /\A\.+\z/ runner.succeed when /\A[EFS]\z/ runner.failed(s) else $stdout.print(s) end end end end module LoadPathOption # :nodoc: all def non_options(files, options) begin require "rbconfig" rescue LoadError warn "#{caller(1)[0]}: warning: Parallel running disabled because can't get path to ruby; run specify with --ruby argument" options[:parallel] = nil else options[:ruby] ||= [RbConfig.ruby] end super end def setup_options(parser, options) super parser.separator "load path options:" parser.on '-Idirectory', 'Add library load path' do |dirs| dirs.split(':').each { |d| $LOAD_PATH.unshift d } end end end module GlobOption # :nodoc: all @@testfile_prefix = "test" @@testfile_suffix = "test" def setup_options(parser, options) super parser.separator "globbing options:" parser.on '-b', '--basedir=DIR', 'Base directory of test suites.' do |dir| options[:base_directory] = dir end parser.on '-x', '--exclude REGEXP', 'Exclude test files on pattern.' do |pattern| (options[:reject] ||= []) << pattern end end def non_options(files, options) paths = [options.delete(:base_directory), nil].uniq if reject = options.delete(:reject) reject_pat = Regexp.union(reject.map {|r| %r"#{r}"}) end files.map! {|f| f = f.tr(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR ((paths if /\A\.\.?(?:\z|\/)/ !~ f) || [nil]).any? do |prefix| if prefix path = f.empty? ? prefix : "#{prefix}/#{f}" else next if f.empty? path = f end if !(match = (Dir["#{path}/**/#{@@testfile_prefix}_*.rb"] + Dir["#{path}/**/*_#{@@testfile_suffix}.rb"]).uniq).empty? if reject match.reject! {|n| n[(prefix.length+1)..-1] if prefix reject_pat =~ n } end break match elsif !reject or reject_pat !~ f and File.exist? path break path end end or raise ArgumentError, "file not found: #{f}" } files.flatten! super(files, options) end end module GCStressOption # :nodoc: all def setup_options(parser, options) super parser.separator "GC options:" parser.on '--[no-]gc-stress', 'Set GC.stress as true' do |flag| options[:gc_stress] = flag end end def non_options(files, options) if options.delete(:gc_stress) MiniTest::Unit::TestCase.class_eval do oldrun = instance_method(:run) define_method(:run) do |runner| begin gc_stress, GC.stress = GC.stress, true oldrun.bind(self).call(runner) ensure GC.stress = gc_stress end end end end super end end module RequireFiles # :nodoc: all def non_options(files, options) return false if !super errors = {} result = false files.each {|f| d = File.dirname(path = File.realpath(f)) unless $:.include? d $: << d end begin require path unless options[:parallel] result = true rescue LoadError next if errors[$!.message] errors[$!.message] = true puts "#{f}: #{$!}" end } result end end module RepeatOption # :nodoc: all def setup_options(parser, options) super options[:repeat_count] = nil parser.separator "repeat options:" parser.on '--repeat-count=NUM', "Number of times to repeat", Integer do |n| options[:repeat_count] = n end end def _run_anything(type) @repeat_count = @options[:repeat_count] super end end module ExcludesOption # :nodoc: all class ExcludedMethods < Struct.new(:excludes) def exclude(name, reason) excludes[name] = reason end def exclude_from(klass) excludes = self.excludes pattern = excludes.keys.grep(Regexp).tap {|k| break (Regexp.new(k.join('|')) unless k.empty?) } klass.class_eval do public_instance_methods(false).each do |method| if excludes[method] or (pattern and pattern =~ method) remove_method(method) end end public_instance_methods(true).each do |method| if excludes[method] or (pattern and pattern =~ method) undef_method(method) end end end end def self.load(dirs, name) return unless dirs and name instance = nil dirs.each do |dir| path = File.join(dir, name.gsub(/::/, '/') + ".rb") begin src = File.read(path) rescue Errno::ENOENT nil else instance ||= new({}) instance.instance_eval(src, path) end end instance end end def setup_options(parser, options) super if excludes = ENV["EXCLUDES"] excludes = excludes.split(File::PATH_SEPARATOR) end options[:excludes] = excludes || [] parser.separator "excludes options:" parser.on '-X', '--excludes-dir DIRECTORY', "Directory name of exclude files" do |d| options[:excludes].concat d.split(File::PATH_SEPARATOR) end end def _run_suite(suite, type) if ex = ExcludedMethods.load(@options[:excludes], suite.name) ex.exclude_from(suite) end super end end module SubprocessOption def setup_options(parser, options) super parser.separator "subprocess options:" parser.on '--subprocess-timeout-scale NUM', "Scale subprocess timeout", Float do |scale| raise OptionParser::InvalidArgument, "timeout scale must be positive" unless scale > 0 options[:timeout_scale] = scale end if scale = options[:timeout_scale] or (scale = ENV["RUBY_TEST_SUBPROCESS_TIMEOUT_SCALE"] and (scale = scale.to_f) > 0) EnvUtil.subprocess_timeout_scale = scale end end end class Runner < MiniTest::Unit # :nodoc: all include Test::Unit::Options include Test::Unit::StatusLine include Test::Unit::Parallel include Test::Unit::Statistics include Test::Unit::Skipping include Test::Unit::GlobOption include Test::Unit::RepeatOption include Test::Unit::LoadPathOption include Test::Unit::GCStressOption include Test::Unit::ExcludesOption include Test::Unit::SubprocessOption include Test::Unit::RunCount class << self; undef autorun; end @@stop_auto_run = false def self.autorun at_exit { Test::Unit::RunCount.run_once { exit(Test::Unit::Runner.new.run(ARGV) || true) } unless @@stop_auto_run } unless @@installed_at_exit @@installed_at_exit = true end alias mini_run_suite _run_suite # Overriding of MiniTest::Unit#puke def puke klass, meth, e # TODO: # this overriding is for minitest feature that skip messages are # hidden when not verbose (-v), note this is temporally. n = report.size rep = super if MiniTest::Skip === e and /no message given\z/ =~ e.message report.slice!(n..-1) rep = "." end rep end end class AutoRunner # :nodoc: all class Runner < Test::Unit::Runner include Test::Unit::RequireFiles end attr_accessor :to_run, :options def initialize(force_standalone = false, default_dir = nil, argv = ARGV) @force_standalone = force_standalone @runner = Runner.new do |files, options| options[:base_directory] ||= default_dir files << default_dir if files.empty? and default_dir @to_run = files yield self if block_given? files end Runner.runner = @runner @options = @runner.option_parser if @force_standalone @options.banner.sub!(/\[options\]/, '\& tests...') end @argv = argv end def process_args(*args) @runner.process_args(*args) !@to_run.empty? end def run if @force_standalone and not process_args(@argv) abort @options.banner end @runner.run(@argv) || true end def self.run(*args) new(*args).run end end class ProxyError < StandardError # :nodoc: all def initialize(ex) @message = ex.message @backtrace = ex.backtrace end attr_accessor :message, :backtrace end end end module MiniTest # :nodoc: all class Unit end end class MiniTest::Unit::TestCase # :nodoc: all test_order = self.test_order class << self attr_writer :test_order undef test_order end def self.test_order defined?(@test_order) ? @test_order : superclass.test_order end self.test_order = test_order undef run_test RUN_TEST_TRACE = "#{__FILE__}:#{__LINE__+3}:in `run_test'".freeze def run_test(name) progname, $0 = $0, "#{$0}: #{self.class}##{name}" self.__send__(name) ensure $@.delete(RUN_TEST_TRACE) if $@ $0 = progname end end Test::Unit::Runner.autorun cmath-1.0.0/test/lib/test/unit/000077500000000000000000000000001321337320700162705ustar00rootroot00000000000000cmath-1.0.0/test/lib/test/unit/assertions.rb000066400000000000000000000715411321337320700210170ustar00rootroot00000000000000# frozen_string_literal: false require 'minitest/unit' require 'pp' module Test module Unit module Assertions include MiniTest::Assertions def mu_pp(obj) #:nodoc: obj.pretty_inspect.chomp end MINI_DIR = File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), "minitest") #:nodoc: # :call-seq: # assert(test, [failure_message]) # #Tests if +test+ is true. # #+msg+ may be a String or a Proc. If +msg+ is a String, it will be used #as the failure message. Otherwise, the result of calling +msg+ will be #used as the message if the assertion fails. # #If no +msg+ is given, a default message will be used. # # assert(false, "This was expected to be true") def assert(test, *msgs) case msg = msgs.first when String, Proc when nil msgs.shift else bt = caller.reject { |s| s.start_with?(MINI_DIR) } raise ArgumentError, "assertion message must be String or Proc, but #{msg.class} was given.", bt end unless msgs.empty? super end # :call-seq: # assert_block( failure_message = nil ) # #Tests the result of the given block. If the block does not return true, #the assertion will fail. The optional +failure_message+ argument is the same as in #Assertions#assert. # # assert_block do # [1, 2, 3].any? { |num| num < 1 } # end def assert_block(*msgs) assert yield, *msgs end # :call-seq: # assert_raise( *args, &block ) # #Tests if the given block raises an exception. Acceptable exception #types may be given as optional arguments. If the last argument is a #String, it will be used as the error message. # # assert_raise do #Fails, no Exceptions are raised # end # # assert_raise NameError do # puts x #Raises NameError, so assertion succeeds # end def assert_raise(*exp, &b) case exp.last when String, Proc msg = exp.pop end 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, message(msg) {"#{mu_pp(exp)} exception expected, not"}.call) } return e end exp = exp.first if exp.size == 1 flunk(message(msg) {"#{mu_pp(exp)} expected but nothing was raised"}) end def assert_raises(*exp, &b) raise NoMethodError, "use assert_raise", caller end # :call-seq: # assert_raise_with_message(exception, expected, msg = nil, &block) # #Tests if the given block raises an exception with the expected #message. # # assert_raise_with_message(RuntimeError, "foo") do # nil #Fails, no Exceptions are raised # end # # assert_raise_with_message(RuntimeError, "foo") do # raise ArgumentError, "foo" #Fails, different Exception is raised # end # # assert_raise_with_message(RuntimeError, "foo") do # raise "bar" #Fails, RuntimeError is raised but the message differs # end # # assert_raise_with_message(RuntimeError, "foo") do # raise "foo" #Raises RuntimeError with the message, so assertion succeeds # end def assert_raise_with_message(exception, expected, msg = nil, &block) case expected when String assert = :assert_equal when Regexp assert = :assert_match else raise TypeError, "Expected #{expected.inspect} to be a kind of String or Regexp, not #{expected.class}" end ex = m = nil EnvUtil.with_default_internal(expected.encoding) do ex = assert_raise(exception, msg || proc {"Exception(#{exception}) with message matches to #{expected.inspect}"}) do yield end m = ex.message end msg = message(msg, "") {"Expected Exception(#{exception}) was raised, but the message doesn't match"} if assert == :assert_equal assert_equal(expected, m, msg) else msg = message(msg) { "Expected #{mu_pp expected} to match #{mu_pp m}" } assert expected =~ m, msg block.binding.eval("proc{|_|$~=_}").call($~) end ex end # :call-seq: # assert_nothing_raised( *args, &block ) # #If any exceptions are given as arguments, the assertion will #fail if one of those exceptions are raised. Otherwise, the test fails #if any exceptions are raised. # #The final argument may be a failure message. # # assert_nothing_raised RuntimeError do # raise Exception #Assertion passes, Exception is not a RuntimeError # end # # assert_nothing_raised do # raise Exception #Assertion fails # end def assert_nothing_raised(*args) self._assertions += 1 if Module === args.last msg = nil else msg = args.pop end begin line = __LINE__; yield rescue MiniTest::Skip raise rescue Exception => e bt = e.backtrace as = e.instance_of?(MiniTest::Assertion) if as ans = /\A#{Regexp.quote(__FILE__)}:#{line}:in /o bt.reject! {|ln| ans =~ ln} end if ((args.empty? && !as) || args.any? {|a| a.instance_of?(Module) ? e.is_a?(a) : e.class == a }) msg = message(msg) { "Exception raised:\n<#{mu_pp(e)}>" } raise MiniTest::Assertion, msg.call, bt else raise end end end # :call-seq: # assert_nothing_thrown( failure_message = nil, &block ) # #Fails if the given block uses a call to Kernel#throw, and #returns the result of the block otherwise. # #An optional failure message may be provided as the final argument. # # assert_nothing_thrown "Something was thrown!" do # throw :problem? # end def assert_nothing_thrown(msg=nil) begin ret = yield rescue ArgumentError => error raise error if /\Auncaught throw (.+)\z/m !~ error.message msg = message(msg) { "<#{$1}> was thrown when nothing was expected" } flunk(msg) end assert(true, "Expected nothing to be thrown") ret end # :call-seq: # assert_throw( tag, failure_message = nil, &block ) # #Fails unless the given block throws +tag+, returns the caught #value otherwise. # #An optional failure message may be provided as the final argument. # # tag = Object.new # assert_throw(tag, "#{tag} was not thrown!") do # throw tag # end def assert_throw(tag, msg = nil) ret = catch(tag) do begin yield(tag) rescue UncaughtThrowError => e thrown = e.tag end msg = message(msg) { "Expected #{mu_pp(tag)} to have been thrown"\ "#{%Q[, not #{thrown}] if thrown}" } assert(false, msg) end assert(true) ret end # :call-seq: # assert_equal( expected, actual, failure_message = nil ) # #Tests if +expected+ is equal to +actual+. # #An optional failure message may be provided as the final argument. def assert_equal(exp, act, msg = nil) msg = message(msg) { exp_str = mu_pp(exp) act_str = mu_pp(act) exp_comment = '' act_comment = '' if exp_str == act_str if (exp.is_a?(String) && act.is_a?(String)) || (exp.is_a?(Regexp) && act.is_a?(Regexp)) exp_comment = " (#{exp.encoding})" act_comment = " (#{act.encoding})" elsif exp.is_a?(Float) && act.is_a?(Float) exp_str = "%\#.#{Float::DIG+2}g" % exp act_str = "%\#.#{Float::DIG+2}g" % act elsif exp.is_a?(Time) && act.is_a?(Time) if exp.subsec * 1000_000_000 == exp.nsec exp_comment = " (#{exp.nsec}[ns])" else exp_comment = " (subsec=#{exp.subsec})" end if act.subsec * 1000_000_000 == act.nsec act_comment = " (#{act.nsec}[ns])" else act_comment = " (subsec=#{act.subsec})" end elsif exp.class != act.class # a subclass of Range, for example. exp_comment = " (#{exp.class})" act_comment = " (#{act.class})" end elsif !Encoding.compatible?(exp_str, act_str) if exp.is_a?(String) && act.is_a?(String) exp_str = exp.dump act_str = act.dump exp_comment = " (#{exp.encoding})" act_comment = " (#{act.encoding})" else exp_str = exp_str.dump act_str = act_str.dump end end "<#{exp_str}>#{exp_comment} expected but was\n<#{act_str}>#{act_comment}" } assert(exp == act, msg) end # :call-seq: # assert_not_nil( expression, failure_message = nil ) # #Tests if +expression+ is not nil. # #An optional failure message may be provided as the final argument. def assert_not_nil(exp, msg=nil) msg = message(msg) { "<#{mu_pp(exp)}> expected to not be nil" } assert(!exp.nil?, msg) end # :call-seq: # assert_not_equal( expected, actual, failure_message = nil ) # #Tests if +expected+ is not equal to +actual+. # #An optional failure message may be provided as the final argument. def assert_not_equal(exp, act, msg=nil) msg = message(msg) { "<#{mu_pp(exp)}> expected to be != to\n<#{mu_pp(act)}>" } assert(exp != act, msg) end # :call-seq: # assert_no_match( regexp, string, failure_message = nil ) # #Tests if the given Regexp does not match a given String. # #An optional failure message may be provided as the final argument. def assert_no_match(regexp, string, msg=nil) assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.") self._assertions -= 1 msg = message(msg) { "<#{mu_pp(regexp)}> expected to not match\n<#{mu_pp(string)}>" } assert(regexp !~ string, msg) end # :call-seq: # assert_not_same( expected, actual, failure_message = nil ) # #Tests if +expected+ is not the same object as +actual+. #This test uses Object#equal? to test equality. # #An optional failure message may be provided as the final argument. # # assert_not_same("x", "x") #Succeeds def assert_not_same(expected, actual, message="") msg = message(msg) { build_message(message, < with id expected to not be equal\\? to with id . EOT assert(!actual.equal?(expected), msg) end # :call-seq: # assert_respond_to( object, method, failure_message = nil ) # #Tests if the given Object responds to +method+. # #An optional failure message may be provided as the final argument. # # assert_respond_to("hello", :reverse) #Succeeds # assert_respond_to("hello", :does_not_exist) #Fails def assert_respond_to(obj, (meth, *priv), msg = nil) unless priv.empty? msg = message(msg) { "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}#{" privately" if priv[0]}" } return assert obj.respond_to?(meth, *priv), msg end #get rid of overcounting if caller_locations(1, 1)[0].path.start_with?(MINI_DIR) return if obj.respond_to?(meth) end super(obj, meth, msg) end # :call-seq: # assert_not_respond_to( object, method, failure_message = nil ) # #Tests if the given Object does not respond to +method+. # #An optional failure message may be provided as the final argument. # # assert_not_respond_to("hello", :reverse) #Fails # assert_not_respond_to("hello", :does_not_exist) #Succeeds def assert_not_respond_to(obj, (meth, *priv), msg = nil) unless priv.empty? msg = message(msg) { "Expected #{mu_pp(obj)} (#{obj.class}) to not respond to ##{meth}#{" privately" if priv[0]}" } return assert !obj.respond_to?(meth, *priv), msg end #get rid of overcounting if caller_locations(1, 1)[0].path.start_with?(MINI_DIR) return unless obj.respond_to?(meth) end refute_respond_to(obj, meth, msg) end # :call-seq: # assert_send( +send_array+, failure_message = nil ) # # Passes if the method send returns a true value. # # +send_array+ is composed of: # * A receiver # * A method # * Arguments to the method # # Example: # assert_send(["Hello world", :include?, "Hello"]) # -> pass # assert_send(["Hello world", :include?, "Goodbye"]) # -> fail def assert_send send_ary, m = nil recv, msg, *args = send_ary m = message(m) { if args.empty? argsstr = "" else (argsstr = mu_pp(args)).sub!(/\A\[(.*)\]\z/m, '(\1)') end "Expected #{mu_pp(recv)}.#{msg}#{argsstr} to return true" } assert recv.__send__(msg, *args), m end # :call-seq: # assert_not_send( +send_array+, failure_message = nil ) # # Passes if the method send doesn't return a true value. # # +send_array+ is composed of: # * A receiver # * A method # * Arguments to the method # # Example: # assert_not_send([[1, 2], :member?, 1]) # -> fail # assert_not_send([[1, 2], :member?, 4]) # -> pass def assert_not_send send_ary, m = nil recv, msg, *args = send_ary m = message(m) { if args.empty? argsstr = "" else (argsstr = mu_pp(args)).sub!(/\A\[(.*)\]\z/m, '(\1)') end "Expected #{mu_pp(recv)}.#{msg}#{argsstr} to return false" } assert !recv.__send__(msg, *args), m end ms = instance_methods(true).map {|sym| sym.to_s } ms.grep(/\Arefute_/) do |m| mname = ('assert_not_' << m.to_s[/.*?_(.*)/, 1]) alias_method(mname, m) unless ms.include? mname end alias assert_include assert_includes alias assert_not_include assert_not_includes def assert_all?(obj, m = nil, &blk) failed = [] obj.each do |*a, &b| unless blk.call(*a, &b) failed << (a.size > 1 ? a : a[0]) end end assert(failed.empty?, message(m) {failed.pretty_inspect}) end def assert_not_all?(obj, m = nil, &blk) failed = [] obj.each do |*a, &b| if blk.call(*a, &b) failed << a.size > 1 ? a : a[0] end end assert(failed.empty?, message(m) {failed.pretty_inspect}) end # compatibility with test-unit alias pend skip def prepare_syntax_check(code, fname = caller_locations(2, 1)[0], mesg = fname.to_s, verbose: nil) code = code.dup.force_encoding(Encoding::UTF_8) verbose, $VERBOSE = $VERBOSE, verbose case when Array === fname fname, line = *fname when defined?(fname.path) && defined?(fname.lineno) fname, line = fname.path, fname.lineno else line = 1 end yield(code, fname, line, mesg) ensure $VERBOSE = verbose end def assert_valid_syntax(code, *args) prepare_syntax_check(code, *args) do |src, fname, line, mesg| yield if defined?(yield) assert_nothing_raised(SyntaxError, mesg) do RubyVM::InstructionSequence.compile(src, fname, fname, line) end end end def assert_syntax_error(code, error, *args) prepare_syntax_check(code, *args) do |src, fname, line, mesg| yield if defined?(yield) e = assert_raise(SyntaxError, mesg) do RubyVM::InstructionSequence.compile(src, fname, fname, line) end assert_match(error, e.message, mesg) end end def assert_normal_exit(testsrc, message = '', child_env: nil, **opt) assert_valid_syntax(testsrc, caller_locations(1, 1)[0]) if child_env child_env = [child_env] else child_env = [] end out, _, status = EnvUtil.invoke_ruby(child_env + %W'-W0', testsrc, true, :merge_to_stdout, **opt) assert !status.signaled?, FailDesc[status, message, out] end FailDesc = proc do |status, message = "", out = ""| pid = status.pid now = Time.now faildesc = proc do if signo = status.termsig signame = Signal.signame(signo) sigdesc = "signal #{signo}" end log = EnvUtil.diagnostic_reports(signame, pid, now) if signame sigdesc = "SIG#{signame} (#{sigdesc})" end if status.coredump? sigdesc << " (core dumped)" end full_message = '' message = message.call if Proc === message if message and !message.empty? full_message << message << "\n" end full_message << "pid #{pid}" full_message << " exit #{status.exitstatus}" if status.exited? full_message << " killed by #{sigdesc}" if sigdesc if out and !out.empty? full_message << "\n#{out.b.gsub(/^/, '| ')}" full_message << "\n" if /\n\z/ !~ full_message end if log full_message << "\n#{log.b.gsub(/^/, '| ')}" end full_message end faildesc end def assert_in_out_err(args, test_stdin = "", test_stdout = [], test_stderr = [], message = nil, success: nil, **opt) stdout, stderr, status = EnvUtil.invoke_ruby(args, test_stdin, true, true, **opt) if signo = status.termsig EnvUtil.diagnostic_reports(Signal.signame(signo), status.pid, Time.now) end if block_given? raise "test_stdout ignored, use block only or without block" if test_stdout != [] raise "test_stderr ignored, use block only or without block" if test_stderr != [] yield(stdout.lines.map {|l| l.chomp }, stderr.lines.map {|l| l.chomp }, status) else all_assertions(message) do |a| [["stdout", test_stdout, stdout], ["stderr", test_stderr, stderr]].each do |key, exp, act| a.for(key) do if exp.is_a?(Regexp) assert_match(exp, act) elsif exp.all? {|e| String === e} assert_equal(exp, act.lines.map {|l| l.chomp }) else assert_pattern_list(exp, act) end end end unless success.nil? a.for("success?") do if success assert_predicate(status, :success?) else assert_not_predicate(status, :success?) end end end end status end end def assert_ruby_status(args, test_stdin="", message=nil, **opt) out, _, status = EnvUtil.invoke_ruby(args, test_stdin, true, :merge_to_stdout, **opt) desc = FailDesc[status, message, out] assert(!status.signaled?, desc) message ||= "ruby exit status is not success:" assert(status.success?, desc) end ABORT_SIGNALS = Signal.list.values_at(*%w"ILL ABRT BUS SEGV TERM") def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **opt) unless file and line loc, = caller_locations(1,1) file ||= loc.path line ||= loc.lineno end src = < marshal_error ignore_stderr = nil end if res if bt = res.backtrace bt.each do |l| l.sub!(/\A-:(\d+)/){"#{file}:#{line + $1.to_i}"} end bt.concat(caller) else res.set_backtrace(caller) end raise res unless SystemExit === res end # really is it succeed? unless ignore_stderr # the body of assert_separately must not output anything to detect error assert(stderr.empty?, FailDesc[status, "assert_separately failed with error message", stderr]) end assert(status.success?, FailDesc[status, "assert_separately failed", stderr]) raise marshal_error if marshal_error end def assert_warning(pat, msg = nil) stderr = EnvUtil.verbose_warning { EnvUtil.with_default_internal(pat.encoding) { yield } } msg = message(msg) {diff pat, stderr} assert(pat === stderr, msg) end def assert_warn(*args) assert_warning(*args) {$VERBOSE = false; yield} end def assert_no_memory_leak(args, prepare, code, message=nil, limit: 2.0, rss: false, **opt) require_relative '../../memory_status' raise MiniTest::Skip, "unsupported platform" unless defined?(Memory::Status) token = "\e[7;1m#{$$.to_s}:#{Time.now.strftime('%s.%L')}:#{rand(0x10000).to_s(16)}:\e[m" token_dump = token.dump token_re = Regexp.quote(token) envs = args.shift if Array === args and Hash === args.first args = [ "--disable=gems", "-r", File.expand_path("../../../memory_status", __FILE__), *args, "-v", "-", ] if defined? Memory::NO_MEMORY_LEAK_ENVS then envs ||= {} newenvs = envs.merge(Memory::NO_MEMORY_LEAK_ENVS) { |_, _, _| break } envs = newenvs if newenvs end args.unshift(envs) if envs cmd = [ 'END {STDERR.puts '"#{token_dump}"'"FINAL=#{Memory::Status.new}"}', prepare, 'STDERR.puts('"#{token_dump}"'"START=#{$initial_status = Memory::Status.new}")', '$initial_size = $initial_status.size', code, 'GC.start', ].join("\n") _, err, status = EnvUtil.invoke_ruby(args, cmd, true, true, **opt) before = err.sub!(/^#{token_re}START=(\{.*\})\n/, '') && Memory::Status.parse($1) after = err.sub!(/^#{token_re}FINAL=(\{.*\})\n/, '') && Memory::Status.parse($1) assert(status.success?, FailDesc[status, message, err]) ([:size, (rss && :rss)] & after.members).each do |n| b = before[n] a = after[n] next unless a > 0 and b > 0 assert_operator(a.fdiv(b), :<, limit, message(message) {"#{n}: #{b} => #{a}"}) end rescue LoadError skip end def assert_is_minus_zero(f) assert(1.0/f == -Float::INFINITY, "#{f} is not -0.0") end def assert_file AssertFile end # pattern_list is an array which contains regexp and :*. # :* means any sequence. # # pattern_list is anchored. # Use [:*, regexp, :*] for non-anchored match. def assert_pattern_list(pattern_list, actual, message=nil) rest = actual anchored = true pattern_list.each_with_index {|pattern, i| if pattern == :* anchored = false else if anchored match = /\A#{pattern}/.match(rest) else match = pattern.match(rest) end unless match msg = message(msg) { expect_msg = "Expected #{mu_pp pattern}\n" if /\n[^\n]/ =~ rest actual_mesg = "to match\n" rest.scan(/.*\n+/) { actual_mesg << ' ' << $&.inspect << "+\n" } actual_mesg.sub!(/\+\n\z/, '') else actual_mesg = "to match #{mu_pp rest}" end actual_mesg << "\nafter #{i} patterns with #{actual.length - rest.length} characters" expect_msg + actual_mesg } assert false, msg end rest = match.post_match anchored = true end } if anchored assert_equal("", rest) end end # threads should respond to shift method. # Array can be used. def assert_join_threads(threads, message = nil) errs = [] values = [] while th = threads.shift begin values << th.value rescue Exception errs << [th, $!] end end if !errs.empty? msg = "exceptions on #{errs.length} threads:\n" + errs.map {|t, err| "#{t.inspect}:\n" + err.backtrace.map.with_index {|line, i| if i == 0 "#{line}: #{err.message} (#{err.class})" else "\tfrom #{line}" end }.join("\n") }.join("\n---\n") if message msg = "#{message}\n#{msg}" end raise MiniTest::Assertion, msg end values end class << (AssertFile = Struct.new(:failure_message).new) include Assertions def assert_file_predicate(predicate, *args) if /\Anot_/ =~ predicate predicate = $' neg = " not" end result = File.__send__(predicate, *args) result = !result if neg mesg = "Expected file " << args.shift.inspect mesg << "#{neg} to be #{predicate}" mesg << mu_pp(args).sub(/\A\[(.*)\]\z/m, '(\1)') unless args.empty? mesg << " #{failure_message}" if failure_message assert(result, mesg) end alias method_missing assert_file_predicate def for(message) clone.tap {|a| a.failure_message = message} end end class AllFailures attr_reader :failures def initialize @count = 0 @failures = {} end def for(key) @count += 1 yield rescue Exception => e @failures[key] = [@count, e] end def message i = 0 total = @count.to_s fmt = "%#{total.size}d" @failures.map {|k, (n, v)| "\n#{i+=1}. [#{fmt%n}/#{total}] Assertion for #{k.inspect}\n#{v.message.b.gsub(/^/, ' | ')}" }.join("\n") end def pass? @failures.empty? end end def assert_all_assertions(msg = nil) all = AllFailures.new yield all ensure assert(all.pass?, message(msg) {all.message.chomp(".")}) end alias all_assertions assert_all_assertions def build_message(head, template=nil, *arguments) #:nodoc: template &&= template.chomp template.gsub(/\G((?:[^\\]|\\.)*?)(\\)?\?/) { $1 + ($2 ? "?" : mu_pp(arguments.shift)) } end def message(msg = nil, *args, &default) # :nodoc: if Proc === msg super(nil, *args) do ary = [msg.call, (default.call if default)].compact.reject(&:empty?) if 1 < ary.length ary[0...-1] = ary[0...-1].map {|str| str.sub(/(?