mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-23 05:51:39 +00:00
test fixtures
This commit is contained in:
parent
bf65d8bfa8
commit
bbd9c0e0fa
22 changed files with 2107 additions and 0 deletions
|
|
@ -71,4 +71,117 @@ return function()
|
|||
|
||||
expect(next(changes)).to.equal(nil)
|
||||
end)
|
||||
|
||||
-- -------------------------------------------------------------------
|
||||
-- Ref property in patch creation
|
||||
-- -------------------------------------------------------------------
|
||||
|
||||
describe("Ref properties", function()
|
||||
local container
|
||||
|
||||
beforeEach(function()
|
||||
container = Instance.new("Folder")
|
||||
container.Name = "RefPatchTestContainer"
|
||||
container.Parent = game:GetService("Workspace")
|
||||
end)
|
||||
|
||||
afterEach(function()
|
||||
if container then
|
||||
container:Destroy()
|
||||
container = nil
|
||||
end
|
||||
end)
|
||||
|
||||
it("should include Ref property changes in patch", function()
|
||||
local instanceMap = InstanceMap.new()
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
local part = Instance.new("Part")
|
||||
part.Parent = model
|
||||
model.PrimaryPart = part
|
||||
|
||||
instanceMap:insert("MODEL", model)
|
||||
instanceMap:insert("PART", part)
|
||||
|
||||
local changes = {
|
||||
[model] = { PrimaryPart = true },
|
||||
}
|
||||
|
||||
local patch = createPatchSet(instanceMap, changes)
|
||||
|
||||
expect(#patch.updated).to.equal(1)
|
||||
expect(patch.updated[1].changedProperties.PrimaryPart).to.be.ok()
|
||||
expect(patch.updated[1].changedProperties.PrimaryPart.Ref).to.equal("PART")
|
||||
end)
|
||||
|
||||
it("should skip Ref changes when target not tracked", function()
|
||||
local instanceMap = InstanceMap.new()
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
local part = Instance.new("Part")
|
||||
part.Parent = model
|
||||
model.PrimaryPart = part
|
||||
|
||||
instanceMap:insert("MODEL", model)
|
||||
-- part NOT in instanceMap
|
||||
|
||||
local changes = {
|
||||
[model] = { PrimaryPart = true },
|
||||
}
|
||||
|
||||
local patch = createPatchSet(instanceMap, changes)
|
||||
|
||||
-- No encodable changes → empty updated
|
||||
expect(#patch.updated).to.equal(0)
|
||||
end)
|
||||
|
||||
it("should handle removal alongside Ref change on different instance", function()
|
||||
local instanceMap = InstanceMap.new()
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
local part = Instance.new("Part")
|
||||
part.Parent = model
|
||||
model.PrimaryPart = part
|
||||
|
||||
local toRemove = Instance.new("Part")
|
||||
toRemove.Parent = container
|
||||
toRemove.Parent = nil -- Simulate deletion
|
||||
|
||||
instanceMap:insert("MODEL", model)
|
||||
instanceMap:insert("PART", part)
|
||||
instanceMap:insert("REMOVED", toRemove)
|
||||
|
||||
local changes = {
|
||||
[model] = { PrimaryPart = true },
|
||||
[toRemove] = { Parent = true },
|
||||
}
|
||||
|
||||
local patch = createPatchSet(instanceMap, changes)
|
||||
|
||||
expect(#patch.removed).to.equal(1)
|
||||
expect(#patch.updated).to.equal(1)
|
||||
end)
|
||||
|
||||
it("should pass instanceMap in syncSourceOnly mode", function()
|
||||
local instanceMap = InstanceMap.new()
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
local part = Instance.new("Part")
|
||||
part.Parent = model
|
||||
model.PrimaryPart = part
|
||||
|
||||
instanceMap:insert("MODEL", model)
|
||||
instanceMap:insert("PART", part)
|
||||
|
||||
local changes = {
|
||||
[model] = { PrimaryPart = true },
|
||||
}
|
||||
|
||||
-- In syncSourceOnly mode, only Source changes go through.
|
||||
-- PrimaryPart is NOT Source, so it should be filtered out.
|
||||
local patch = createPatchSet(instanceMap, changes, true)
|
||||
|
||||
expect(#patch.updated).to.equal(0)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -59,4 +59,198 @@ return function()
|
|||
expect(color.Color3[2]).to.be.near(0.2, 0.01)
|
||||
expect(color.Color3[3]).to.be.near(0.9, 0.01)
|
||||
end)
|
||||
|
||||
-- -------------------------------------------------------------------
|
||||
-- Ref property encoding tests
|
||||
-- -------------------------------------------------------------------
|
||||
|
||||
local InstanceMap = require(script.Parent.Parent.InstanceMap)
|
||||
|
||||
describe("Ref property encoding", function()
|
||||
local container
|
||||
local instanceMap
|
||||
|
||||
beforeEach(function()
|
||||
container = Instance.new("Folder")
|
||||
container.Name = "RefTestContainer"
|
||||
container.Parent = game:GetService("Workspace")
|
||||
instanceMap = InstanceMap.new()
|
||||
end)
|
||||
|
||||
afterEach(function()
|
||||
instanceMap:stop()
|
||||
if container then
|
||||
container:Destroy()
|
||||
container = nil
|
||||
end
|
||||
end)
|
||||
|
||||
it("should encode Ref property to tracked instance", function()
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
local part = Instance.new("Part")
|
||||
part.Parent = model
|
||||
model.PrimaryPart = part
|
||||
|
||||
instanceMap:insert("MODEL_ID", model)
|
||||
instanceMap:insert("PART_ID", part)
|
||||
|
||||
local update = encodePatchUpdate(model, "MODEL_ID", { PrimaryPart = true }, instanceMap)
|
||||
|
||||
expect(update).to.be.ok()
|
||||
expect(update.changedProperties.PrimaryPart).to.be.ok()
|
||||
expect(update.changedProperties.PrimaryPart.Ref).to.equal("PART_ID")
|
||||
end)
|
||||
|
||||
it("should encode nil Ref as null ref", function()
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
model.PrimaryPart = nil
|
||||
|
||||
instanceMap:insert("MODEL_ID", model)
|
||||
|
||||
local update = encodePatchUpdate(model, "MODEL_ID", { PrimaryPart = true }, instanceMap)
|
||||
|
||||
expect(update).to.be.ok()
|
||||
expect(update.changedProperties.PrimaryPart).to.be.ok()
|
||||
expect(update.changedProperties.PrimaryPart.Ref).to.equal("00000000000000000000000000000000")
|
||||
end)
|
||||
|
||||
it("should skip Ref when target not in InstanceMap", function()
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
local part = Instance.new("Part")
|
||||
part.Parent = model
|
||||
model.PrimaryPart = part
|
||||
|
||||
instanceMap:insert("MODEL_ID", model)
|
||||
-- part is NOT inserted into instanceMap
|
||||
|
||||
local update = encodePatchUpdate(model, "MODEL_ID", { PrimaryPart = true }, instanceMap)
|
||||
|
||||
-- PrimaryPart should be skipped (not encoded)
|
||||
if update then
|
||||
expect(update.changedProperties.PrimaryPart).to.equal(nil)
|
||||
end
|
||||
end)
|
||||
|
||||
it("should encode Ref alongside non-Ref properties", function()
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
local part = Instance.new("Part")
|
||||
part.Parent = model
|
||||
model.PrimaryPart = part
|
||||
model.Name = "TestModel"
|
||||
|
||||
instanceMap:insert("MODEL_ID", model)
|
||||
instanceMap:insert("PART_ID", part)
|
||||
|
||||
local update = encodePatchUpdate(
|
||||
model,
|
||||
"MODEL_ID",
|
||||
{ PrimaryPart = true, Name = true },
|
||||
instanceMap
|
||||
)
|
||||
|
||||
expect(update).to.be.ok()
|
||||
expect(update.changedProperties.PrimaryPart).to.be.ok()
|
||||
expect(update.changedProperties.PrimaryPart.Ref).to.equal("PART_ID")
|
||||
expect(update.changedName).to.equal("TestModel")
|
||||
end)
|
||||
|
||||
it("should return nil when only unresolvable Ref changes", function()
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
local part = Instance.new("Part")
|
||||
part.Parent = model
|
||||
model.PrimaryPart = part
|
||||
|
||||
instanceMap:insert("MODEL_ID", model)
|
||||
-- part not in map
|
||||
|
||||
local update = encodePatchUpdate(model, "MODEL_ID", { PrimaryPart = true }, instanceMap)
|
||||
|
||||
-- No encodable changes → nil
|
||||
expect(update).to.equal(nil)
|
||||
end)
|
||||
|
||||
it("should encode ObjectValue.Value Ref", function()
|
||||
local objVal = Instance.new("ObjectValue")
|
||||
objVal.Parent = container
|
||||
local target = Instance.new("Part")
|
||||
target.Parent = container
|
||||
objVal.Value = target
|
||||
|
||||
instanceMap:insert("OBJVAL_ID", objVal)
|
||||
instanceMap:insert("TARGET_ID", target)
|
||||
|
||||
local update = encodePatchUpdate(objVal, "OBJVAL_ID", { Value = true }, instanceMap)
|
||||
|
||||
expect(update).to.be.ok()
|
||||
expect(update.changedProperties.Value).to.be.ok()
|
||||
expect(update.changedProperties.Value.Ref).to.equal("TARGET_ID")
|
||||
end)
|
||||
|
||||
it("should encode self-referencing Ref", function()
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
local part = Instance.new("Part")
|
||||
part.Parent = model
|
||||
model.PrimaryPart = part
|
||||
|
||||
instanceMap:insert("MODEL_ID", model)
|
||||
-- PrimaryPart points to part, which IS in the map
|
||||
instanceMap:insert("PART_ID", part)
|
||||
|
||||
local update = encodePatchUpdate(model, "MODEL_ID", { PrimaryPart = true }, instanceMap)
|
||||
|
||||
expect(update).to.be.ok()
|
||||
expect(update.changedProperties.PrimaryPart.Ref).to.equal("PART_ID")
|
||||
end)
|
||||
|
||||
it("should warn when no InstanceMap provided for Ref property", function()
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
local part = Instance.new("Part")
|
||||
part.Parent = model
|
||||
model.PrimaryPart = part
|
||||
|
||||
-- Pass nil for instanceMap
|
||||
local update = encodePatchUpdate(model, "MODEL_ID", { PrimaryPart = true }, nil)
|
||||
|
||||
-- Should not crash; PrimaryPart is skipped
|
||||
if update then
|
||||
expect(update.changedProperties.PrimaryPart).to.equal(nil)
|
||||
end
|
||||
end)
|
||||
|
||||
it("should encode multiple Ref properties on same instance", function()
|
||||
-- Use a Weld which has Part0 and Part1 ref properties
|
||||
local weld = Instance.new("WeldConstraint")
|
||||
weld.Parent = container
|
||||
local partA = Instance.new("Part")
|
||||
partA.Parent = container
|
||||
local partB = Instance.new("Part")
|
||||
partB.Parent = container
|
||||
weld.Part0 = partA
|
||||
weld.Part1 = partB
|
||||
|
||||
instanceMap:insert("WELD_ID", weld)
|
||||
instanceMap:insert("PART_A", partA)
|
||||
instanceMap:insert("PART_B", partB)
|
||||
|
||||
local update = encodePatchUpdate(
|
||||
weld,
|
||||
"WELD_ID",
|
||||
{ Part0 = true, Part1 = true },
|
||||
instanceMap
|
||||
)
|
||||
|
||||
expect(update).to.be.ok()
|
||||
expect(update.changedProperties.Part0).to.be.ok()
|
||||
expect(update.changedProperties.Part0.Ref).to.equal("PART_A")
|
||||
expect(update.changedProperties.Part1).to.be.ok()
|
||||
expect(update.changedProperties.Part1.Ref).to.equal("PART_B")
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -168,4 +168,125 @@ return function()
|
|||
part:Destroy()
|
||||
end)
|
||||
end)
|
||||
|
||||
-- -------------------------------------------------------------------
|
||||
-- Ref property batching tests
|
||||
-- -------------------------------------------------------------------
|
||||
|
||||
describe("Ref property batching", function()
|
||||
local container
|
||||
|
||||
beforeEach(function()
|
||||
container = Instance.new("Folder")
|
||||
container.Name = "RefBatchTestContainer"
|
||||
container.Parent = game:GetService("Workspace")
|
||||
end)
|
||||
|
||||
afterEach(function()
|
||||
if container then
|
||||
container:Destroy()
|
||||
container = nil
|
||||
end
|
||||
end)
|
||||
|
||||
it("should accumulate Ref property changes", function()
|
||||
local instanceMap = InstanceMap.new()
|
||||
local changeBatcher = ChangeBatcher.new(instanceMap, noop)
|
||||
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
instanceMap:insert("MODEL", model)
|
||||
|
||||
changeBatcher:add(model, "PrimaryPart")
|
||||
|
||||
local properties = changeBatcher.__pendingPropertyChanges[model]
|
||||
expect(properties).to.be.ok()
|
||||
expect(properties.PrimaryPart).to.equal(true)
|
||||
|
||||
changeBatcher:stop()
|
||||
end)
|
||||
|
||||
it("should produce patch with Ref when target is tracked", function()
|
||||
local instanceMap = InstanceMap.new()
|
||||
local lastPatch = nil
|
||||
local changeBatcher = ChangeBatcher.new(instanceMap, function(patch)
|
||||
lastPatch = patch
|
||||
end)
|
||||
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
local part = Instance.new("Part")
|
||||
part.Parent = model
|
||||
model.PrimaryPart = part
|
||||
|
||||
instanceMap:insert("MODEL", model)
|
||||
instanceMap:insert("PART", part)
|
||||
|
||||
changeBatcher.__pendingPropertyChanges[model] = { PrimaryPart = true }
|
||||
changeBatcher:__cycle(1.0) -- Force flush
|
||||
|
||||
expect(lastPatch).to.be.ok()
|
||||
expect(#lastPatch.updated).to.equal(1)
|
||||
expect(lastPatch.updated[1].changedProperties.PrimaryPart).to.be.ok()
|
||||
expect(lastPatch.updated[1].changedProperties.PrimaryPart.Ref).to.equal("PART")
|
||||
|
||||
changeBatcher:stop()
|
||||
end)
|
||||
|
||||
it("should drop unresolvable Ref with warning", function()
|
||||
local instanceMap = InstanceMap.new()
|
||||
local lastPatch = nil
|
||||
local changeBatcher = ChangeBatcher.new(instanceMap, function(patch)
|
||||
lastPatch = patch
|
||||
end)
|
||||
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
local part = Instance.new("Part")
|
||||
part.Parent = model
|
||||
model.PrimaryPart = part
|
||||
|
||||
instanceMap:insert("MODEL", model)
|
||||
-- part NOT in instanceMap
|
||||
|
||||
changeBatcher.__pendingPropertyChanges[model] = { PrimaryPart = true }
|
||||
changeBatcher:__cycle(1.0) -- Force flush
|
||||
|
||||
-- No encodable changes → no patch flushed
|
||||
expect(lastPatch).to.equal(nil)
|
||||
|
||||
changeBatcher:stop()
|
||||
end)
|
||||
|
||||
it("should batch Ref with other property changes", function()
|
||||
local instanceMap = InstanceMap.new()
|
||||
local lastPatch = nil
|
||||
local changeBatcher = ChangeBatcher.new(instanceMap, function(patch)
|
||||
lastPatch = patch
|
||||
end)
|
||||
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
local part = Instance.new("Part")
|
||||
part.Parent = model
|
||||
model.PrimaryPart = part
|
||||
model.Name = "TestModel"
|
||||
|
||||
instanceMap:insert("MODEL", model)
|
||||
instanceMap:insert("PART", part)
|
||||
|
||||
changeBatcher.__pendingPropertyChanges[model] = {
|
||||
PrimaryPart = true,
|
||||
Name = true,
|
||||
}
|
||||
changeBatcher:__cycle(1.0) -- Force flush
|
||||
|
||||
expect(lastPatch).to.be.ok()
|
||||
expect(#lastPatch.updated).to.equal(1)
|
||||
expect(lastPatch.updated[1].changedProperties.PrimaryPart).to.be.ok()
|
||||
expect(lastPatch.updated[1].changedName).to.equal("TestModel")
|
||||
|
||||
changeBatcher:stop()
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -201,6 +201,51 @@ return function()
|
|||
|
||||
instanceMap:stop()
|
||||
end)
|
||||
|
||||
it("should decode ref after instance was inserted later", function()
|
||||
local instanceMap = InstanceMap.new()
|
||||
|
||||
local part = Instance.new("Part")
|
||||
part.Parent = container
|
||||
|
||||
local partId = generateId()
|
||||
|
||||
-- Try decoding BEFORE inserting → should fail
|
||||
local success1, _ = decodeValue({ Ref = partId }, instanceMap)
|
||||
expect(success1).to.equal(false)
|
||||
|
||||
-- Insert and try again → should succeed
|
||||
instanceMap:insert(partId, part)
|
||||
local success2, value2 = decodeValue({ Ref = partId }, instanceMap)
|
||||
expect(success2).to.equal(true)
|
||||
expect(value2).to.equal(part)
|
||||
|
||||
instanceMap:stop()
|
||||
end)
|
||||
|
||||
it("should decode ref to different instance types", function()
|
||||
local instanceMap = InstanceMap.new()
|
||||
|
||||
local folder = Instance.new("Folder")
|
||||
folder.Parent = container
|
||||
local folderId = generateId()
|
||||
instanceMap:insert(folderId, folder)
|
||||
|
||||
local model = Instance.new("Model")
|
||||
model.Parent = container
|
||||
local modelId = generateId()
|
||||
instanceMap:insert(modelId, model)
|
||||
|
||||
local s1, v1 = decodeValue({ Ref = folderId }, instanceMap)
|
||||
expect(s1).to.equal(true)
|
||||
expect(v1).to.equal(folder)
|
||||
|
||||
local s2, v2 = decodeValue({ Ref = modelId }, instanceMap)
|
||||
expect(s2).to.equal(true)
|
||||
expect(v2).to.equal(model)
|
||||
|
||||
instanceMap:stop()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("Vector3 decoding", function()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue