From 9e6d7ea9e4c633e74645eb11f38dfb152d07fd89 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 26 Sep 2024 11:20:33 -0700 Subject: [PATCH] test: add patch tests --- src/__tests__/sync/patch.spec.luau | 99 ++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/__tests__/sync/patch.spec.luau diff --git a/src/__tests__/sync/patch.spec.luau b/src/__tests__/sync/patch.spec.luau new file mode 100644 index 0000000..813fdbc --- /dev/null +++ b/src/__tests__/sync/patch.spec.luau @@ -0,0 +1,99 @@ +local HttpService = game:GetService("HttpService") +local patch = require(script.Parent.Parent.Parent.sync.patch) + +return function() + local function serdes(value: { [any]: any }) + return HttpService:JSONDecode(HttpService:JSONEncode(value)) + end + + it("returns a patch", function() + local prevState = { foo = "bar", baz = "qux" } + local nextState = { foo = "bar", baz = "quux" } + local patches = patch.diff(prevState, nextState) + + expect(patches).to.be.ok() + expect(patches.baz).to.equal("quux") + expect(patches.foo).to.never.be.ok() + end) + + it("applies a patch", function() + local prevState = { foo = "bar", baz = "qux" } + local patches = { baz = "quux", qaz = "qux" } + local applied = patch.apply(prevState, patches) + + expect(applied).to.be.ok() + expect(applied.baz).to.equal("quux") + expect(applied.foo).to.equal("bar") + expect(applied.qaz).to.equal("qux") + end) + + it("allows nested patches", function() + local prevState = { foo = { bar = "baz" } } + local nextState = { foo = { bar = "qux" } } + local patches = patch.diff(prevState, nextState) + local applied = patch.apply(prevState, patches) + + expect(applied.foo.bar).to.equal("qux") + end) + + it("preserves array density when applying", function() + local prevState = { "a", "b", "c", "d" } + local nextState = { ["2"] = "B", ["4"] = "D" } + local applied = patch.apply(prevState, nextState) + + expect(applied[1]).to.equal("a") + expect(applied[2]).to.equal("B") + expect(applied[3]).to.equal("c") + expect(applied[4]).to.equal("D") + + expect(applied["2"]).to.never.be.ok() + expect(applied["4"]).to.never.be.ok() + end) + + it("preserves array density after serdes", function() + -- This particular change results in a patch that cannot be serialized + -- without losing information. Charm resolves this issue internally. + local prevState = { "a", "b", "c", "d", "e" } + local nextState = { "A", "b", "c", "D" } + + local patches = serdes(patch.diff(prevState, nextState)) + local applied = patch.apply(prevState, patches) + + for index in next, prevState do + expect(applied[index]).to.equal(nextState[index]) + end + + for index in next, applied do + expect(applied[index]).to.equal(nextState[index]) + end + end) + + it("preserves large gaps between keys", function() + local prevState = table.create(10000, "foo") + local nextState = table.move(prevState, 2, 9998, 2, { [1] = "bar", [9999] = "bar" }) + + local start = os.clock() + + local patches = serdes(patch.diff(prevState, nextState)) + local applied = patch.apply(prevState, patches) + + assert(os.clock() - start < 1e-3, `Performance is not acceptable ({(os.clock() - start) * 1e3}ms)`) + + for index in next, prevState do + expect(applied[index]).to.equal(nextState[index]) + end + end) + + it("cannot preserve sparse arrays", function() + local prevState = {} + local nextState = { [2] = "foo" } + + local patches = serdes(patch.diff(prevState, nextState)) + local applied = patch.apply(prevState, patches) + + -- Not enough information is available to determine whether 'patches' + -- should keep the string keys added during remote event serialization. + expect(applied["2"]).to.be.ok() + expect(applied[2]).to.never.be.ok() + end) +end