local c=require(script.Parent)return function()describe("\067\108\097\115\115",function()it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \099\114\101\097\116\101 \099\108\097\115\115\101\115",function()(expect(c())).to.be.a("\116\097\098\108\101")end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \105\110\104\101\114\105\116 \099\108\097\115\115\101\115",function()local K=c()local w=(c()):Extend(K)function K.test(c)return 5 end;(expect(w)).to.be.a("\116\097\098\108\101");(expect((w()):test())).to.equal(5)local Z=(c()):Extend(w);(expect((Z()):test())).to.equal(5)end)end)describe("\079\098\106\101\099\116",function()it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \099\114\101\097\116\101 \111\098\106\101\099\116\115",function()(expect((c())())).to.be.a("\116\097\098\108\101")end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \097\099\099\101\115\115 \115\117\112\101\114\099\108\097\115\115\101\115",function()local K=c()local w=(c()):Extend(K)local Z=(c()):Extend(w)local m=K()local D=w()local C=Z();(expect(m:GetClass())).to.equal(K);(expect(D:GetClass())).to.equal(w);(expect((D:GetClass()):GetExtendedClass())).to.equal(K);(expect(C:GetClass())).to.equal(Z);(expect((C:GetClass()):GetExtendedClass())).to.equal(w);(expect(((C:GetClass()):GetExtendedClass()):GetExtendedClass())).to.equal(K)end)it("\115\104\111\117\108\100 \099\097\108\108 \105\110\105\116 \109\101\116\104\111\100\115",function()local K=c()function K.init(c)c.a=5 end local w=K();(expect(w.a)).to.equal(5)w.a=10;(expect(w.a)).to.equal(10)end)local K=Instance.new("\080\097\114\116")it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \119\114\097\112 \105\110\115\116\097\110\099\101\115",function()(expect(function()((c())()):WrapInstance(K)end)).to.be.ok()end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \097\099\099\101\115\115 \082\066\088 \097\116\116\114\105\098\117\116\101\115",function()local w=((c())()):WrapInstance(K)w:SetAttribute("\116\101\115\116","\116\101\115\116");(expect(w:GetAttribute("\116\101\115\116"))).to.equal("\116\101\115\116")w:WrapAttribute("\116\101\115\116");(expect(w.test)).to.equal("\116\101\115\116")end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \097\099\099\101\115\115 \082\066\088 \112\114\111\112\101\114\116\105\101\115 \097\110\100 \101\118\101\110\116\115",function()local w=((c())()):WrapInstance(K);(expect(w:GetProperty("\078\097\109\101"))).to.be.a("\115\116\114\105\110\103");(expect(typeof(w:GetEvent("\084\111\117\099\104\101\100"))=="\082\066\088\083\099\114\105\112\116\083\105\103\110\097\108")).to.equal(true)w:WrapProperty("\078\097\109\101")w:WrapEvent("\084\111\117\099\104\101\100");(expect(w.Name)).to.be.a("\115\116\114\105\110\103");(expect(typeof(w.Touched)=="\082\066\088\083\099\114\105\112\116\083\105\103\110\097\108")).to.equal(true)end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \097\099\099\101\115\115 \082\066\088 \109\101\116\104\111\100\115",function()local w=((c())()):WrapInstance(K);(expect(w:GetMethod("\067\108\111\110\101"))).to.be.a("\102\117\110\099\116\105\111\110")w:WrapMethod("\067\108\111\110\101");(expect(w.Clone)).to.be.a("\102\117\110\099\116\105\111\110")end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \102\105\110\100 \119\114\097\112\112\101\100 \105\110\100\101\120\101\115",function()local w=((c())()):WrapInstance(K,{[c.Attributes]={"\119\114\097\112\112\101\100\073\110\100\101\120\065\116\116\114\105\098\117\116\101"};[c.Events]={"\084\111\117\099\104\101\100"};[c.Methods]={"\067\108\111\110\101"},[c.Properties]={"\078\097\109\101"}});(expect(w.wrappedIndexAttribute)).to.be.equal(nil)w.wrappedIndexAttribute=5;(expect(w.wrappedIndexAttribute)).to.be.equal(5);(expect((w:GetWrappedInstance()):GetAttribute("\119\114\097\112\112\101\100\073\110\100\101\120\065\116\116\114\105\098\117\116\101"))).to.be.equal(5);(expect(typeof(w.Touched)=="\082\066\088\083\099\114\105\112\116\083\105\103\110\097\108")).to.be.equal(true);(expect(w.Clone)).to.be.a("\102\117\110\099\116\105\111\110");(expect(w.Name)).to.be.a("\115\116\114\105\110\103")w.Name="\119\114\097\112\112\101\100";(expect(w.Name)).to.be.equal("\119\114\097\112\112\101\100");(expect((w:GetWrappedInstance()).Name)).to.be.equal("\119\114\097\112\112\101\100")end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \099\108\097\115\115 \099\104\101\099\107",function()(expect(((c())()):IsA())).to.equal(false);(expect(((c("\102\111\111\098\097\114"))()):IsA("\102\111\111\098\097\114"))).to.equal(true)local K=(c("\102\111\111")):Extend(c("\098\097\114"));(expect((K()):IsA("\102\111\111"))).to.equal(true);(expect((K()):IsA("\098\097\114"))).to.equal(true);(expect((K()):IsA("\098\097\114",true))).to.equal(false)end)end)describe("\067\108\097\115\115 \109\111\100\117\108\101",function()local K=c()local w=(c()):Extend(K)local Z=K()local m=w()it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \116\121\112\101\099\104\101\099\107 \099\108\097\115\115\101\115",function()(expect(c.isClass(K))).to.equal(true);(expect(c.isClass(w))).to.equal(true);(expect(c.isClass(Z))).to.equal(false);(expect(c.isClass(m))).to.equal(false)end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \116\121\112\101\099\104\101\099\107 \111\098\106\101\099\116\115",function()(expect(c.isObject(K))).to.equal(false);(expect(c.isObject(w))).to.equal(false);(expect(c.isObject(Z))).to.equal(true);(expect(c.isObject(m))).to.equal(true)end)end)end
local Class = require(script.Parent)

return function()
    describe("Class", function()
        it("should be able to create classes", function()
            expect(Class()).to.be.a("table")
        end)

        it("should be able to inherit classes", function()
            local classA = Class()
            local classB = Class():Extend(classA)

            function classA:test()
                return 5
            end

            expect(classB).to.be.a("table")
            expect(classB():test()).to.equal(5)

            -- Deep inheritance
            local classC = Class():Extend(classB)
            expect(classC():test()).to.equal(5)
        end)
    end)

    describe("Object", function()
        it("should be able to create objects", function()
            expect(Class()()).to.be.a("table")
        end)

        it("should be able to access superclasses", function()
            local classA = Class()
            local classB = Class():Extend(classA)
            local classC = Class():Extend(classB)

            local objA = classA()
            local objB = classB()
            local objC = classC()

            expect(objA:GetClass()).to.equal(classA)

            expect(objB:GetClass()).to.equal(classB)
            expect(objB:GetClass():GetExtendedClass()).to.equal(classA)

            expect(objC:GetClass()).to.equal(classC)
            expect(objC:GetClass():GetExtendedClass()).to.equal(classB)
            expect(objC:GetClass():GetExtendedClass():GetExtendedClass()).to.equal(classA)
        end)

        it("should call init methods", function()
            local class = Class()

            function class:init()
                self.a = 5
            end

            local obj = class()
            expect(obj.a).to.equal(5)

            obj.a = 10

            expect(obj.a).to.equal(10)
        end)

        local instance = Instance.new("Part")
        it("should be able to wrap instances", function()
            expect(function()
                Class()():WrapInstance(instance)
            end).to.be.ok()
        end)

        it("should be able to access RBX attributes", function()
            local obj = Class()():WrapInstance(instance)
            obj:SetAttribute("test", "test")

            expect(obj:GetAttribute("test")).to.equal("test")

            obj:WrapAttribute("test")

            expect(obj.test).to.equal("test")
        end)

        it("should be able to access RBX properties and events", function()
            local obj = Class()():WrapInstance(instance)
            expect(obj:GetProperty("Name")).to.be.a("string")
            expect(typeof(obj:GetEvent("Touched")) == "RBXScriptSignal").to.equal(true)

            obj:WrapProperty("Name")
            obj:WrapEvent("Touched")

            expect(obj.Name).to.be.a("string")
            expect(typeof(obj.Touched) == "RBXScriptSignal").to.equal(true)
        end)

        it("should be able to access RBX methods", function()
            local obj = Class()():WrapInstance(instance)
            expect(obj:GetMethod("Clone")).to.be.a("function")

            obj:WrapMethod("Clone")

            expect(obj.Clone).to.be.a("function")
        end)

        it("should be able to find wrapped indexes", function()
            local obj = Class()():WrapInstance(instance, {
                [Class.Attributes] = {
                    "wrappedIndexAttribute",
                },
                [Class.Events] = {
                    "Touched",
                },
                [Class.Methods] = {
                    "Clone",
                },
                [Class.Properties] = {
                    "Name",
                },
            })

            expect(obj.wrappedIndexAttribute).to.be.equal(nil)
            obj.wrappedIndexAttribute = 5
            expect(obj.wrappedIndexAttribute).to.be.equal(5)
            expect(obj:GetWrappedInstance():GetAttribute("wrappedIndexAttribute")).to.be.equal(5)

            expect(typeof(obj.Touched) == "RBXScriptSignal").to.be.equal(true)
            expect(obj.Clone).to.be.a("function")
            expect(obj.Name).to.be.a("string")

            obj.Name = "wrapped"
            expect(obj.Name).to.be.equal("wrapped")
            expect(obj:GetWrappedInstance().Name).to.be.equal("wrapped")
        end)

        it("should be able to class check", function()
            expect(Class()():IsA()).to.equal(false)

            expect(Class("foobar")():IsA("foobar")).to.equal(true)

            local extendedClass = Class("foo"):Extend(Class("bar"))
            expect(extendedClass():IsA("foo")).to.equal(true)
            expect(extendedClass():IsA("bar")).to.equal(true)
            expect(extendedClass():IsA("bar", true)).to.equal(false)
        end)
    end)

    describe("Class module", function()
        local class = Class()
        local extendedClass = Class():Extend(class)
        local object = class()
        local extendedClassObject = extendedClass()

        it("should be able to typecheck classes", function()
            expect(Class.isClass(class)).to.equal(true)
            expect(Class.isClass(extendedClass)).to.equal(true)
            expect(Class.isClass(object)).to.equal(false)
            expect(Class.isClass(extendedClassObject)).to.equal(false)
        end)

        it("should be able to typecheck objects", function()
            expect(Class.isObject(class)).to.equal(false)
            expect(Class.isObject(extendedClass)).to.equal(false)
            expect(Class.isObject(object)).to.equal(true)
            expect(Class.isObject(extendedClassObject)).to.equal(true)
        end)
    end)
end
