class MiniTest::Unit::TestCase
def self.bench_exp min, max, base = 10
def self.bench_exp min, max, base = 10 min = (Math.log10(min) / Math.log10(base)).to_i max = (Math.log10(max) / Math.log10(base)).to_i (min..max).map { |m| base ** m }.to_a end
def self.bench_linear min, max, step = 10
def self.bench_linear min, max, step = 10 (min..max).step(step).to_a rescue LocalJumpError # 1.8.6 r = []; (min..max).step(step) { |n| r << n }; r end
def self.bench_range
def self.bench_range bench_exp 1, 10_000 end
def self.benchmark_methods # :nodoc:
def self.benchmark_methods # :nodoc: public_instance_methods(true).grep(/^bench_/).map { |m| m.to_s }.sort end
def self.benchmark_suites
def self.benchmark_suites TestCase.test_suites.reject { |s| s.benchmark_methods.empty? } end
def self.current # :nodoc:
def self.current # :nodoc: @@current end
def self.i_suck_and_my_tests_are_order_dependent!
def self.i_suck_and_my_tests_are_order_dependent! class << self undef_method :test_order if method_defined? :test_order define_method :test_order do :alpha end end end
def self.inherited klass # :nodoc:
def self.inherited klass # :nodoc: @@test_suites[klass] = true klass.reset_setup_teardown_hooks super end
def self.make_my_diffs_pretty!
def self.make_my_diffs_pretty! require 'pp' define_method :mu_pp do |o| o.pretty_inspect end end
def self.parallelize_me!
def self.parallelize_me! class << self undef_method :test_order if method_defined? :test_order define_method :test_order do :parallel end end end
def self.reset # :nodoc:
def self.reset # :nodoc: @@test_suites = {} end
def self.reset_setup_teardown_hooks # :nodoc:
def self.reset_setup_teardown_hooks # :nodoc: # also deprecated... believe it. @setup_hooks = [] @teardown_hooks = [] end
def self.test_methods # :nodoc:
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
def self.test_order # :nodoc:
def self.test_order # :nodoc: :random end
def self.test_suites # :nodoc:
def self.test_suites # :nodoc: @@test_suites.keys.sort_by { |ts| ts.name.to_s } end
def assert_performance validation, &work
def assert_performance validation, &work range = self.class.bench_range io.print "#{__name__}" times = [] range.each do |x| GC.start t0 = Time.now instance_exec(x, &work) t = Time.now - t0 io.print "\t%9.6f" % t times << t end io.puts validation[range, times] end
def assert_performance_constant threshold = 0.99, &work
def assert_performance_constant threshold = 0.99, &work validation = proc do |range, times| a, b, rr = fit_linear range, times assert_in_delta 0, b, 1 - threshold [a, b, rr] end assert_performance validation, &work end
def assert_performance_exponential threshold = 0.99, &work
def assert_performance_exponential threshold = 0.99, &work assert_performance validation_for_fit(:exponential, threshold), &work end
def assert_performance_linear threshold = 0.99, &work
def assert_performance_linear threshold = 0.99, &work assert_performance validation_for_fit(:linear, threshold), &work end
def assert_performance_power threshold = 0.99, &work
def assert_performance_power threshold = 0.99, &work assert_performance validation_for_fit(:power, threshold), &work end
def fit_error xys
def fit_error xys y_bar = sigma(xys) { |x, y| y } / xys.size.to_f ss_tot = sigma(xys) { |x, y| (y - y_bar) ** 2 } ss_err = sigma(xys) { |x, y| (yield(x) - y) ** 2 } 1 - (ss_err / ss_tot) end
def fit_exponential xs, ys
def fit_exponential xs, ys n = xs.size xys = xs.zip(ys) sxlny = sigma(xys) { |x,y| x * Math.log(y) } slny = sigma(xys) { |x,y| Math.log(y) } sx2 = sigma(xys) { |x,y| x * x } sx = sigma xs c = n * sx2 - sx ** 2 a = (slny * sx2 - sx * sxlny) / c b = ( n * sxlny - sx * slny ) / c return Math.exp(a), b, fit_error(xys) { |x| Math.exp(a + b * x) } end
def fit_linear xs, ys
def fit_linear xs, ys n = xs.size xys = xs.zip(ys) sx = sigma xs sy = sigma ys sx2 = sigma(xs) { |x| x ** 2 } sxy = sigma(xys) { |x,y| x * y } c = n * sx2 - sx**2 a = (sy * sx2 - sx * sxy) / c b = ( n * sxy - sx * sy ) / c return a, b, fit_error(xys) { |x| a + b * x } end
def fit_power xs, ys
def fit_power xs, ys n = xs.size xys = xs.zip(ys) slnxlny = sigma(xys) { |x, y| Math.log(x) * Math.log(y) } slnx = sigma(xs) { |x | Math.log(x) } slny = sigma(ys) { | y| Math.log(y) } slnx2 = sigma(xs) { |x | Math.log(x) ** 2 } b = (n * slnxlny - slnx * slny) / (n * slnx2 - slnx ** 2); a = (slny - b * slnx) / n return Math.exp(a), b, fit_error(xys) { |x| (Math.exp(a) * (x ** b)) } end
def initialize name # :nodoc:
def initialize name # :nodoc: @__name__ = name @__io__ = nil @passed = nil @@current = self end
def io
def io @__io__ = true MiniTest::Unit.output end
def io?
def io? @__io__ end
def passed?
def passed? @passed end
def run 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 SUPPORTS_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 = false 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 result = runner.puke self.class, self.__name__, e end end trap 'INFO', 'DEFAULT' if SUPPORTS_INFO_SIGNAL end result end
def setup; end
def setup; end
def sigma enum, &block
def sigma enum, &block enum = enum.map(&block) if block enum.inject { |sum, n| sum + n } end
def teardown; end
def teardown; end
def validation_for_fit msg, threshold
def validation_for_fit msg, threshold proc do |range, times| a, b, rr = send "fit_#{msg}", range, times assert_operator rr, :>=, threshold [a, b, rr] end end