return function()local m=require(script.Parent.Server)local q=require(script.Parent.RemoteFunctionClient)describe("\082\101\109\111\116\101\070\117\110\099\116\105\111\110\067\108\105\101\110\116\058\105\110\118\111\107\101\083\101\114\118\101\114",function()it("\115\104\111\117\108\100 \114\101\116\117\114\110 \097 \114\101\115\112\111\110\115\101 \102\114\111\109 \116\104\101 \115\101\114\118\101\114 \105\102 \097 \104\097\110\100\108\101\114 \101\120\105\115\116\115",function()local q=m.new();(q:createRemoteFunction("\114\101\109\111\116\101\070\117\110\099\116\105\111\110")).OnServerInvoke=function(m,q)return q*2 end;(expect(((q:connect("\117\115\101\114")):getRemoteFunction("\114\101\109\111\116\101\070\117\110\099\116\105\111\110")):invokeServer(1))).to.equal(2)q:destroy()end)it("\115\104\111\117\108\100 \113\117\101\117\101 \114\101\113\117\101\115\116\115 \111\110 \115\101\114\118\101\114 \105\102 \110\111\116 \104\097\110\100\108\101\114 \101\120\105\115\116\115 \097\110\100 \114\101\115\112\111\110\100 \111\110\099\101 \105\116 \100\111\101\115",function()local q=m.new()local x=q:connect("\117\115\101\114")local L=q:createRemoteFunction("\114\101\109\111\116\101\070\117\110\099\116\105\111\110")local E=0 task.spawn(function()local m=(x:getRemoteFunction("\114\101\109\111\116\101\070\117\110\099\116\105\111\110")):invokeServer(1)E+=m end)task.spawn(function()local m=(x:getRemoteFunction("\114\101\109\111\116\101\070\117\110\099\116\105\111\110")):invokeServer(2)E+=m end)L.OnServerInvoke=function(m,q)return q*2 end;(expect(E)).to.equal(6)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")q:createRemoteFunction("\114\101\109\111\116\101\070\117\110\099\116\105\111\110")local L=x:getRemoteFunction("\114\101\109\111\116\101\070\117\110\099\116\105\111\110")local E={a=1}E.b=E;(expect(function()L:invokeServer(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:createRemoteFunction("\114\101\109\111\116\101\070\117\110\099\116\105\111\110")local E=Instance.new("\080\097\114\116")local A={ok=1}local b={a={[E]=1},b={key=2};[A]=3}task.spawn(function()(x:getRemoteFunction("\114\101\109\111\116\101\070\117\110\099\116\105\111\110")):invokeServer(b,b,E)end)local i,t,I L.OnServerInvoke=function(m,...)i,t,I=...end;(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)end
return function()
    local Server = require(script.Parent.Server)
    local RemoteFunctionClient = require(script.Parent.RemoteFunctionClient)

    describe("RemoteFunctionClient:invokeServer", function()
       it("should return a response from the server if a handler exists", function()
            local server = Server.new()

            server:createRemoteFunction("remoteFunction").OnServerInvoke = function(client, value)
                return value * 2
            end

            expect(server:connect("user"):getRemoteFunction("remoteFunction"):invokeServer(1)).to.equal(2)
            
            server:destroy()
        end)

        it("should queue requests on server if not handler exists and respond once it does", function()
            local server = Server.new()
            local user = server:connect("user")

            local remoteFunction = server:createRemoteFunction("remoteFunction")
            local count = 0

            task.spawn(function()
                local new = user:getRemoteFunction("remoteFunction"):invokeServer(1)
                count += new
            end)
            
            task.spawn(function()
                local new = user:getRemoteFunction("remoteFunction"):invokeServer(2)
                count += new
            end)

            remoteFunction.OnServerInvoke = function(client, value)
                return value * 2
            end

            expect(count).to.equal(6)

            server:destroy()
        end)

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

            server:createRemoteFunction("remoteFunction")

            local remoteFunction = user:getRemoteFunction("remoteFunction")

            local data = {
                a = 1,
            }

            data.b = data

            expect(function()
                remoteFunction:invokeServer(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 remoteFunction = server:createRemoteFunction("remoteFunction")

            local part = Instance.new("Part")

            local tab = {ok = 1}

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

            task.spawn(function()
                user:getRemoteFunction("remoteFunction"):invokeServer(data, data, part)
            end)

            local data1, data2, passedPart

            remoteFunction.OnServerInvoke = function(_, ...)
                data1, data2, passedPart = ...
            end

            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)
end