local function p(y,U)if typeof(y)~=typeof(U)then return false,("\123\049\125 \105\115 \111\102 \116\121\112\101 \037\115\044 \098\117\116 \123\050\125 \105\115 \111\102 \116\121\112\101 \037\115"):format(typeof(y),typeof(U))end if typeof(y)=="\116\097\098\108\101"then local X={}for y,M in y do X[y]=true local z,c=p(M,U[y])if not z then return false,(c:gsub("\123\049\125",("\123\049\125\091\037\115\093"):format(tostring(y)))):gsub("\123\050\125",("\123\050\125\091\037\115\093"):format(tostring(y)))end end for U,M in U do if not X[U]then local X,z=p(M,y[U])if not X then return false,(z:gsub("\123\049\125",("\123\049\125\091\037\115\093"):format(tostring(U)))):gsub("\123\050\125",("\123\050\125\091\037\115\093"):format(tostring(U)))end end end return true end if y==U then return true end return false,"\123\049\125 ~\061 \123\050\125"end local function y(y,U)local X,M=p(y,U)if not X then error(("\086\097\108\117\101\115 \119\101\114\101 \110\111\116 \100\101\101\112-\101\113\117\097\108\046\n\037\115"):format((M:gsub("\123\049\125","\102\105\114\115\116")):gsub("\123\050\125","\115\101\099\111\110\100")),2)end end return y
--[[
	A utility used to assert that two objects are value-equal recursively. It
	outputs fairly nicely formatted messages to help diagnose why two objects
	would be different.
]]

local function deepEqual(a, b)
	if typeof(a) ~= typeof(b) then
		return false, ("{1} is of type %s, but {2} is of type %s"):format(typeof(a), typeof(b))
	end

	if typeof(a) == "table" then
		local visitedKeys = {}

		for key, value in a do
			visitedKeys[key] = true

			local success, innerMessage = deepEqual(value, b[key])
			if not success then
				return false, innerMessage:gsub("{1}", ("{1}[%s]"):format(tostring(key))):gsub("{2}", ("{2}[%s]"):format(tostring(key)))
			end
		end

		for key, value in b do
			if not visitedKeys[key] then
				local success, innerMessage = deepEqual(value, a[key])

				if not success then
					return false, innerMessage:gsub("{1}", ("{1}[%s]"):format(tostring(key))):gsub("{2}", ("{2}[%s]"):format(tostring(key)))
				end
			end
		end

		return true
	end

	if a == b then
		return true
	end

	return false, "{1} ~= {2}"
end

local function assertDeepEqual(a, b)
	local success, innerMessageTemplate = deepEqual(a, b)

	if not success then
		error(("Values were not deep-equal.\n%s"):format(innerMessageTemplate:gsub("{1}", "first"):gsub("{2}", "second")), 2)
	end
end

return assertDeepEqual
