local ROT = require 'src.rot'
local expect = require 'tests.expect' (assert)

describe("RNG", function()
    describe("getUniform", function()
        local value = ROT.RNG:getUniform()
        it("should return a number", function()
            expect(type(value)).toEqual("number")
        end)
        it("should return a number 0..1", function()
            expect(value).toBeGreaterThan(0)
            expect(value).toBeLessThan(1)
        end)
    end)

    describe("getUniformInt", function()
    local lowerBound = 5
    local upperBound = 10
        it("should return a number", function()
          local value = ROT.RNG:getUniformInt(lowerBound, upperBound)
            expect(type(value)).toEqual("number")
        end)
        it("should not care which number is larger in the arguments", function()
            local seed = math.floor(math.random()*1000000)
            ROT.RNG:setSeed(seed)
            local val1 = ROT.RNG:getUniformInt(lowerBound, upperBound)
            ROT.RNG:setSeed(seed)
            local val2 = ROT.RNG:getUniformInt(upperBound, lowerBound)
            expect(val1).toEqual(val2)
        end)
        it("should only return a number in the desired range", function()
            local value = ROT.RNG:getUniformInt(lowerBound, upperBound)
            local value2 = ROT.RNG:getUniformInt(upperBound, lowerBound)
            expect(value).NOT.toBeGreaterThan(upperBound)
            expect(value).NOT.toBeLessThan(lowerBound)
            expect(value2).NOT.toBeGreaterThan(upperBound)
            expect(value2).NOT.toBeLessThan(lowerBound)
        end)
    end)

    describe("seeding", function()
        it("should return a seed number", function()
            expect(type(ROT.RNG:getSeed())).toEqual("number")
        end)

        it("should return the same value for a given seed", function()
            local seed = math.floor(os.time()*1000000)
            ROT.RNG:setSeed(seed)
            local val1 = ROT.RNG:getUniform()
            ROT.RNG:setSeed(seed)
            local val2 = ROT.RNG:getUniform()
            expect(val1).toEqual(val2)
        end)

        it("should return a precomputed value for a given seed", function()
            ROT.RNG:setSeed(12345)
            local val = ROT.RNG:getUniform()
            -- expect(val).toEqual(0.01198604702949524)
            -- We expect the same value the original Alea/Mash would give
            expect(val).toEqual(0.27138191112317144871)

        end)
    end)

    describe("state manipulation", function()
        it("should return identical values after setting identical states", function()
            ROT.RNG:getUniform()

            local state = ROT.RNG:getState()
            local val1 = ROT.RNG:getUniform()
            ROT.RNG:setState(state)
            local val2 = ROT.RNG:getUniform()

            expect(val1).toEqual(val2)
        end)
    end)

    describe("cloning", function()
        it("should be able to clone a RNG", function()
            local clone = ROT.RNG:clone()
            expect(type(clone)).toEqual("table")
        end)

        it("should clone a working RNG", function()
            local clone = ROT.RNG:clone()
            local num = clone:getUniform()
            expect(type(num)).toEqual("number")
        end)

        it("should clone maintaining its state", function()
            local clone = ROT.RNG:clone()
            local num1 = ROT.RNG:getUniform()
            local num2 = clone:getUniform()
            expect(num1).toEqual(num2)
        end)
    end)

end)

