This commit is contained in:
lx
2026-07-06 14:01:11 -04:00
commit c4f97d729d
16468 changed files with 935321 additions and 0 deletions
@@ -0,0 +1,9 @@
{
"lint": {
"LocalShadow": "fatal",
"LocalUnused": "fatal",
"ImportUnused": "fatal",
"ImplicitReturn": "fatal",
"DeprecatedGlobal": "fatal"
}
}
@@ -0,0 +1,142 @@
local function IsRunningInStudio()
return game:GetService("RunService"):IsStudio()
end
local function assert_(condition, message)
if IsRunningInStudio() or _G.__TESTEZ_RUNNING_TEST__ then
assert(condition, message)
end
end
local ArgCheck = {}
function ArgCheck.isNonNegativeNumber(value, name)
-- Temporarily disabled outside of studio/tests. See MOBLUAPP-1161.
assert_(typeof(value) == "number" and value >= 0, string.format("expects %s to be a non-negative number!", name))
return value
end
function ArgCheck.isType(value, expectedType, name)
assert_(typeof(value) == expectedType,
string.format("expects %s to be a %s! it was: %s", name, expectedType, typeof(value)))
return value
end
function ArgCheck.isInTypes(value, expectedTypes, name)
for _, expectedType in ipairs(expectedTypes) do
if typeof(value) == expectedType then
return value
end
end
assert_(false, string.format("expects %s to be one of expectedTypes! it was: %s", name, typeof(value)))
return value
end
function ArgCheck.isTypeOrNil(value, expectedType, name)
assert_(value == nil or typeof(value) == expectedType,
string.format("expects %s to be a %s! it was: %s", name, expectedType, typeof(value)))
return value
end
function ArgCheck.isNotNil(value, name)
assert_(value ~= nil, string.format("expects %s to be not nil!", name))
return value
end
function ArgCheck.isNonEmptyString(value, name)
assert_(typeof(value) == "string" and value ~= "" ,
string.format("expects %s to be a non-empty string!", name))
return value
end
function ArgCheck.isEqual(value, expectedValue, name)
assert_(value == expectedValue, string.format("expects %s to equal %s! it was: %s", name, tostring(expectedValue), tostring(value)))
return value
end
-- checks for a number or string representing an integer
function ArgCheck.representsInteger(value, name)
local numberValue = tonumber(value)
assert_(numberValue ~= nil , string.format("expects %s to represent a number!", name))
assert_(numberValue % 1 == 0 , string.format("expects %s to represent an integer!", name))
return value
end
--[[
Checks if the value matches the given interface
iface is the interface description; it can be (in order of priority):
* a custom type name: checks against a type from dependencies (see below)
* an ArgCheck handler:
* "integer" => ArgCheck.representsInteger
* "nonEmptyString" => ArgCheck.isNonEmptyString
* a lua type (string): equivalent to ArgCheck.isType
* a list style table (only first item is considered):
checks for a list table with items matching the given interface
* a dict style table: checks for a table with keys matching the given interfaces
dependencies is a table of named interfaces that can be referenced in iface
Example:
local myTypes = {
Tree = {
value = "string",
leaves = {"string"},
branches = {"Tree"},
},
}
ArgCheck.matchesInterface(someValue, "Tree", "myVal", myTypes)
]]--
function ArgCheck.matchesInterface(value, iface, name, dependencies)
if IsRunningInStudio() or _G.__TESTEZ_RUNNING_TEST__ then
local checkFnList = {
integer = ArgCheck.representsInteger,
nonEmptyString = ArgCheck.isNonEmptyString,
}
if type(iface) == "string" then
if dependencies and dependencies[iface] then
ArgCheck.matchesInterface(value, dependencies[iface], name, dependencies)
else
local checkFn = checkFnList[iface]
if type(checkFn) == "function" then
checkFn(value, name)
else
ArgCheck.isType(value, iface, name)
end
end
else
-- assume iface describes a table (list or dict)
ArgCheck.isType(value, "table", name)
if iface[1] ~= nil then
for index, item in ipairs(value) do
ArgCheck.matchesInterface(item, iface[1], name .. "[" .. index .. "]", dependencies)
end
else
for key, desc in pairs(iface) do
if string.sub(key, 1, 1) ~= "_" then
local itemName = name .. "." .. key
local itemValue = value[key]
local isRequired = iface._required and iface._required[key]
if isRequired or itemValue ~= nil then
ArgCheck.matchesInterface(itemValue, desc, itemName, dependencies)
end
end
end
end
end
end
return value
end
function ArgCheck.assert(...)
assert_(...)
end
return ArgCheck
@@ -0,0 +1,287 @@
return function()
local ArgCheck = require(script.Parent.ArgCheck)
describe("isNonNegativeNumber", function()
it("should assert if given non-number, or negative number", function()
expect(function()
ArgCheck.isNonNegativeNumber(nil, "")
end).to.throw()
expect(function()
ArgCheck.isNonNegativeNumber({}, "")
end).to.throw()
expect(function()
ArgCheck.isNonNegativeNumber("string", "")
end).to.throw()
expect(function()
ArgCheck.isNonNegativeNumber(-1, "")
end).to.throw()
end)
it("should return the value if it is a non-negative number", function()
expect(ArgCheck.isNonNegativeNumber(0, "")).to.equal(0)
expect(ArgCheck.isNonNegativeNumber(1, "")).to.equal(1)
end)
end)
describe("isType", function()
it("should assert if type is wrong", function()
expect(function()
ArgCheck.isType(nil, "number", "")
end).to.throw()
expect(function()
ArgCheck.isType("test", "number", "")
end).to.throw()
expect(function()
ArgCheck.isType(5, "string", "")
end).to.throw()
expect(function()
ArgCheck.isType(5, "table", "")
end).to.throw()
end)
it("should return the value if the type is correct", function()
expect(ArgCheck.isType(0, "number", "")).to.equal(0)
expect(ArgCheck.isType("test", "string", "")).to.equal("test")
end)
end)
describe("isInTypes", function()
it("should assert if type is not expected", function()
expect(function()
ArgCheck.isInTypes(nil, {"number", "string", "table"}, "")
end).to.throw()
expect(function()
ArgCheck.isInTypes("test", {"number", "table"}, "")
end).to.throw()
expect(function()
ArgCheck.isInTypes(5, {"string", "table"}, "")
end).to.throw()
expect(function()
ArgCheck.isInTypes({}, {"number", "string"}, "")
end).to.throw()
end)
it("should return the value if the type is expected", function()
expect(ArgCheck.isInTypes(0, {"number", "string"}, "")).to.equal(0)
expect(ArgCheck.isInTypes("test", {"table", "string"}, "")).to.equal("test")
local testTable = {}
expect(ArgCheck.isInTypes(testTable, {"table", "string"}, "")).to.equal(testTable)
local testFunction = function() end
expect(ArgCheck.isInTypes(testFunction, {"function", "string"}, "")).to.equal(testFunction)
end)
end)
describe("isTypeOrNil", function()
it("should assert if type is wrong", function()
expect(function()
ArgCheck.isTypeOrNil("test", "number", "")
end).to.throw()
expect(function()
ArgCheck.isTypeOrNil(5, "string", "")
end).to.throw()
expect(function()
ArgCheck.isTypeOrNil(5, "table", "")
end).to.throw()
end)
it("should return the value if the type is correct", function()
expect(ArgCheck.isTypeOrNil(nil, "number", "")).to.equal(nil)
expect(ArgCheck.isTypeOrNil(0, "number", "")).to.equal(0)
expect(ArgCheck.isTypeOrNil("test", "string", "")).to.equal("test")
end)
end)
describe("isNotNil", function()
it("should assert if type is nil", function()
expect(function()
ArgCheck.isNotNil(nil, "")
end).to.throw()
end)
it("should return the value if it's not nil", function()
expect(ArgCheck.isNotNil(0, "")).to.equal(0)
expect(ArgCheck.isNotNil("test", "")).to.equal("test")
local testTable = {}
expect(ArgCheck.isNotNil(testTable, "")).to.equal(testTable)
local testFunction = function() end
expect(ArgCheck.isNotNil(testFunction, "")).to.equal(testFunction)
end)
end)
describe("isEqual", function()
it("should assert if not equal", function()
expect(function()
ArgCheck.isEqual(0, nil, "")
end).to.throw()
expect(function()
ArgCheck.isEqual(2, 1, "")
end).to.throw()
expect(function()
ArgCheck.isEqual("", "test", "")
end).to.throw()
expect(function()
ArgCheck.isEqual({}, {}, "")
end).to.throw()
expect(function()
ArgCheck.isEqual(function() end, function() end, "")
end).to.throw()
end)
it("should return the value if value is equal to expected value", function()
expect(ArgCheck.isEqual(nil, nil, "")).to.equal(nil)
expect(ArgCheck.isEqual(0, 0, "")).to.equal(0)
expect(ArgCheck.isEqual(true, true, "")).to.equal(true)
expect(ArgCheck.isEqual("test", "test", "")).to.equal("test")
local testTable = {}
expect(ArgCheck.isEqual(testTable, testTable, "")).to.equal(testTable)
local testFunction = function() end
expect(ArgCheck.isEqual(testFunction, testFunction, "")).to.equal(testFunction)
end)
end)
describe("representsInteger", function()
it("should fail if not a number", function()
expect(function()
ArgCheck.representsInteger(nil, "")
end).to.throw()
expect(function()
ArgCheck.representsInteger({}, "")
end).to.throw()
expect(function()
ArgCheck.representsInteger(function()end, "")
end).to.throw()
expect(function()
ArgCheck.representsInteger(true, "")
end).to.throw()
expect(function()
ArgCheck.representsInteger("NaN", "")
end).to.throw()
expect(function()
ArgCheck.representsInteger("1test", "")
end).to.throw()
end)
it("should fail if not an integer", function()
expect(function()
ArgCheck.representsInteger(1.5, "")
end).to.throw()
expect(function()
ArgCheck.representsInteger("1.5", "")
end).to.throw()
expect(function()
ArgCheck.representsInteger("1e-1", "")
end).to.throw()
end)
it("should return the same value on success", function()
expect(ArgCheck.representsInteger(5, "")).to.equal(5)
expect(ArgCheck.representsInteger("-5", "")).to.equal("-5")
expect(ArgCheck.representsInteger("1e1", "")).to.equal("1e1")
expect(ArgCheck.representsInteger("0xa", "")).to.equal("0xa")
end)
end)
describe("matchesInterface", function()
it("should match a simple interface", function()
local interface = {
num = "number",
str = "string",
bool = "boolean",
func = "function",
tab = "table",
list = {"number"},
-- only num is required, rest is optional
_required = {
num = true,
}
}
local obj1 = {
num = 5,
str = "5",
bool = true,
func = function()end,
tab = {},
list = {1, 2, 3}
}
local obj2 = {
num = "5",
}
local obj3 = {
num = 5,
list = {"NaN"},
}
local obj4 = {
str = "5",
}
expect(function()
ArgCheck.matchesInterface(obj1, interface, "")
end).to.never.throw()
expect(function()
ArgCheck.matchesInterface(obj2, interface, "")
end).to.throw()
expect(function()
ArgCheck.matchesInterface(obj3, interface, "")
end).to.throw()
expect(function()
ArgCheck.matchesInterface(obj4, interface, "")
end).to.throw()
end)
it("should match ArgCheck functions", function()
expect(function()
ArgCheck.matchesInterface("5", "nonEmptyString", "")
end).to.never.throw()
expect(function()
ArgCheck.matchesInterface(5, "nonEmptyString", "")
end).to.throw()
expect(function()
ArgCheck.matchesInterface("", "nonEmptyString", "")
end).to.throw()
expect(function()
ArgCheck.matchesInterface({str = "5"}, {str = "nonEmptyString"}, "")
end).to.never.throw()
end)
it("should match dependent types", function()
local types = {
child = {
name = "string",
},
parent = {
name = "string",
children = {"child"},
}
}
local child1 = {
name = "child1",
}
local child2 = {
name = "child2",
}
local parent1 = {
name = "parent1",
children = {child1, child2},
}
local parent2 = {
name = "parent2",
children = {"child1", "child2"},
}
expect(function()
ArgCheck.matchesInterface(child1, types.child, "", types)
end).to.never.throw()
expect(function()
ArgCheck.matchesInterface(parent1, types.parent, "", types)
end).to.never.throw()
expect(function()
ArgCheck.matchesInterface(parent2, types.parent, "", types)
end).to.throw()
end)
it("should return the same value on success", function()
expect(ArgCheck.matchesInterface(5, "number", "")).to.equal(5)
expect(ArgCheck.matchesInterface("5", "nonEmptyString", "")).to.equal("5")
local list = {1, 2, 3}
expect(ArgCheck.matchesInterface(list, {"number"}, "")).to.equal(list)
end)
end)
end
@@ -0,0 +1 @@
return require(script.ArgCheck)