mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-23 14:01:37 +00:00
Add Audit Plan for Ambiguous Path Handling
- Introduced a new audit plan detailing the "Ambiguous Path Handling" feature, including three parallel matching algorithm implementations (two in Rust and one in Lua) and their integration with the Reconciler. - Documented findings related to scoring discrepancies between Lua and Rust implementations, including fixes for stale comments, scoring granularity for Tags/Attributes, and performance improvements in cost computation. - Enhanced the `trueEquals` function to support fuzzy equality for additional types (UDim, UDim2, NumberRange, Rect, NumberSequence, ColorSequence) with corresponding unit tests to ensure accuracy. These changes aim to improve the reliability and performance of the matching algorithms while ensuring consistency across implementations.
This commit is contained in:
parent
7e0538b9f5
commit
69f0b9fd63
4 changed files with 517 additions and 4 deletions
|
|
@ -416,9 +416,9 @@ matchChildren = function(
|
|||
virtualInstances: VirtualInstances,
|
||||
parentVirtualId: string?,
|
||||
parentStudioInstance: Instance?,
|
||||
depth: number?
|
||||
_depth: number?
|
||||
): MatchResult
|
||||
depth = depth or 0
|
||||
local depth = _depth or 0
|
||||
if parentVirtualId and parentStudioInstance then
|
||||
local pc = session.matchCache[parentVirtualId]
|
||||
if pc then
|
||||
|
|
@ -430,6 +430,7 @@ matchChildren = function(
|
|||
end
|
||||
|
||||
local matched: { MatchPair } = {}
|
||||
local matchedCosts: { number? } = {}
|
||||
local matchedV: { [number]: boolean } = {}
|
||||
local matchedS: { [number]: boolean } = {}
|
||||
|
||||
|
|
@ -476,6 +477,7 @@ matchChildren = function(
|
|||
virtualId = virtualChildren[vi],
|
||||
studioInstance = studioChildren[si],
|
||||
})
|
||||
table.insert(matchedCosts, nil)
|
||||
matchedV[vi] = true
|
||||
matchedS[si] = true
|
||||
continue
|
||||
|
|
@ -590,6 +592,7 @@ matchChildren = function(
|
|||
virtualId = virtualChildren[pair.vi],
|
||||
studioInstance = studioChildren[pair.si],
|
||||
})
|
||||
table.insert(matchedCosts, pair.cost)
|
||||
matchedV[pair.vi] = true
|
||||
matchedS[pair.si] = true
|
||||
end
|
||||
|
|
@ -613,8 +616,13 @@ matchChildren = function(
|
|||
end
|
||||
|
||||
local totalCost = 0
|
||||
for _, pair in ipairs(matched) do
|
||||
totalCost += computePairCost(session, pair.virtualId, pair.studioInstance, virtualInstances, math.huge, depth)
|
||||
for i, pair in ipairs(matched) do
|
||||
local precomputed = matchedCosts[i]
|
||||
if precomputed ~= nil then
|
||||
totalCost += precomputed
|
||||
else
|
||||
totalCost += computePairCost(session, pair.virtualId, pair.studioInstance, virtualInstances, math.huge, depth)
|
||||
end
|
||||
end
|
||||
totalCost += (#unmatchedVirtual + #unmatchedStudio) * UNMATCHED_PENALTY
|
||||
|
||||
|
|
|
|||
|
|
@ -107,6 +107,50 @@ local function trueEquals(a: any, b: any): boolean
|
|||
if t == "CFrame" then
|
||||
return cframeEq(a, b)
|
||||
end
|
||||
if t == "UDim" then
|
||||
return fuzzyEq(a.Scale, b.Scale) and a.Offset == b.Offset
|
||||
end
|
||||
if t == "UDim2" then
|
||||
return fuzzyEq(a.X.Scale, b.X.Scale)
|
||||
and a.X.Offset == b.X.Offset
|
||||
and fuzzyEq(a.Y.Scale, b.Y.Scale)
|
||||
and a.Y.Offset == b.Y.Offset
|
||||
end
|
||||
if t == "NumberRange" then
|
||||
return fuzzyEq(a.Min, b.Min) and fuzzyEq(a.Max, b.Max)
|
||||
end
|
||||
if t == "Rect" then
|
||||
return fuzzyEq(a.Min.X, b.Min.X)
|
||||
and fuzzyEq(a.Min.Y, b.Min.Y)
|
||||
and fuzzyEq(a.Max.X, b.Max.X)
|
||||
and fuzzyEq(a.Max.Y, b.Max.Y)
|
||||
end
|
||||
if t == "NumberSequence" then
|
||||
local aKp = a.Keypoints
|
||||
local bKp = b.Keypoints
|
||||
if #aKp ~= #bKp then
|
||||
return false
|
||||
end
|
||||
for i = 1, #aKp do
|
||||
if not (fuzzyEq(aKp[i].Time, bKp[i].Time) and fuzzyEq(aKp[i].Value, bKp[i].Value) and fuzzyEq(aKp[i].Envelope, bKp[i].Envelope)) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
if t == "ColorSequence" then
|
||||
local aKp = a.Keypoints
|
||||
local bKp = b.Keypoints
|
||||
if #aKp ~= #bKp then
|
||||
return false
|
||||
end
|
||||
for i = 1, #aKp do
|
||||
if not (fuzzyEq(aKp[i].Time, bKp[i].Time) and color3Eq(aKp[i].Value, bKp[i].Value)) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
|
|
|||
|
|
@ -360,6 +360,187 @@ return function()
|
|||
end)
|
||||
end)
|
||||
|
||||
describe("UDim", function()
|
||||
it("identical", function()
|
||||
expect(trueEquals(UDim.new(0.5, 10), UDim.new(0.5, 10))).to.equal(true)
|
||||
end)
|
||||
|
||||
it("scale within epsilon", function()
|
||||
expect(trueEquals(UDim.new(0.5, 10), UDim.new(0.50005, 10))).to.equal(true)
|
||||
end)
|
||||
|
||||
it("scale beyond epsilon", function()
|
||||
expect(trueEquals(UDim.new(0.5, 10), UDim.new(0.502, 10))).to.equal(false)
|
||||
end)
|
||||
|
||||
it("offset differs by 1", function()
|
||||
expect(trueEquals(UDim.new(0.5, 10), UDim.new(0.5, 11))).to.equal(false)
|
||||
end)
|
||||
|
||||
it("zero vs zero", function()
|
||||
expect(trueEquals(UDim.new(0, 0), UDim.new(0, 0))).to.equal(true)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("UDim2", function()
|
||||
it("identical", function()
|
||||
expect(trueEquals(UDim2.new(1, 0, 0.5, 100), UDim2.new(1, 0, 0.5, 100))).to.equal(true)
|
||||
end)
|
||||
|
||||
it("X scale within epsilon", function()
|
||||
expect(trueEquals(UDim2.new(1, 0, 0.5, 100), UDim2.new(1.00005, 0, 0.5, 100))).to.equal(true)
|
||||
end)
|
||||
|
||||
it("X scale beyond epsilon", function()
|
||||
expect(trueEquals(UDim2.new(1, 0, 0.5, 100), UDim2.new(1.002, 0, 0.5, 100))).to.equal(false)
|
||||
end)
|
||||
|
||||
it("Y scale within epsilon", function()
|
||||
expect(trueEquals(UDim2.new(1, 0, 0.5, 100), UDim2.new(1, 0, 0.50005, 100))).to.equal(true)
|
||||
end)
|
||||
|
||||
it("X offset differs", function()
|
||||
expect(trueEquals(UDim2.new(1, 0, 0.5, 100), UDim2.new(1, 1, 0.5, 100))).to.equal(false)
|
||||
end)
|
||||
|
||||
it("Y offset differs", function()
|
||||
expect(trueEquals(UDim2.new(1, 0, 0.5, 100), UDim2.new(1, 0, 0.5, 101))).to.equal(false)
|
||||
end)
|
||||
|
||||
it("fromOffset identical", function()
|
||||
expect(trueEquals(UDim2.fromOffset(100, 200), UDim2.fromOffset(100, 200))).to.equal(true)
|
||||
end)
|
||||
|
||||
it("fromScale identical", function()
|
||||
expect(trueEquals(UDim2.fromScale(0.5, 0.5), UDim2.fromScale(0.5, 0.5))).to.equal(true)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("NumberRange", function()
|
||||
it("identical", function()
|
||||
expect(trueEquals(NumberRange.new(0, 10), NumberRange.new(0, 10))).to.equal(true)
|
||||
end)
|
||||
|
||||
it("min within epsilon", function()
|
||||
expect(trueEquals(NumberRange.new(0, 10), NumberRange.new(0.00005, 10))).to.equal(true)
|
||||
end)
|
||||
|
||||
it("max beyond epsilon", function()
|
||||
expect(trueEquals(NumberRange.new(0, 10), NumberRange.new(0, 10.002))).to.equal(false)
|
||||
end)
|
||||
|
||||
it("single-value range", function()
|
||||
expect(trueEquals(NumberRange.new(5), NumberRange.new(5))).to.equal(true)
|
||||
end)
|
||||
|
||||
it("different ranges", function()
|
||||
expect(trueEquals(NumberRange.new(0, 10), NumberRange.new(0, 20))).to.equal(false)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("Rect", function()
|
||||
it("identical", function()
|
||||
expect(trueEquals(Rect.new(0, 0, 100, 200), Rect.new(0, 0, 100, 200))).to.equal(true)
|
||||
end)
|
||||
|
||||
it("min X within epsilon", function()
|
||||
expect(trueEquals(Rect.new(0, 0, 100, 200), Rect.new(0.00005, 0, 100, 200))).to.equal(true)
|
||||
end)
|
||||
|
||||
it("max Y beyond epsilon", function()
|
||||
expect(trueEquals(Rect.new(0, 0, 100, 200), Rect.new(0, 0, 100, 200.5))).to.equal(false)
|
||||
end)
|
||||
|
||||
it("from Vector2 identical", function()
|
||||
expect(trueEquals(
|
||||
Rect.new(Vector2.new(10, 20), Vector2.new(30, 40)),
|
||||
Rect.new(Vector2.new(10, 20), Vector2.new(30, 40))
|
||||
)).to.equal(true)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("NumberSequence", function()
|
||||
it("identical two-keypoint", function()
|
||||
expect(trueEquals(
|
||||
NumberSequence.new({ NumberSequenceKeypoint.new(0, 0), NumberSequenceKeypoint.new(1, 1) }),
|
||||
NumberSequence.new({ NumberSequenceKeypoint.new(0, 0), NumberSequenceKeypoint.new(1, 1) })
|
||||
)).to.equal(true)
|
||||
end)
|
||||
|
||||
it("value within epsilon", function()
|
||||
expect(trueEquals(
|
||||
NumberSequence.new({ NumberSequenceKeypoint.new(0, 0), NumberSequenceKeypoint.new(1, 1) }),
|
||||
NumberSequence.new({ NumberSequenceKeypoint.new(0, 0), NumberSequenceKeypoint.new(1, 1.00005) })
|
||||
)).to.equal(true)
|
||||
end)
|
||||
|
||||
it("value beyond epsilon", function()
|
||||
expect(trueEquals(
|
||||
NumberSequence.new({ NumberSequenceKeypoint.new(0, 0), NumberSequenceKeypoint.new(1, 1) }),
|
||||
NumberSequence.new({ NumberSequenceKeypoint.new(0, 0), NumberSequenceKeypoint.new(1, 1.002) })
|
||||
)).to.equal(false)
|
||||
end)
|
||||
|
||||
it("different keypoint count", function()
|
||||
expect(trueEquals(
|
||||
NumberSequence.new({ NumberSequenceKeypoint.new(0, 0), NumberSequenceKeypoint.new(1, 1) }),
|
||||
NumberSequence.new({ NumberSequenceKeypoint.new(0, 0), NumberSequenceKeypoint.new(0.5, 0.5), NumberSequenceKeypoint.new(1, 1) })
|
||||
)).to.equal(false)
|
||||
end)
|
||||
|
||||
it("simple constructor identical", function()
|
||||
expect(trueEquals(NumberSequence.new(5), NumberSequence.new(5))).to.equal(true)
|
||||
end)
|
||||
|
||||
it("envelope within epsilon", function()
|
||||
expect(trueEquals(
|
||||
NumberSequence.new({ NumberSequenceKeypoint.new(0, 1, 0.5), NumberSequenceKeypoint.new(1, 1, 0.5) }),
|
||||
NumberSequence.new({ NumberSequenceKeypoint.new(0, 1, 0.50005), NumberSequenceKeypoint.new(1, 1, 0.5) })
|
||||
)).to.equal(true)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("ColorSequence", function()
|
||||
it("identical two-keypoint", function()
|
||||
expect(trueEquals(
|
||||
ColorSequence.new({ ColorSequenceKeypoint.new(0, Color3.new(1, 0, 0)), ColorSequenceKeypoint.new(1, Color3.new(0, 0, 1)) }),
|
||||
ColorSequence.new({ ColorSequenceKeypoint.new(0, Color3.new(1, 0, 0)), ColorSequenceKeypoint.new(1, Color3.new(0, 0, 1)) })
|
||||
)).to.equal(true)
|
||||
end)
|
||||
|
||||
it("color within epsilon", function()
|
||||
expect(trueEquals(
|
||||
ColorSequence.new({ ColorSequenceKeypoint.new(0, Color3.new(0.5, 0, 0)), ColorSequenceKeypoint.new(1, Color3.new(0, 0, 1)) }),
|
||||
ColorSequence.new({ ColorSequenceKeypoint.new(0, Color3.new(0.50005, 0, 0)), ColorSequenceKeypoint.new(1, Color3.new(0, 0, 1)) })
|
||||
)).to.equal(true)
|
||||
end)
|
||||
|
||||
it("color beyond epsilon", function()
|
||||
expect(trueEquals(
|
||||
ColorSequence.new({ ColorSequenceKeypoint.new(0, Color3.new(0.5, 0, 0)), ColorSequenceKeypoint.new(1, Color3.new(0, 0, 1)) }),
|
||||
ColorSequence.new({ ColorSequenceKeypoint.new(0, Color3.new(0.6, 0, 0)), ColorSequenceKeypoint.new(1, Color3.new(0, 0, 1)) })
|
||||
)).to.equal(false)
|
||||
end)
|
||||
|
||||
it("different keypoint count", function()
|
||||
expect(trueEquals(
|
||||
ColorSequence.new({ ColorSequenceKeypoint.new(0, Color3.new(1, 0, 0)), ColorSequenceKeypoint.new(1, Color3.new(0, 0, 1)) }),
|
||||
ColorSequence.new({ ColorSequenceKeypoint.new(0, Color3.new(1, 0, 0)), ColorSequenceKeypoint.new(0.5, Color3.new(0, 1, 0)), ColorSequenceKeypoint.new(1, Color3.new(0, 0, 1)) })
|
||||
)).to.equal(false)
|
||||
end)
|
||||
|
||||
it("simple constructor identical", function()
|
||||
expect(trueEquals(ColorSequence.new(Color3.new(1, 0, 0)), ColorSequence.new(Color3.new(1, 0, 0)))).to.equal(true)
|
||||
end)
|
||||
|
||||
it("time within epsilon", function()
|
||||
expect(trueEquals(
|
||||
ColorSequence.new({ ColorSequenceKeypoint.new(0, Color3.new(1, 0, 0)), ColorSequenceKeypoint.new(1, Color3.new(0, 0, 1)) }),
|
||||
ColorSequence.new({ ColorSequenceKeypoint.new(0.00005, Color3.new(1, 0, 0)), ColorSequenceKeypoint.new(1, Color3.new(0, 0, 1)) })
|
||||
)).to.equal(true)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("type mismatches", function()
|
||||
it("string vs number", function()
|
||||
expect(trueEquals("hello", 42)).to.equal(false)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue