return function()local m=require(script.Parent.Server)local q=require(script.Parent.RemoteEventServer)describe("\082\101\109\111\116\101\069\118\101\110\116\083\101\114\118\101\114\058\102\105\114\101\067\108\105\101\110\116",function()it("\115\104\111\117\108\100 \102\105\114\101 \116\104\101 \115\112\101\099\105\102\105\101\100 \099\108\105\101\110\116 \114\101\109\111\116\101 \101\118\101\110\116 \119\105\116\104 \116\104\101 \112\097\115\115\101\100 \097\114\103\115",function()local q=m.new()local x=q:connect("\117\115\101\114\048")local L=q:connect("\117\115\101\114\049")local E=q:createRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116");(x:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")).OnClientEvent:connect(function(m,q)(expect(m)).to.equal(0);(expect(q)).to.equal(1)end);(L:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")).OnClientEvent:connect(function(m,q)(expect(m)).to.equal(2);(expect(q)).to.equal(3)end)E:fireClient(x,0,1)E:fireClient(L,2,3)q:destroy()end)it("\115\104\111\117\108\100 \113\117\101\117\101 \112\097\115\115\101\100 \097\114\103\115 \111\110 \099\108\105\101\110\116 \117\110\116\105\108 \097\110 \097\099\116\105\118\097\116\105\110\103 \099\111\110\110\101\099\116\105\111\110 \105\115 \109\097\100\101 \116\111 \116\104\101 \115\112\101\099\105\102\105\101\100 \114\101\109\111\116\101\069\118\101\110\116\067\108\105\101\110\116 \079\110\067\108\105\101\110\116\069\118\101\110\116 \115\105\103\110\097\108",function()local q=m.new()local x=q:connect("\117\115\101\114\048")local L=q:connect("\117\115\101\114\049")local E=q:createRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")E:fireClient(x,0,1)E:fireClient(L,2,3);(x:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")).OnClientEvent:connect(function(m,q)(expect(m)).to.equal(0);(expect(q)).to.equal(1)end);(L:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")).OnClientEvent:connect(function(m,q)(expect(m)).to.equal(2);(expect(q)).to.equal(3)end)q:destroy()end)it("\115\104\111\117\108\100 \116\104\114\111\119 \105\102 \116\097\098\108\101\115 \119\105\116\104 \099\121\099\108\105\099 \118\097\108\117\101\115 \097\114\101 \112\097\115\115\101\100",function()local q=m.new()local x=q:connect("\117\115\101\114")local L=q:createRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")local E={a=1}E.b=E;(expect(function()L:fireClient(x,E)end)).to.throw()q:destroy()end)it("\115\104\111\117\108\100 \112\097\115\115 \100\101\101\112 \099\111\112\105\101\115 \111\102 \100\097\116\097 \097\110\100 \099\111\110\118\101\114\116 \105\110\115\116\097\110\099\101 \097\110\100 \116\097\098\108\101 \107\101\121\115 \116\111 \115\116\114\105\110\103\115",function()local q=m.new()local x=q:connect("\117\115\101\114")local L=q:createRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")local E=Instance.new("\080\097\114\116")local A={ok=1}local b={a={[E]=1},b={key=2};[A]=3}L:fireClient(x,b,b,E)local i,t,I=(x:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")).OnClientEvent:wait();(expect(i)).to.never.equal(b);(expect(t)).to.never.equal(b);(expect(i)).to.never.equal(t);(expect(i.a[E])).to.never.be.ok();(expect(i.a["\060\073\110\115\116\097\110\099\101\062 \040\080\097\114\116\041"])).to.equal(1);(expect(t.a[E])).to.never.be.ok();(expect(t.a["\060\073\110\115\116\097\110\099\101\062 \040\080\097\114\116\041"])).to.equal(1);(expect(i[A])).to.never.be.ok();(expect(i["\060\084\097\098\108\101\062 \040"..(tostring(A).."\041")])).to.equal(3);(expect(t[A])).to.never.be.ok();(expect(t["\060\084\097\098\108\101\062 \040"..(tostring(A).."\041")])).to.equal(3);(expect(I)).to.equal(E)E:Destroy()q:destroy()end)end)describe("\082\101\109\111\116\101\069\118\101\110\116\083\101\114\118\101\114\058\102\105\114\101\065\108\108\067\108\105\101\110\116\115",function()it("\115\104\111\117\108\100 \102\105\114\101 \116\104\101 \115\112\101\099\105\102\105\101\100 \099\108\105\101\110\116 \114\101\109\111\116\101 \101\118\101\110\116 \102\111\114 \097\108\108 \099\108\105\101\110\116\115 \119\105\116\104 \116\104\101 \112\097\115\115\101\100 \097\114\103\115",function()local q=m.new()local x=q:connect("\117\115\101\114\048")local L=q:connect("\117\115\101\114\049")local E=q:createRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116");(x:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")).OnClientEvent:connect(function(m,q)(expect(m)).to.equal(0);(expect(q)).to.equal(1)end);(L:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")).OnClientEvent:connect(function(m,q)(expect(m)).to.equal(0);(expect(q)).to.equal(1)end)E:fireAllClients(0,1)q:destroy()end)it("\115\104\111\117\108\100 \113\117\101\117\101 \112\097\115\115\101\100 \097\114\103\115 \111\110 \099\108\105\101\110\116\115 \117\110\116\105\108 \097\110 \097\099\116\105\118\097\116\105\110\103 \099\111\110\110\101\099\116\105\111\110 \105\115 \109\097\100\101 \116\111 \116\104\101 \099\108\105\101\110\116\'\115 \114\101\109\111\116\101\069\118\101\110\116\067\108\105\101\110\116 \079\110\067\108\105\101\110\116\069\118\101\110\116 \115\105\103\110\097\108",function()local q=m.new()local x=q:connect("\117\115\101\114\048")local L=q:connect("\117\115\101\114\049")local E=q:createRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")E:fireAllClients(0,1);(x:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")).OnClientEvent:connect(function(m,q)(expect(m)).to.equal(0);(expect(q)).to.equal(1)end);(L:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")).OnClientEvent:connect(function(m,q)(expect(m)).to.equal(0);(expect(q)).to.equal(1)end)q:destroy()end)it("\115\104\111\117\108\100 \116\104\114\111\119 \105\102 \116\097\098\108\101\115 \119\105\116\104 \099\121\099\108\105\099 \118\097\108\117\101\115 \097\114\101 \112\097\115\115\101\100",function()local q=m.new()local x=q:createRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")local L={a=1}L.b=L;(expect(function()x:fireAllClients(L)end)).to.throw()q:destroy()end)it("\115\104\111\117\108\100 \112\097\115\115 \100\101\101\112 \099\111\112\105\101\115 \111\102 \100\097\116\097 \097\110\100 \099\111\110\118\101\114\116 \105\110\115\116\097\110\099\101 \097\110\100 \116\097\098\108\101 \107\101\121\115 \116\111 \115\116\114\105\110\103\115",function()local q=m.new()local x=q:connect("\117\115\101\114\049")local L=q:connect("\117\115\101\114\050")local E=q:createRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")local A=Instance.new("\080\097\114\116")local b={ok=1}local i={a={[A]=1},b={key=2};[b]=3}E:fireAllClients(i,i,A)local t,I,z=(x:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")).OnClientEvent:wait()local e,F,n=(L:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")).OnClientEvent:wait();(expect(t)).to.never.equal(i);(expect(I)).to.never.equal(i);(expect(t)).to.never.equal(I);(expect(t.a[A])).to.never.be.ok();(expect(t.a["\060\073\110\115\116\097\110\099\101\062 \040\080\097\114\116\041"])).to.equal(1);(expect(I.a[A])).to.never.be.ok();(expect(I.a["\060\073\110\115\116\097\110\099\101\062 \040\080\097\114\116\041"])).to.equal(1);(expect(t[b])).to.never.be.ok();(expect(t["\060\084\097\098\108\101\062 \040"..(tostring(b).."\041")])).to.equal(3);(expect(I[b])).to.never.be.ok();(expect(I["\060\084\097\098\108\101\062 \040"..(tostring(b).."\041")])).to.equal(3);(expect(z)).to.equal(A);(expect(e)).to.never.equal(i);(expect(F)).to.never.equal(i);(expect(e)).to.never.equal(F);(expect(e.a[A])).to.never.be.ok();(expect(e.a["\060\073\110\115\116\097\110\099\101\062 \040\080\097\114\116\041"])).to.equal(1);(expect(F.a[A])).to.never.be.ok();(expect(F.a["\060\073\110\115\116\097\110\099\101\062 \040\080\097\114\116\041"])).to.equal(1);(expect(e[b])).to.never.be.ok();(expect(e["\060\084\097\098\108\101\062 \040"..(tostring(b).."\041")])).to.equal(3);(expect(F[b])).to.never.be.ok();(expect(F["\060\084\097\098\108\101\062 \040"..(tostring(b).."\041")])).to.equal(3);(expect(n)).to.equal(A)A:Destroy()q:destroy()end)end)describe("\082\101\109\111\116\101\069\118\101\110\116\083\101\114\118\101\114\058\100\101\115\116\114\111\121",function()it("\115\104\111\117\108\100 \114\101\109\111\118\101 \097\115\115\111\099\105\097\116\101\100 \099\108\105\101\110\116 \115\105\100\101\100 \114\101\109\111\116\101 \101\118\101\110\116\115 \102\111\114 \101\097\099\104 \099\108\105\101\110\116",function()local q=m.new()local x=q:connect("\117\115\101\114\048")local L=q:connect("\117\115\101\114\049")local E=q:createRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116");(expect(x:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116"))).to.be.ok();(expect(L:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116"))).to.be.ok()E:destroy();(expect(function()x:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")end)).to.throw();(expect(function()L:getRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")end)).to.throw()q:destroy()end)it("\115\104\111\117\108\100 \115\101\116 \100\101\115\116\114\111\121\101\100 \102\105\101\108\100 \116\111 \116\114\117\101",function()local q=m.new()local x=q:createRemoteEvent("\114\101\109\111\116\101\069\118\101\110\116")x:destroy();(expect(x.destroyed)).to.equal(true)q:destroy()end)end)end
return function()
    local Server = require(script.Parent.Server)
    local RemoteEventServer = require(script.Parent.RemoteEventServer)

    describe("RemoteEventServer:fireClient", function()
        it("should fire the specified client remote event with the passed args", function()
            local server = Server.new()
            local user0 = server:connect("user0")
            local user1 = server:connect("user1")

            local remoteEvent = server:createRemoteEvent("remoteEvent")

            user0:getRemoteEvent("remoteEvent").OnClientEvent:connect(function(value0, value1)
                expect(value0).to.equal(0)
                expect(value1).to.equal(1)
            end)

            user1:getRemoteEvent("remoteEvent").OnClientEvent:connect(function(value2, value3)
                expect(value2).to.equal(2)
                expect(value3).to.equal(3)
            end)

            remoteEvent:fireClient(user0, 0, 1)
            remoteEvent:fireClient(user1, 2, 3)

            server:destroy()
        end)

        it("should queue passed args on client until an activating connection is made to the specified remoteEventClient OnClientEvent signal", function()
            local server = Server.new()
            local user0 = server:connect("user0")
            local user1 = server:connect("user1")

            local remoteEvent = server:createRemoteEvent("remoteEvent")

            remoteEvent:fireClient(user0, 0, 1)
            remoteEvent:fireClient(user1, 2, 3)

            user0:getRemoteEvent("remoteEvent").OnClientEvent:connect(function(value0, value1)
                expect(value0).to.equal(0)
                expect(value1).to.equal(1)
            end)

            user1:getRemoteEvent("remoteEvent").OnClientEvent:connect(function(value2, value3)
                expect(value2).to.equal(2)
                expect(value3).to.equal(3)
            end)

            server:destroy()
        end)

        it("should throw if tables with cyclic values are passed", function()
            local server = Server.new()
            local user = server:connect("user")
            
            local remoteEvent = server:createRemoteEvent("remoteEvent")

            local data = {
                a = 1,
            }

            data.b = data

            expect(function()
                remoteEvent:fireClient(user, data)
            end).to.throw()

            server:destroy()
        end)

        it("should pass deep copies of data and convert instance and table keys to strings", function()
            local server = Server.new()
            local user = server:connect("user")
            
            local remoteEvent = server:createRemoteEvent("remoteEvent")

            local part = Instance.new("Part")

            local tab = {ok = 1}

            local data = {
                a = {[part] = 1},
                b = {key = 2},
                [tab] = 3,
            }

            remoteEvent:fireClient(user, data, data, part)

            local data1, data2, passedPart = user:getRemoteEvent("remoteEvent").OnClientEvent:wait()

            expect(data1).to.never.equal(data)
            expect(data2).to.never.equal(data)

            expect(data1).to.never.equal(data2)

            expect(data1.a[part]).to.never.be.ok()
            expect(data1.a["<Instance> (Part)"]).to.equal(1)
            
            expect(data2.a[part]).to.never.be.ok()
            expect(data2.a["<Instance> (Part)"]).to.equal(1)

            expect(data1[tab]).to.never.be.ok()
            expect(data1["<Table> ("..tostring(tab)..")"]).to.equal(3)

            expect(data2[tab]).to.never.be.ok()
            expect(data2["<Table> ("..tostring(tab)..")"]).to.equal(3)

            expect(passedPart).to.equal(part)

            part:Destroy()
            server:destroy()
        end)
    end)

    describe("RemoteEventServer:fireAllClients", function()
        it("should fire the specified client remote event for all clients with the passed args", function()
            local server = Server.new()
            local user0 = server:connect("user0")
            local user1 = server:connect("user1")

            local remoteEvent = server:createRemoteEvent("remoteEvent")

            user0:getRemoteEvent("remoteEvent").OnClientEvent:connect(function(value0, value1)
                expect(value0).to.equal(0)
                expect(value1).to.equal(1)
            end)

            user1:getRemoteEvent("remoteEvent").OnClientEvent:connect(function(value2, value3)
                expect(value2).to.equal(0)
                expect(value3).to.equal(1)
            end)

            remoteEvent:fireAllClients(0, 1)

            server:destroy()
        end)

        it("should queue passed args on clients until an activating connection is made to the client's remoteEventClient OnClientEvent signal", function()
            local server = Server.new()
            local user0 = server:connect("user0")
            local user1 = server:connect("user1")

            local remoteEvent = server:createRemoteEvent("remoteEvent")

            remoteEvent:fireAllClients(0, 1)

            user0:getRemoteEvent("remoteEvent").OnClientEvent:connect(function(value0, value1)
                expect(value0).to.equal(0)
                expect(value1).to.equal(1)
            end)

            user1:getRemoteEvent("remoteEvent").OnClientEvent:connect(function(value2, value3)
                expect(value2).to.equal(0)
                expect(value3).to.equal(1)
            end)

            server:destroy()
        end)

        it("should throw if tables with cyclic values are passed", function()
            local server = Server.new()
            local remoteEvent = server:createRemoteEvent("remoteEvent")

            local data = {
                a = 1,
            }

            data.b = data

            expect(function()
                remoteEvent:fireAllClients(data)
            end).to.throw()

            server:destroy()
        end)

        it("should pass deep copies of data and convert instance and table keys to strings", function()
            local server = Server.new()
            local user1 = server:connect("user1")
            local user2 = server:connect("user2")

            local remoteEvent = server:createRemoteEvent("remoteEvent")

            local part = Instance.new("Part")

            local tab = {ok = 1}

            local data = {
                a = {[part] = 1},
                b = {key = 2},
                [tab] = 3,
            }

            remoteEvent:fireAllClients(data, data, part)

            local user1Data1, user1Data2, user1PassedPart = user1:getRemoteEvent("remoteEvent").OnClientEvent:wait()
            local user2Data1, user2Data2, user2PassedPart = user2:getRemoteEvent("remoteEvent").OnClientEvent:wait()

            expect(user1Data1).to.never.equal(data)
            expect(user1Data2).to.never.equal(data)

            expect(user1Data1).to.never.equal(user1Data2)

            expect(user1Data1.a[part]).to.never.be.ok()
            expect(user1Data1.a["<Instance> (Part)"]).to.equal(1)

            expect(user1Data2.a[part]).to.never.be.ok()
            expect(user1Data2.a["<Instance> (Part)"]).to.equal(1)

            expect(user1Data1[tab]).to.never.be.ok()
            expect(user1Data1["<Table> ("..tostring(tab)..")"]).to.equal(3)

            expect(user1Data2[tab]).to.never.be.ok()
            expect(user1Data2["<Table> ("..tostring(tab)..")"]).to.equal(3)

            expect(user1PassedPart).to.equal(part)

            expect(user2Data1).to.never.equal(data)
            expect(user2Data2).to.never.equal(data)

            expect(user2Data1).to.never.equal(user2Data2)

            expect(user2Data1.a[part]).to.never.be.ok()
            expect(user2Data1.a["<Instance> (Part)"]).to.equal(1)

            expect(user2Data2.a[part]).to.never.be.ok()
            expect(user2Data2.a["<Instance> (Part)"]).to.equal(1)

            expect(user2Data1[tab]).to.never.be.ok()
            expect(user2Data1["<Table> ("..tostring(tab)..")"]).to.equal(3)

            expect(user2Data2[tab]).to.never.be.ok()
            expect(user2Data2["<Table> ("..tostring(tab)..")"]).to.equal(3)

            expect(user2PassedPart).to.equal(part)

            part:Destroy()
            server:destroy()
        end)
    end)

    describe("RemoteEventServer:destroy", function()
        it("should remove associated client sided remote events for each client", function()
            local server = Server.new()
            local user0 = server:connect("user0")
            local user1 = server:connect("user1")

            local remoteEvent = server:createRemoteEvent("remoteEvent")

            expect(user0:getRemoteEvent("remoteEvent")).to.be.ok()
            expect(user1:getRemoteEvent("remoteEvent")).to.be.ok()

            remoteEvent:destroy()

            expect(function()
                user0:getRemoteEvent("remoteEvent")
            end).to.throw()
            
            expect(function()
                user1:getRemoteEvent("remoteEvent")
            end).to.throw()

            server:destroy()
        end)

        it("should set destroyed field to true", function()
            local server = Server.new()
            local remoteEvent = server:createRemoteEvent("remoteEvent")

            remoteEvent:destroy()

            expect(remoteEvent.destroyed).to.equal(true)
            
            server:destroy()
        end)
    end)
end