class MiniTest::Unit::TestCase

def self.add_setup_hook arg=nil, &block

def self.add_setup_hook arg=nil, &block
  hook = arg || block
  @setup_hooks << hook
end

def self.add_teardown_hook arg=nil, &block

def self.add_teardown_hook arg=nil, &block
  hook = arg || block
  @teardown_hooks << hook
end

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:

: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:

: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
    define_method :test_order do :alpha end
  end
end

def self.inherited klass # :nodoc:

:nodoc:
def self.inherited klass # :nodoc:
  @@test_suites[klass] = true
  klass.reset_setup_teardown_hooks
  super
end

def self.reset # :nodoc:

:nodoc:
def self.reset # :nodoc:
  @@test_suites = {}
end

def self.reset_setup_teardown_hooks # :nodoc:

:nodoc:
def self.reset_setup_teardown_hooks # :nodoc:
  @setup_hooks = []
  @teardown_hooks = []
end

def self.setup_hooks # :nodoc:

:nodoc:
def self.setup_hooks # :nodoc:
  if superclass.respond_to? :setup_hooks then
    superclass.setup_hooks
  else
    []
  end + @setup_hooks
end

def self.teardown_hooks # :nodoc:

:nodoc:
def self.teardown_hooks # :nodoc:
  if superclass.respond_to? :teardown_hooks then
    superclass.teardown_hooks
  else
    []
  end + @teardown_hooks
end

def self.test_methods # :nodoc:

:nodoc:
def self.test_methods # :nodoc:
  methods = public_instance_methods(true).grep(/^test/).map { |m| m.to_s }
  case self.test_order
  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:

:nodoc:
def self.test_order # :nodoc:
  :random
end

def self.test_suites # :nodoc:

: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:

: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
    time = runner.start_time ? Time.now - runner.start_time : 0
    warn "%s#%s %.2fs" % [self.class, self.__name__, time]
    runner.status $stderr
  end if SUPPORTS_INFO_SIGNAL
  result = ""
  begin
    @passed = nil
    self.setup
    self.run_setup_hooks
    self.__send__ self.__name__
    result = "." unless io?
    @passed = true
  rescue *PASSTHROUGH_EXCEPTIONS
    raise
  rescue Exception => e
    @passed = false
    result = runner.puke self.class, self.__name__, e
  ensure
    begin
      self.run_teardown_hooks
      self.teardown
    rescue *PASSTHROUGH_EXCEPTIONS
      raise
    rescue Exception => e
      result = runner.puke self.class, self.__name__, e
    end
    trap 'INFO', 'DEFAULT' if SUPPORTS_INFO_SIGNAL
  end
  result
end

def run_setup_hooks # :nodoc:

:nodoc:
def run_setup_hooks # :nodoc:
  self.class.setup_hooks.each do |hook|
    if hook.respond_to?(:arity) && hook.arity == 1
      hook.call(self)
    else
      hook.call
    end
  end
end

def run_teardown_hooks # :nodoc:

:nodoc:
def run_teardown_hooks # :nodoc:
  self.class.teardown_hooks.reverse.each do |hook|
    if hook.respond_to?(:arity) && hook.arity == 1
      hook.call(self)
    else
      hook.call
    end
  end
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