local math = require('math')

local luaunit = require('luaunit')

local cache = require('webshield.builtins.cache')
local class = require('webshield.builtins.class')
local etable = require('webshield.builtins.etable')


TestCache = {}

    function TestCache.test_cached_return_value()
        local test_cache = cache.Cache()
        math.randomseed(os.time())

        local function rnd()
            return math.random()
        end

        local r1 = rnd()
        local r2 = rnd()

        luaunit.assertNotEquals(r1, r2)

        rnd = test_cache(rnd)

        local r3 = rnd()
        local r4 = rnd()

        luaunit.assertEquals(r3, r4)

        test_cache:invalidate()

        local r5 = rnd()
        local r6 = rnd()

        luaunit.assertNotEquals(r4, r5)
        luaunit.assertEquals(r5, r6)
    end

    function TestCache.test_cached_return_multiple_values()
        local test_cache = cache.Cache()

        local function f()
            return 1, 2
        end

        f = test_cache(f)

        local res = {f()}

        luaunit.assertEquals(res, {1, 2})
    end


local Class1 = class()
    Class1.x = 'x1'

local Class2 = class()
    function Class2.__init(self)
        self.y = 'y2'
    end

local Class3 = class(Class2)
    function Class3.__init(self)
        Class3.__super().__init(self)
        self.z = 'z3'
    end

local Class4 = class(Class1, Class2)
    Class4.x = 'x4'
    Class4.z = 'z4'


TestClass = {}

    function TestClass.test_class_attribute()
        local obj = Class1()
        luaunit.assertEquals(obj.x, Class1.x)
    end

    function TestClass.test_instance_attribute()
        local obj = Class2()
        luaunit.assertIsNil(Class2.y)
        luaunit.assertNotNil(obj.y)
    end

    function TestClass.test_inheritance()
        local obj = Class3()
        luaunit.assertEquals(obj.x, Class3.x)
        luaunit.assertIsNil(Class3.y)
        luaunit.assertIsNil(Class3.z)
        -- Class2.__init called explicitly via Class3.__super().__init
        luaunit.assertNotNil(obj.y)
        luaunit.assertNotNil(obj.z)
    end

    function TestClass.test_multiple_inheritance()
        local obj = Class4()
        luaunit.assertIsNil(Class4.y)
        luaunit.assertNotNil(Class4.z)
        luaunit.assertEquals(obj.x, Class4.x)
        -- Class2.__init called implicitly
        luaunit.assertNotNil(obj.y)
        luaunit.assertEquals(obj.z, Class4.z)
    end


TestEtable = {}

    function TestEtable.test_equal_keys()
        local t = {}
        local et = etable()
        local k1 = {1}
        local k2 = {1}

        t[k1] = {123}
        et[k1] = {456}

        luaunit.assertNotIs(k1, k2)
        luaunit.assertIsNil(t[k2])
        luaunit.assertIs(et[k1], et[k2])
    end

    function TestEtable.test_init_value()
        local et = etable({hello = 'world'})
        luaunit.assertEquals(et.hello, 'world')
    end


os.exit(luaunit.LuaUnit.run())
