require 'runit/testcase'
require 'runit/assert'
require 'runit/cui/testrunner'

class TargetAssert
  include RUNIT::Assert
  public :float_to_str
end

class TestAssert < RUNIT::TestCase
  def setup
    @assert = TargetAssert.new
    @e = nil
  end

  def test_float_to_str
    f = 0.1
    e = 0.01
    assert_equal("0.100", @assert.float_to_str(f, e))
    assert_equal(0.01, e)
    assert_equal(0.1, f)
  end

  def test_assert
    sub_test_assert_pass(true)
    sub_test_assert_pass(TRUE)
    sub_test_assert_failure(false, "<false:FalseClass>")
    sub_test_assert_failure(FALSE, "<false:FalseClass>")
    assert_exception(TypeError) {
      @assert.assert(nil)
    }
    assert_exception(TypeError) {
      @assert.assert("")
    }
    assert_exception(TypeError) {
      @assert.assert("ok")
    }
    assert_exception(TypeError) {
      @assert.assert(1)
    }
    assert_exception(TypeError) {
      @assert.assert(0)
    }
    except = assert_exception(RUNIT::AssertionFailedError) {
      @assert.assert(false)
    }
#    assert_match(/testassert.rb.*in.*test_assert/, except.backtrace[0])
  end

  def test_assert_with_2_argument
    assert_no_exception {
      assert(true, "3")
    }
    assert_no_exception {
      assert(true)
    }
  end

  def test_assert_equal_float_0_1
    run_asserts = RUNIT::Assert.run_asserts
    assert_proc = Proc.new {
      @assert.assert_equal_float(1.4, 1.35, 0.1)
    }
    sub_assert_pass(assert_proc)
    after_run_asserts = RUNIT::Assert.run_asserts - run_asserts
    assert_equal(2, after_run_asserts)
  end

  def test_assert_equal_float_0_5
    run_asserts = RUNIT::Assert.run_asserts
    assert_proc = Proc.new {
      @assert.assert_equal_float(1.4, 1.34, 0.5)
    }
    sub_assert_pass(assert_proc)
    after_run_asserts = RUNIT::Assert.run_asserts - run_asserts
    assert_equal(2, after_run_asserts)
  end

  def test_assert_equal_float_0
    assert_proc = Proc.new {
      @assert.assert_equal_float(1.4, 1.4, 0)
    }
    sub_assert_pass(assert_proc)
  end

  def test_assert_equal_float_0_raise
    assert_proc = Proc.new {
      @assert.assert_equal_float(1.4, 1.34, 0)
    }
    sub_assert_raise_fail(assert_proc, 'expected:<1.4> but was:<1.34>')
  end

  def test_assert_equal_float_0_01
    assert_proc = Proc.new {
      @assert.assert_equal_float(1.4, 1.35, 0.01)
    }
    sub_assert_raise_fail(assert_proc, 'expected:<1.400> but was:<1.350>')
  end

  def test_assert_equal_float_0_001
    assert_proc = Proc.new {
      @assert.assert_equal_float(Math.sqrt(2), 1.414, 0.001)
    }
    sub_assert_pass(assert_proc)
  end

  def test_assert_equal_float_minus_1_0
    assert_proc = Proc.new {
      @assert.assert_equal_float(1.4, 1.35, -1.0)
    }
    sub_assert_raise_error(assert_proc, '-1.0: 3rd argument should be 0 or greater than 0.')
  end

  def test_assert_fail
    except = nil
    begin
      @assert.assert_fail("failure")
    rescue
      except = $!
    end
    assert_not_nil(except)
#    assert_match(/testassert.rb.*in.*test_assert_fail/, except.backtrace[0])
  end

  def sub_test_assert_pass(obj)
    assert_proc = Proc.new {
      @assert.assert(obj)
    }
    sub_assert_pass(assert_proc)
  end

  def sub_test_assert_failure(obj, msg)
    assert_proc = Proc.new {
      @assert.assert(obj)
    }
    sub_assert_raise_fail(assert_proc, 'The condition is ' + msg)
  end

  def test_assert_equal
    assert_proc = Proc.new {
      @assert.assert_equal(2, 2)
    }
    sub_assert_pass(assert_proc)
    assert_proc = Proc.new {
      @assert.assert_equal(2, 3)
    }
    sub_assert_raise_fail(assert_proc, 'expected:<2> but was:<3>')
  end

  def test_assert_nil
    obj = nil
    assert_proc = Proc.new {
      @assert.assert_nil(obj)
    }
    sub_assert_pass(assert_proc)
    obj = 'string'
    sub_assert_raise_fail(assert_proc, '<string:String> is not nil')
  end

  def test_assert_not_nil
    obj = 'string'
    assert_proc = Proc.new {
      @assert.assert_not_nil(obj)
    }
    sub_assert_pass(assert_proc)

    obj = nil
    sub_assert_raise_fail(assert_proc, 'object is nil')
  end

  def test_assert_operator
    assert_proc = Proc.new {
      @assert.assert_operator(2, :<, 3)
    }
    sub_assert_pass(assert_proc)
    assert_proc = Proc.new {
      @assert.assert_operator(2, :>, 3)
    }
    sub_assert_raise_fail(assert_proc, 'The condition is not satisfied: 2 > 3')
  end

  def test_assert_respond_to
    sub_test_assert_respond_to('string', 'sub', 'foo', '<string:String> does not respond to <foo>')
    sub_test_assert_respond_to('string', :sub, :foo, '<string:String> does not respond to <foo>')
  end

  def sub_test_assert_respond_to(obj, msg, dummy_msg, err_string)
    assert_proc = Proc.new {
      @assert.assert_respond_to(msg, obj)
    }
    sub_assert_pass(assert_proc)
    assert_proc = Proc.new {
      @assert.assert_respond_to(dummy_msg, obj)
    }
    sub_assert_raise_fail(assert_proc, err_string)
  end

  def test_assert_send
    assert_proc = Proc.new {
      ary = []
      @assert.assert_send ary, :empty?
    }
    sub_assert_pass(assert_proc)
    assert_proc = Proc.new {
      ary = [2,3]
      @assert.assert_send ary, :empty?
    }
    sub_assert_raise_fail(assert_proc, "Assertion failed: Array([2, 3])#empty?")
    assert_proc = Proc.new {
      str = "abc"
      @assert.assert_send str, :sub!, "z", "y"
    }
    sub_assert_raise_fail(assert_proc, 'Assertion failed: String("abc")#sub!(<"z":String>, <"y":String>)')
  end

  def test_assert_kind_of
    assert_proc = Proc.new {
      @assert.assert_kind_of(String, "string")
    }
    sub_assert_pass(assert_proc)
    assert_proc = Proc.new {
      @assert.assert_kind_of(Regexp, "string")
    }
    sub_assert_raise_fail(assert_proc, '<string:String> is not kind of <Regexp>')
  end

  def test_assert_instance_of
    assert_proc = Proc.new {
      @assert.assert_instance_of(String, "string")
    }
    sub_assert_pass(assert_proc)
    assert_proc = Proc.new {
      @assert.assert_instance_of(Object, "string")
    }
    sub_assert_raise_fail(assert_proc, '<string:String> is not instance of <Object>')
  end

  def test_assert_match
    assert_proc = Proc.new{
      @assert.assert_match('foostring', /foo/)
    }
    sub_assert_pass(assert_proc)
    assert_proc = Proc.new {
      @assert.assert_match('barstring', /foo/)
    }
    sub_assert_raise_fail(assert_proc, '</foo/> not match <barstring>')
    match = @assert.assert_match('foostring', /foo/)
    assert_instance_of(MatchData, match)
    assert_equal('foo', match[0])
  end

  def test_assert_matches
    assert_proc = Proc.new{
      @assert.assert_matches('foostring', /foo/)
    }
    sub_assert_pass(assert_proc)
    assert_proc = Proc.new {
      @assert.assert_matches('barstring', /foo/)
    }
    sub_assert_raise_fail(assert_proc, '</foo/> not match <barstring>')
  end

  def test_assert_not_match
    assert_proc = Proc.new{
      @assert.assert_not_match('barstring', /foo/)
    }
    sub_assert_pass(assert_proc)
    assert_proc = Proc.new {
      @assert.assert_not_match('foostring', /foo/)
    }
    sub_assert_raise_fail(assert_proc, '</foo/> matches \'foo\' of <foostring>')
    assert_proc = Proc.new {
      @assert.assert_not_match('foobarbaz', /ba.+/)
    }
    sub_assert_raise_fail(assert_proc, '</ba.+/> matches \'barbaz\' of <foobarbaz>')
  end

  def test_assert_same
    flag = false
    e = "foo"
    a = e
    assert_proc = Proc.new {@assert.assert_same(e, a)}
    sub_assert_pass(assert_proc)

    a = "foo"
    sub_assert_raise_fail(assert_proc, '<foo:String> is not same object: <foo:String>')
  end

  def test_assert_exception
    assert_proc = Proc.new{
      @assert.assert_exception(IOError) {
	raise IOError
      }
    }
    sub_assert_pass(assert_proc)

    assert_proc = Proc.new{
      @assert.assert_exception(StandardError) {
	raise IOError
      }
    }
    sub_assert_raise_fail(assert_proc, "expected:<StandardError> but was:<IOError>")

    assert_proc = Proc.new{
      @assert.assert_exception(IOError, "Exception") {
	raise StandardError
      }
    }
    sub_assert_raise_fail(assert_proc, "Exception expected:<IOError> but was:<StandardError>")

    assert_proc = Proc.new {
      @assert.assert_exception(StandardError) {
	"No Exception raised in this block"
      }
    }
    sub_assert_raise_fail(assert_proc, 'expected:<StandardError> but was:<NO EXCEPTION RAISED>')

    assert_proc = Proc.new {
      @assert.assert_exception(StandardError) {
	exit(33)
      }
    }
    sub_assert_raise_fail(assert_proc, 'expected:<StandardError> but was:<SystemExit>')

    t = @assert.assert_exception(IOError) {
      raise IOError
    }
    assert_instance_of(IOError, t)
    t = @assert.assert_exception(ArgumentError) {
      Math.sqrt(-1)
    }
    assert_instance_of(ArgumentError, t)
    t = @assert.assert_exception(SystemExit) {
      exit(33)
    }
    assert_instance_of(SystemExit, t)
  end

  def test_assert_no_exception
    assert_proc = Proc.new{
      @assert.assert_no_exception(IOError, ArgumentError) {
	"No Exception raised in this block"
      }
    }
    sub_assert_pass(assert_proc)

    assert_proc = Proc.new{
      @assert.assert_no_exception(IOError, ArgumentError) {
	raise StandardError, "Standard Error raised"
      }
    }
    sub_assert_raise_error(assert_proc, "Standard Error raised")

    assert_proc = Proc.new{
      @assert.assert_no_exception(IOError, ArgumentError) {
	raise ArgumentError, "Bad Argument"
      }
    }
    sub_assert_raise_fail(assert_proc, "Exception raised:#<ArgumentError: Bad Argument>")

    assert_proc = Proc.new{
      @assert.assert_no_exception {
        raise ArgumentError, "Bad Argument"
      }
    }
    sub_assert_raise_fail(assert_proc, "Exception raised:#<ArgumentError: Bad Argument>")

    assert_proc = Proc.new{
      @assert.assert_no_exception {
        raise NameError, "Bad Name"
      }
    }
    sub_assert_raise_fail(assert_proc, "Exception raised:#<NameError: Bad Name>")
    assert_proc = Proc.new {
      @assert.assert_no_exception {
	raise NoMemoryError
      }
    }
    sub_assert_raise_fail(assert_proc, "Exception raised:#<NoMemoryError: NoMemoryError>")
  end

  def sub_assert_pass(p)
    flag = false
    err = nil
    begin
      p.call
      flag = true
    rescue
      err = $!
      flag = false
    end
    assert(flag, err.to_s)
  end

  def sub_assert_raise_fail(p, msg)
    flag = false
    err = nil
    begin
      p.call
      flag = false
    rescue RUNIT::AssertionFailedError
      flag = true
      err = $!
    rescue Exception
      flag = false
      err = $!
    end
    assert(flag, err.to_s)
    assert_equal(msg, err.to_s)
  end
    
  def sub_assert_raise_error(p, msg=nil)
    flag = false
    err = nil
    begin
      p.call
      flag = false
    rescue RUNIT::AssertionFailedError
      flag = false
      err = $!
    rescue Exception
      flag = true
      err = $!
    end
    assert(flag, err.to_s)
    assert_equal(msg, err.to_s) if msg
  end
end

if $0 == __FILE__
  RUNIT::CUI::TestRunner.run(TestAssert.suite)
end


