require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))


class TestRound < Minitest::Test


  def setup
    initialize_context
  end


  def test_round

    assert_equal(101,  DecNum('100.5').round)
    assert DecNum('100.5').round.kind_of?(Integer)
    assert_equal 100, DecNum('100.4999999999').round
    assert_equal(-101, DecNum('-100.5').round)
    assert_equal(-100, DecNum('-100.4999999999').round)

    assert_equal 101, DecNum('100.5').round(:places=>0)
    assert DecNum('100.5').round(:places=>0).kind_of?(DecNum)
    assert_equal 101, DecNum('100.5').round(0)
    assert DecNum('100.5').round(0).kind_of?(DecNum)

    assert_equal DecNum('123.12'), DecNum('123.123').round(2)
    assert_equal DecNum('123'), DecNum('123.123').round(0)
    assert_equal DecNum('120'), DecNum('123.123').round(-1)
    assert_equal DecNum('120'), DecNum('123.123').round(:precision=>2)
    assert_equal DecNum('123.12'), DecNum('123.123').round(:precision=>5)

    assert_equal 100, DecNum('100.5').round(:rounding=>:half_even)
    assert_equal 101, DecNum('100.5000001').round(:rounding=>:half_even)
    assert_equal 102, DecNum('101.5').round(:rounding=>:half_even)
    assert_equal 101, DecNum('101.4999999999').round(:rounding=>:half_even)

    assert_equal 101, DecNum('100.0001').ceil
    assert_equal(-100, DecNum('-100.0001').ceil)
    assert_equal(-100, DecNum('-100.9999').ceil)
    assert_equal 100, DecNum('100.9999').floor
    assert_equal(-101, DecNum('-100.9999').floor)
    assert_equal(-101, DecNum('-100.0001').floor)

    assert_equal 100, DecNum('100.99999').truncate
    assert_equal(-100, DecNum('-100.99999').truncate)

    assert_equal(10,  DecNum('9.99999').round(:rounding=>:half_up))
    assert_equal(1,  DecNum('0.999999').round(:rounding=>:half_up))
    assert_equal(0,  DecNum('0.0999999').round(:rounding=>:half_up))
    assert_equal(1,  DecNum('0.0999999').round(:rounding=>:up))

  end

  def test_ruby_2_4_round
    assert_equal 100, DecNum('100.5').round(:half => :even)
    assert_equal 101, DecNum('100.5000001').round(:half => :even)
    assert_equal 102, DecNum('101.5').round(:half => :even)
    assert_equal 101, DecNum('101.4999999999').round(:half => :even)

    assert_equal 100, DecNum('100.5').round(:half => :down)
    assert_equal 101, DecNum('100.5000001').round(:half => :down)
    assert_equal 101, DecNum('101.5').round(:half => :down)
    assert_equal 101, DecNum('101.4999999999').round(:half => :down)

    assert_equal 101, DecNum('100.5').round(:half => :up)
    assert_equal 101, DecNum('100.5000001').round(:half => :up)
    assert_equal 102, DecNum('101.5').round(:half => :up)
    assert_equal 101, DecNum('101.4999999999').round(:half => :up)

    assert_equal 101, DecNum('100.5').round(0)
    assert_equal DecNum('100.5'), DecNum('100.5').round(1)
    assert_equal 100, DecNum('100.5').round(-1)
    assert_equal DecNum('100.1235'), DecNum('100.1235'), DecNum('100.12345').round(4)

    assert_equal 100, DecNum('100.5').round(0, :half => :even)
    assert_equal 101, DecNum('100.5').round(0, :half => :up)
    assert_equal 100, DecNum('100.5').round(0, :half => :down)
    assert_equal DecNum('100.5'), DecNum('100.5').round(1, half: :even)
    assert_equal DecNum('100.5'), DecNum('100.5').round(1, half: :up)
    assert_equal DecNum('100.5'), DecNum('100.5').round(1, half: :down)
    assert_equal 100, DecNum('100.5').round(-1, half: :even)
    assert_equal 100, DecNum('100.5').round(-1, half: :down)
    assert_equal 100, DecNum('100.5').round(-1, half: :up)
    assert_equal DecNum('100.1234'), DecNum('100.12345').round(4, half: :even)
    assert_equal DecNum('100.1235'), DecNum('100.12345').round(4, half: :up)
    assert_equal DecNum('100.1234'), DecNum('100.12345').round(4, half: :down)
  end

  def detect_rounding(type)
    x = type.new(1)*type.int_radix_power(type.context.precision+1)
    y = x + type.int_radix_power(2)
    h = type.radix/2
    b = h*type.radix
    z = type.new(type.int_radix_power(2) - 1)
    type.context do
      type.context.precision = 8 if type.context.exact?
      if x + 1 == y
        if (y + 1 == y) && type.radix==10
          :up05
        elsif -x - 1 == -y
          :up
        else
          :ceiling
        end
      else # x + 1 == x
        if x + z == x
          if -x - z == -x
            :down
          else
            :floor
          end
        else # x + z == y
          # round to nearest
          if x + b == x
            if y + b == y
              :half_down
            else
              :half_even
            end
          else # x + b == y
            :half_up
          end
        end
      end
    end
  end

  def test_round_detection
    [DecNum, BinNum].each do |type|
      [:half_even, :half_up, :half_down, :down, :up, :floor, :ceiling, :up05].each do |rounding|
        type.context(:rounding=>rounding) do
          next if type==BinNum && rounding==:up05
          assert_equal rounding, detect_rounding(type)
        end
      end
    end
  end


end
