unc.lua hinzugefügt
This commit is contained in:
871
unc.lua
Normal file
871
unc.lua
Normal file
@@ -0,0 +1,871 @@
|
||||
local passes, fails, undefined = 0, 0, 0
|
||||
local running = 0
|
||||
|
||||
local function getGlobal(path)
|
||||
local value = getfenv(0)
|
||||
|
||||
while value ~= nil and path ~= "" do
|
||||
local name, nextValue = string.match(path, "^([^.]+)%.?(.*)$")
|
||||
value = value[name]
|
||||
path = nextValue
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
local function test(name, aliases, callback)
|
||||
running += 1
|
||||
|
||||
task.spawn(function()
|
||||
if not callback then
|
||||
print("⏺️ " .. name)
|
||||
elseif not getGlobal(name) then
|
||||
fails += 1
|
||||
warn("⛔ " .. name)
|
||||
else
|
||||
local success, message = pcall(callback)
|
||||
|
||||
if success then
|
||||
passes += 1
|
||||
print("✅ " .. name .. (message and " • " .. message or ""))
|
||||
else
|
||||
fails += 1
|
||||
warn("⛔ " .. name .. " failed: " .. message)
|
||||
end
|
||||
end
|
||||
|
||||
local undefinedAliases = {}
|
||||
|
||||
for _, alias in ipairs(aliases) do
|
||||
if getGlobal(alias) == nil then
|
||||
table.insert(undefinedAliases, alias)
|
||||
end
|
||||
end
|
||||
|
||||
if #undefinedAliases > 0 then
|
||||
undefined += 1
|
||||
warn("⚠️ " .. table.concat(undefinedAliases, ", "))
|
||||
end
|
||||
|
||||
running -= 1
|
||||
end)
|
||||
end
|
||||
|
||||
-- Header and summary
|
||||
|
||||
print("\n")
|
||||
|
||||
print("UNC Environment Check")
|
||||
print("✅ - Pass, ⛔ - Fail, ⏺️ - No test, ⚠️ - Missing aliases\n")
|
||||
|
||||
task.defer(function()
|
||||
repeat task.wait() until running == 0
|
||||
|
||||
local rate = math.round(passes / (passes + fails) * 100)
|
||||
local outOf = passes .. " out of " .. (passes + fails)
|
||||
|
||||
print("\n")
|
||||
|
||||
print("UNC Summary")
|
||||
print("✅ Tested with a " .. rate .. "% success rate (" .. outOf .. ")")
|
||||
print("⛔ " .. fails .. " tests failed")
|
||||
print("⚠️ " .. undefined .. " globals are missing aliases")
|
||||
end)
|
||||
|
||||
-- Cache
|
||||
|
||||
test("cache.invalidate", {}, function()
|
||||
local container = Instance.new("Folder")
|
||||
local part = Instance.new("Part", container)
|
||||
cache.invalidate(container:FindFirstChild("Part"))
|
||||
assert(part ~= container:FindFirstChild("Part"), "Reference `part` could not be invalidated")
|
||||
end)
|
||||
|
||||
test("cache.iscached", {}, function()
|
||||
local part = Instance.new("Part")
|
||||
assert(cache.iscached(part), "Part should be cached")
|
||||
cache.invalidate(part)
|
||||
assert(not cache.iscached(part), "Part should not be cached")
|
||||
end)
|
||||
|
||||
test("cache.replace", {}, function()
|
||||
local part = Instance.new("Part")
|
||||
local fire = Instance.new("Fire")
|
||||
cache.replace(part, fire)
|
||||
assert(part ~= fire, "Part was not replaced with Fire")
|
||||
end)
|
||||
|
||||
test("cloneref", {}, function()
|
||||
local part = Instance.new("Part")
|
||||
local clone = cloneref(part)
|
||||
assert(part ~= clone, "Clone should not be equal to original")
|
||||
clone.Name = "Test"
|
||||
assert(part.Name == "Test", "Clone should have updated the original")
|
||||
end)
|
||||
|
||||
test("compareinstances", {}, function()
|
||||
local part = Instance.new("Part")
|
||||
local clone = cloneref(part)
|
||||
assert(part ~= clone, "Clone should not be equal to original")
|
||||
assert(compareinstances(part, clone), "Clone should be equal to original when using compareinstances()")
|
||||
end)
|
||||
|
||||
-- Closures
|
||||
|
||||
local function shallowEqual(t1, t2)
|
||||
if t1 == t2 then
|
||||
return true
|
||||
end
|
||||
|
||||
local UNIQUE_TYPES = {
|
||||
["function"] = true,
|
||||
["table"] = true,
|
||||
["userdata"] = true,
|
||||
["thread"] = true,
|
||||
}
|
||||
|
||||
for k, v in pairs(t1) do
|
||||
if UNIQUE_TYPES[type(v)] then
|
||||
if type(t2[k]) ~= type(v) then
|
||||
return false
|
||||
end
|
||||
elseif t2[k] ~= v then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in pairs(t2) do
|
||||
if UNIQUE_TYPES[type(v)] then
|
||||
if type(t2[k]) ~= type(v) then
|
||||
return false
|
||||
end
|
||||
elseif t1[k] ~= v then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
test("checkcaller", {}, function()
|
||||
assert(checkcaller(), "Main scope should return true")
|
||||
end)
|
||||
|
||||
test("clonefunction", {}, function()
|
||||
local function test()
|
||||
return "success"
|
||||
end
|
||||
local copy = clonefunction(test)
|
||||
assert(test() == copy(), "The clone should return the same value as the original")
|
||||
assert(test ~= copy, "The clone should not be equal to the original")
|
||||
end)
|
||||
|
||||
test("getcallingscript", {})
|
||||
|
||||
test("getscriptclosure", {"getscriptfunction"}, function()
|
||||
local module = game:GetService("CoreGui").RobloxGui.Modules.Common.Constants
|
||||
local constants = getrenv().require(module)
|
||||
local generated = getscriptclosure(module)()
|
||||
assert(constants ~= generated, "Generated module should not match the original")
|
||||
assert(shallowEqual(constants, generated), "Generated constant table should be shallow equal to the original")
|
||||
end)
|
||||
|
||||
test("hookfunction", {"replaceclosure"}, function()
|
||||
local function test()
|
||||
return true
|
||||
end
|
||||
local ref = hookfunction(test, function()
|
||||
return false
|
||||
end)
|
||||
assert(test() == false, "Function should return false")
|
||||
assert(ref() == true, "Original function should return true")
|
||||
assert(test ~= ref, "Original function should not be same as the reference")
|
||||
end)
|
||||
|
||||
test("iscclosure", {}, function()
|
||||
assert(iscclosure(print) == true, "Function 'print' should be a C closure")
|
||||
assert(iscclosure(function() end) == false, "Executor function should not be a C closure")
|
||||
end)
|
||||
|
||||
test("islclosure", {}, function()
|
||||
assert(islclosure(print) == false, "Function 'print' should not be a Lua closure")
|
||||
assert(islclosure(function() end) == true, "Executor function should be a Lua closure")
|
||||
end)
|
||||
|
||||
test("isexecutorclosure", {"checkclosure", "isourclosure"}, function()
|
||||
assert(isexecutorclosure(isexecutorclosure) == true, "Did not return true for an executor global")
|
||||
assert(isexecutorclosure(newcclosure(function() end)) == true, "Did not return true for an executor C closure")
|
||||
assert(isexecutorclosure(function() end) == true, "Did not return true for an executor Luau closure")
|
||||
assert(isexecutorclosure(print) == false, "Did not return false for a Roblox global")
|
||||
end)
|
||||
|
||||
test("loadstring", {}, function()
|
||||
local animate = game:GetService("Players").LocalPlayer.Character.Animate
|
||||
local bytecode = getscriptbytecode(animate)
|
||||
local func = loadstring(bytecode)
|
||||
assert(type(func) ~= "function", "Luau bytecode should not be loadable!")
|
||||
assert(assert(loadstring("return ... + 1"))(1) == 2, "Failed to do simple math")
|
||||
assert(type(select(2, loadstring("f"))) == "string", "Loadstring did not return anything for a compiler error")
|
||||
end)
|
||||
|
||||
test("newcclosure", {}, function()
|
||||
local function test()
|
||||
return true
|
||||
end
|
||||
local testC = newcclosure(test)
|
||||
assert(test() == testC(), "New C closure should return the same value as the original")
|
||||
assert(test ~= testC, "New C closure should not be same as the original")
|
||||
assert(iscclosure(testC), "New C closure should be a C closure")
|
||||
end)
|
||||
|
||||
-- Console
|
||||
|
||||
test("rconsoleclear", {"consoleclear"})
|
||||
|
||||
test("rconsolecreate", {"consolecreate"})
|
||||
|
||||
test("rconsoledestroy", {"consoledestroy"})
|
||||
|
||||
test("rconsoleinput", {"consoleinput"})
|
||||
|
||||
test("rconsoleprint", {"consoleprint"})
|
||||
|
||||
test("rconsolesettitle", {"rconsolename", "consolesettitle"})
|
||||
|
||||
-- Crypt
|
||||
|
||||
test("crypt.base64encode", {"crypt.base64.encode", "crypt.base64_encode", "base64.encode", "base64_encode"}, function()
|
||||
assert(crypt.base64encode("test") == "dGVzdA==", "Base64 encoding failed")
|
||||
end)
|
||||
|
||||
test("crypt.base64decode", {"crypt.base64.decode", "crypt.base64_decode", "base64.decode", "base64_decode"}, function()
|
||||
assert(crypt.base64decode("dGVzdA==") == "test", "Base64 decoding failed")
|
||||
end)
|
||||
|
||||
test("crypt.encrypt", {}, function()
|
||||
local key = crypt.generatekey()
|
||||
local encrypted, iv = crypt.encrypt("test", key, nil, "CBC")
|
||||
assert(iv, "crypt.encrypt should return an IV")
|
||||
local decrypted = crypt.decrypt(encrypted, key, iv, "CBC")
|
||||
assert(decrypted == "test", "Failed to decrypt raw string from encrypted data")
|
||||
end)
|
||||
|
||||
test("crypt.decrypt", {}, function()
|
||||
local key, iv = crypt.generatekey(), crypt.generatekey()
|
||||
local encrypted = crypt.encrypt("test", key, iv, "CBC")
|
||||
local decrypted = crypt.decrypt(encrypted, key, iv, "CBC")
|
||||
assert(decrypted == "test", "Failed to decrypt raw string from encrypted data")
|
||||
end)
|
||||
|
||||
test("crypt.generatebytes", {}, function()
|
||||
local size = math.random(10, 100)
|
||||
local bytes = crypt.generatebytes(size)
|
||||
assert(#crypt.base64decode(bytes) == size, "The decoded result should be " .. size .. " bytes long (got " .. #crypt.base64decode(bytes) .. " decoded, " .. #bytes .. " raw)")
|
||||
end)
|
||||
|
||||
test("crypt.generatekey", {}, function()
|
||||
local key = crypt.generatekey()
|
||||
assert(#crypt.base64decode(key) == 32, "Generated key should be 32 bytes long when decoded")
|
||||
end)
|
||||
|
||||
test("crypt.hash", {}, function()
|
||||
local algorithms = {'sha1', 'sha384', 'sha512', 'md5', 'sha256', 'sha3-224', 'sha3-256', 'sha3-512'}
|
||||
for _, algorithm in ipairs(algorithms) do
|
||||
local hash = crypt.hash("test", algorithm)
|
||||
assert(hash, "crypt.hash on algorithm '" .. algorithm .. "' should return a hash")
|
||||
end
|
||||
end)
|
||||
|
||||
--- Debug
|
||||
|
||||
test("debug.getconstant", {}, function()
|
||||
local function test()
|
||||
print("Hello, world!")
|
||||
end
|
||||
assert(debug.getconstant(test, 1) == "print", "First constant must be print")
|
||||
assert(debug.getconstant(test, 2) == nil, "Second constant must be nil")
|
||||
assert(debug.getconstant(test, 3) == "Hello, world!", "Third constant must be 'Hello, world!'")
|
||||
end)
|
||||
|
||||
test("debug.getconstants", {}, function()
|
||||
local function test()
|
||||
local num = 5000 .. 50000
|
||||
print("Hello, world!", num, warn)
|
||||
end
|
||||
local constants = debug.getconstants(test)
|
||||
assert(constants[1] == 50000, "First constant must be 50000")
|
||||
assert(constants[2] == "print", "Second constant must be print")
|
||||
assert(constants[3] == nil, "Third constant must be nil")
|
||||
assert(constants[4] == "Hello, world!", "Fourth constant must be 'Hello, world!'")
|
||||
assert(constants[5] == "warn", "Fifth constant must be warn")
|
||||
end)
|
||||
|
||||
test("debug.getinfo", {}, function()
|
||||
local types = {
|
||||
source = "string",
|
||||
short_src = "string",
|
||||
func = "function",
|
||||
what = "string",
|
||||
currentline = "number",
|
||||
name = "string",
|
||||
nups = "number",
|
||||
numparams = "number",
|
||||
is_vararg = "number",
|
||||
}
|
||||
local function test(...)
|
||||
print(...)
|
||||
end
|
||||
local info = debug.getinfo(test)
|
||||
for k, v in pairs(types) do
|
||||
assert(info[k] ~= nil, "Did not return a table with a '" .. k .. "' field")
|
||||
assert(type(info[k]) == v, "Did not return a table with " .. k .. " as a " .. v .. " (got " .. type(info[k]) .. ")")
|
||||
end
|
||||
end)
|
||||
|
||||
test("debug.getproto", {}, function()
|
||||
local function test()
|
||||
local function proto()
|
||||
return true
|
||||
end
|
||||
end
|
||||
local proto = debug.getproto(test, 1, true)[1]
|
||||
local realproto = debug.getproto(test, 1)
|
||||
assert(proto, "Failed to get the inner function")
|
||||
assert(proto() == true, "The inner function did not return anything")
|
||||
if not realproto() then
|
||||
return "Proto return values are disabled on this executor"
|
||||
end
|
||||
end)
|
||||
|
||||
test("debug.getprotos", {}, function()
|
||||
local function test()
|
||||
local function _1()
|
||||
return true
|
||||
end
|
||||
local function _2()
|
||||
return true
|
||||
end
|
||||
local function _3()
|
||||
return true
|
||||
end
|
||||
end
|
||||
for i in ipairs(debug.getprotos(test)) do
|
||||
local proto = debug.getproto(test, i, true)[1]
|
||||
local realproto = debug.getproto(test, i)
|
||||
assert(proto(), "Failed to get inner function " .. i)
|
||||
if not realproto() then
|
||||
return "Proto return values are disabled on this executor"
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
test("debug.getstack", {}, function()
|
||||
local _ = "a" .. "b"
|
||||
assert(debug.getstack(1, 1) == "ab", "The first item in the stack should be 'ab'")
|
||||
assert(debug.getstack(1)[1] == "ab", "The first item in the stack table should be 'ab'")
|
||||
end)
|
||||
|
||||
test("debug.getupvalue", {}, function()
|
||||
local upvalue = function() end
|
||||
local function test()
|
||||
print(upvalue)
|
||||
end
|
||||
assert(debug.getupvalue(test, 1) == upvalue, "Unexpected value returned from debug.getupvalue")
|
||||
end)
|
||||
|
||||
test("debug.getupvalues", {}, function()
|
||||
local upvalue = function() end
|
||||
local function test()
|
||||
print(upvalue)
|
||||
end
|
||||
local upvalues = debug.getupvalues(test)
|
||||
assert(upvalues[1] == upvalue, "Unexpected value returned from debug.getupvalues")
|
||||
end)
|
||||
|
||||
test("debug.setconstant", {}, function()
|
||||
local function test()
|
||||
return "fail"
|
||||
end
|
||||
debug.setconstant(test, 1, "success")
|
||||
assert(test() == "success", "debug.setconstant did not set the first constant")
|
||||
end)
|
||||
|
||||
test("debug.setstack", {}, function()
|
||||
local function test()
|
||||
return "fail", debug.setstack(1, 1, "success")
|
||||
end
|
||||
assert(test() == "success", "debug.setstack did not set the first stack item")
|
||||
end)
|
||||
|
||||
test("debug.setupvalue", {}, function()
|
||||
local function upvalue()
|
||||
return "fail"
|
||||
end
|
||||
local function test()
|
||||
return upvalue()
|
||||
end
|
||||
debug.setupvalue(test, 1, function()
|
||||
return "success"
|
||||
end)
|
||||
assert(test() == "success", "debug.setupvalue did not set the first upvalue")
|
||||
end)
|
||||
|
||||
-- Filesystem
|
||||
|
||||
if isfolder and makefolder and delfolder then
|
||||
if isfolder(".tests") then
|
||||
delfolder(".tests")
|
||||
end
|
||||
makefolder(".tests")
|
||||
end
|
||||
|
||||
test("readfile", {}, function()
|
||||
writefile(".tests/readfile.txt", "success")
|
||||
assert(readfile(".tests/readfile.txt") == "success", "Did not return the contents of the file")
|
||||
end)
|
||||
|
||||
test("listfiles", {}, function()
|
||||
makefolder(".tests/listfiles")
|
||||
writefile(".tests/listfiles/test_1.txt", "success")
|
||||
writefile(".tests/listfiles/test_2.txt", "success")
|
||||
local files = listfiles(".tests/listfiles")
|
||||
assert(#files == 2, "Did not return the correct number of files")
|
||||
assert(isfile(files[1]), "Did not return a file path")
|
||||
assert(readfile(files[1]) == "success", "Did not return the correct files")
|
||||
makefolder(".tests/listfiles_2")
|
||||
makefolder(".tests/listfiles_2/test_1")
|
||||
makefolder(".tests/listfiles_2/test_2")
|
||||
local folders = listfiles(".tests/listfiles_2")
|
||||
assert(#folders == 2, "Did not return the correct number of folders")
|
||||
assert(isfolder(folders[1]), "Did not return a folder path")
|
||||
end)
|
||||
|
||||
test("writefile", {}, function()
|
||||
writefile(".tests/writefile.txt", "success")
|
||||
assert(readfile(".tests/writefile.txt") == "success", "Did not write the file")
|
||||
local requiresFileExt = pcall(function()
|
||||
writefile(".tests/writefile", "success")
|
||||
assert(isfile(".tests/writefile.txt"))
|
||||
end)
|
||||
if not requiresFileExt then
|
||||
return "This executor requires a file extension in writefile"
|
||||
end
|
||||
end)
|
||||
|
||||
test("makefolder", {}, function()
|
||||
makefolder(".tests/makefolder")
|
||||
assert(isfolder(".tests/makefolder"), "Did not create the folder")
|
||||
end)
|
||||
|
||||
test("appendfile", {}, function()
|
||||
writefile(".tests/appendfile.txt", "su")
|
||||
appendfile(".tests/appendfile.txt", "cce")
|
||||
appendfile(".tests/appendfile.txt", "ss")
|
||||
assert(readfile(".tests/appendfile.txt") == "success", "Did not append the file")
|
||||
end)
|
||||
|
||||
test("isfile", {}, function()
|
||||
writefile(".tests/isfile.txt", "success")
|
||||
assert(isfile(".tests/isfile.txt") == true, "Did not return true for a file")
|
||||
assert(isfile(".tests") == false, "Did not return false for a folder")
|
||||
assert(isfile(".tests/doesnotexist.exe") == false, "Did not return false for a nonexistent path (got " .. tostring(isfile(".tests/doesnotexist.exe")) .. ")")
|
||||
end)
|
||||
|
||||
test("isfolder", {}, function()
|
||||
assert(isfolder(".tests") == true, "Did not return false for a folder")
|
||||
assert(isfolder(".tests/doesnotexist.exe") == false, "Did not return false for a nonexistent path (got " .. tostring(isfolder(".tests/doesnotexist.exe")) .. ")")
|
||||
end)
|
||||
|
||||
test("delfolder", {}, function()
|
||||
makefolder(".tests/delfolder")
|
||||
delfolder(".tests/delfolder")
|
||||
assert(isfolder(".tests/delfolder") == false, "Failed to delete folder (isfolder = " .. tostring(isfolder(".tests/delfolder")) .. ")")
|
||||
end)
|
||||
|
||||
test("delfile", {}, function()
|
||||
writefile(".tests/delfile.txt", "Hello, world!")
|
||||
delfile(".tests/delfile.txt")
|
||||
assert(isfile(".tests/delfile.txt") == false, "Failed to delete file (isfile = " .. tostring(isfile(".tests/delfile.txt")) .. ")")
|
||||
end)
|
||||
|
||||
test("loadfile", {}, function()
|
||||
writefile(".tests/loadfile.txt", "return ... + 1")
|
||||
assert(assert(loadfile(".tests/loadfile.txt"))(1) == 2, "Failed to load a file with arguments")
|
||||
writefile(".tests/loadfile.txt", "f")
|
||||
local callback, err = loadfile(".tests/loadfile.txt")
|
||||
assert(err and not callback, "Did not return an error message for a compiler error")
|
||||
end)
|
||||
|
||||
test("dofile", {})
|
||||
|
||||
-- Input
|
||||
|
||||
test("isrbxactive", {"isgameactive"}, function()
|
||||
assert(type(isrbxactive()) == "boolean", "Did not return a boolean value")
|
||||
end)
|
||||
|
||||
test("mouse1click", {})
|
||||
|
||||
test("mouse1press", {})
|
||||
|
||||
test("mouse1release", {})
|
||||
|
||||
test("mouse2click", {})
|
||||
|
||||
test("mouse2press", {})
|
||||
|
||||
test("mouse2release", {})
|
||||
|
||||
test("mousemoveabs", {})
|
||||
|
||||
test("mousemoverel", {})
|
||||
|
||||
test("mousescroll", {})
|
||||
|
||||
-- Instances
|
||||
|
||||
test("fireclickdetector", {}, function()
|
||||
local detector = Instance.new("ClickDetector")
|
||||
fireclickdetector(detector, 50, "MouseHoverEnter")
|
||||
end)
|
||||
|
||||
test("getcallbackvalue", {}, function()
|
||||
local bindable = Instance.new("BindableFunction")
|
||||
local function test()
|
||||
end
|
||||
bindable.OnInvoke = test
|
||||
assert(getcallbackvalue(bindable, "OnInvoke") == test, "Did not return the correct value")
|
||||
end)
|
||||
|
||||
test("getconnections", {}, function()
|
||||
local types = {
|
||||
Enabled = "boolean",
|
||||
ForeignState = "boolean",
|
||||
LuaConnection = "boolean",
|
||||
Function = "function",
|
||||
Thread = "thread",
|
||||
Fire = "function",
|
||||
Defer = "function",
|
||||
Disconnect = "function",
|
||||
Disable = "function",
|
||||
Enable = "function",
|
||||
}
|
||||
local bindable = Instance.new("BindableEvent")
|
||||
bindable.Event:Connect(function() end)
|
||||
local connection = getconnections(bindable.Event)[1]
|
||||
for k, v in pairs(types) do
|
||||
assert(connection[k] ~= nil, "Did not return a table with a '" .. k .. "' field")
|
||||
assert(type(connection[k]) == v, "Did not return a table with " .. k .. " as a " .. v .. " (got " .. type(connection[k]) .. ")")
|
||||
end
|
||||
end)
|
||||
|
||||
test("getcustomasset", {}, function()
|
||||
writefile(".tests/getcustomasset.txt", "success")
|
||||
local contentId = getcustomasset(".tests/getcustomasset.txt")
|
||||
assert(type(contentId) == "string", "Did not return a string")
|
||||
assert(#contentId > 0, "Returned an empty string")
|
||||
assert(string.match(contentId, "rbxasset://") == "rbxasset://", "Did not return an rbxasset url")
|
||||
end)
|
||||
|
||||
test("gethiddenproperty", {}, function()
|
||||
local fire = Instance.new("Fire")
|
||||
local property, isHidden = gethiddenproperty(fire, "size_xml")
|
||||
assert(property == 5, "Did not return the correct value")
|
||||
assert(isHidden == true, "Did not return whether the property was hidden")
|
||||
end)
|
||||
|
||||
test("sethiddenproperty", {}, function()
|
||||
local fire = Instance.new("Fire")
|
||||
local hidden = sethiddenproperty(fire, "size_xml", 10)
|
||||
assert(hidden, "Did not return true for the hidden property")
|
||||
assert(gethiddenproperty(fire, "size_xml") == 10, "Did not set the hidden property")
|
||||
end)
|
||||
|
||||
test("gethui", {}, function()
|
||||
assert(typeof(gethui()) == "Instance", "Did not return an Instance")
|
||||
end)
|
||||
|
||||
test("getinstances", {}, function()
|
||||
assert(getinstances()[1]:IsA("Instance"), "The first value is not an Instance")
|
||||
end)
|
||||
|
||||
test("getnilinstances", {}, function()
|
||||
assert(getnilinstances()[1]:IsA("Instance"), "The first value is not an Instance")
|
||||
assert(getnilinstances()[1].Parent == nil, "The first value is not parented to nil")
|
||||
end)
|
||||
|
||||
test("isscriptable", {}, function()
|
||||
local fire = Instance.new("Fire")
|
||||
assert(isscriptable(fire, "size_xml") == false, "Did not return false for a non-scriptable property (size_xml)")
|
||||
assert(isscriptable(fire, "Size") == true, "Did not return true for a scriptable property (Size)")
|
||||
end)
|
||||
|
||||
test("setscriptable", {}, function()
|
||||
local fire = Instance.new("Fire")
|
||||
local wasScriptable = setscriptable(fire, "size_xml", true)
|
||||
assert(wasScriptable == false, "Did not return false for a non-scriptable property (size_xml)")
|
||||
assert(isscriptable(fire, "size_xml") == true, "Did not set the scriptable property")
|
||||
fire = Instance.new("Fire")
|
||||
assert(isscriptable(fire, "size_xml") == false, "⚠️⚠️ setscriptable persists between unique instances ⚠️⚠️")
|
||||
end)
|
||||
|
||||
test("setrbxclipboard", {})
|
||||
|
||||
-- Metatable
|
||||
|
||||
test("getrawmetatable", {}, function()
|
||||
local metatable = { __metatable = "Locked!" }
|
||||
local object = setmetatable({}, metatable)
|
||||
assert(getrawmetatable(object) == metatable, "Did not return the metatable")
|
||||
end)
|
||||
|
||||
test("hookmetamethod", {}, function()
|
||||
local object = setmetatable({}, { __index = newcclosure(function() return false end), __metatable = "Locked!" })
|
||||
local ref = hookmetamethod(object, "__index", function() return true end)
|
||||
assert(object.test == true, "Failed to hook a metamethod and change the return value")
|
||||
assert(ref() == false, "Did not return the original function")
|
||||
end)
|
||||
|
||||
test("getnamecallmethod", {}, function()
|
||||
local method
|
||||
local ref
|
||||
ref = hookmetamethod(game, "__namecall", function(...)
|
||||
if not method then
|
||||
method = getnamecallmethod()
|
||||
end
|
||||
return ref(...)
|
||||
end)
|
||||
game:GetService("Lighting")
|
||||
assert(method == "GetService", "Did not get the correct method (GetService)")
|
||||
end)
|
||||
|
||||
test("isreadonly", {}, function()
|
||||
local object = {}
|
||||
table.freeze(object)
|
||||
assert(isreadonly(object), "Did not return true for a read-only table")
|
||||
end)
|
||||
|
||||
test("setrawmetatable", {}, function()
|
||||
local object = setmetatable({}, { __index = function() return false end, __metatable = "Locked!" })
|
||||
local objectReturned = setrawmetatable(object, { __index = function() return true end })
|
||||
assert(object, "Did not return the original object")
|
||||
assert(object.test == true, "Failed to change the metatable")
|
||||
if objectReturned then
|
||||
return objectReturned == object and "Returned the original object" or "Did not return the original object"
|
||||
end
|
||||
end)
|
||||
|
||||
test("setreadonly", {}, function()
|
||||
local object = { success = false }
|
||||
table.freeze(object)
|
||||
setreadonly(object, false)
|
||||
object.success = true
|
||||
assert(object.success, "Did not allow the table to be modified")
|
||||
end)
|
||||
|
||||
-- Miscellaneous
|
||||
|
||||
test("identifyexecutor", {"getexecutorname"}, function()
|
||||
local name, version = identifyexecutor()
|
||||
assert(type(name) == "string", "Did not return a string for the name")
|
||||
return type(version) == "string" and "Returns version as a string" or "Does not return version"
|
||||
end)
|
||||
|
||||
test("lz4compress", {}, function()
|
||||
local raw = "Hello, world!"
|
||||
local compressed = lz4compress(raw)
|
||||
assert(type(compressed) == "string", "Compression did not return a string")
|
||||
assert(lz4decompress(compressed, #raw) == raw, "Decompression did not return the original string")
|
||||
end)
|
||||
|
||||
test("lz4decompress", {}, function()
|
||||
local raw = "Hello, world!"
|
||||
local compressed = lz4compress(raw)
|
||||
assert(type(compressed) == "string", "Compression did not return a string")
|
||||
assert(lz4decompress(compressed, #raw) == raw, "Decompression did not return the original string")
|
||||
end)
|
||||
|
||||
test("messagebox", {})
|
||||
|
||||
test("queue_on_teleport", {"queueonteleport"})
|
||||
|
||||
test("request", {"http.request", "http_request"}, function()
|
||||
local response = request({
|
||||
Url = "https://httpbin.org/user-agent",
|
||||
Method = "GET",
|
||||
})
|
||||
assert(type(response) == "table", "Response must be a table")
|
||||
assert(response.StatusCode == 200, "Did not return a 200 status code")
|
||||
local data = game:GetService("HttpService"):JSONDecode(response.Body)
|
||||
assert(type(data) == "table" and type(data["user-agent"]) == "string", "Did not return a table with a user-agent key")
|
||||
return "User-Agent: " .. data["user-agent"]
|
||||
end)
|
||||
|
||||
test("setclipboard", {"toclipboard"})
|
||||
|
||||
test("setfpscap", {}, function()
|
||||
local renderStepped = game:GetService("RunService").RenderStepped
|
||||
local function step()
|
||||
renderStepped:Wait()
|
||||
local sum = 0
|
||||
for _ = 1, 5 do
|
||||
sum += 1 / renderStepped:Wait()
|
||||
end
|
||||
return math.round(sum / 5)
|
||||
end
|
||||
setfpscap(60)
|
||||
local step60 = step()
|
||||
setfpscap(0)
|
||||
local step0 = step()
|
||||
return step60 .. "fps @60 • " .. step0 .. "fps @0"
|
||||
end)
|
||||
|
||||
-- Scripts
|
||||
|
||||
test("getgc", {}, function()
|
||||
local gc = getgc()
|
||||
assert(type(gc) == "table", "Did not return a table")
|
||||
assert(#gc > 0, "Did not return a table with any values")
|
||||
end)
|
||||
|
||||
test("getgenv", {}, function()
|
||||
getgenv().__TEST_GLOBAL = true
|
||||
assert(__TEST_GLOBAL, "Failed to set a global variable")
|
||||
getgenv().__TEST_GLOBAL = nil
|
||||
end)
|
||||
|
||||
test("getloadedmodules", {}, function()
|
||||
local modules = getloadedmodules()
|
||||
assert(type(modules) == "table", "Did not return a table")
|
||||
assert(#modules > 0, "Did not return a table with any values")
|
||||
assert(typeof(modules[1]) == "Instance", "First value is not an Instance")
|
||||
assert(modules[1]:IsA("ModuleScript"), "First value is not a ModuleScript")
|
||||
end)
|
||||
|
||||
test("getrenv", {}, function()
|
||||
assert(_G ~= getrenv()._G, "The variable _G in the executor is identical to _G in the game")
|
||||
end)
|
||||
|
||||
test("getrunningscripts", {}, function()
|
||||
local scripts = getrunningscripts()
|
||||
assert(type(scripts) == "table", "Did not return a table")
|
||||
assert(#scripts > 0, "Did not return a table with any values")
|
||||
assert(typeof(scripts[1]) == "Instance", "First value is not an Instance")
|
||||
assert(scripts[1]:IsA("ModuleScript") or scripts[1]:IsA("LocalScript"), "First value is not a ModuleScript or LocalScript")
|
||||
end)
|
||||
|
||||
test("getscriptbytecode", {"dumpstring"}, function()
|
||||
local animate = game:GetService("Players").LocalPlayer.Character.Animate
|
||||
local bytecode = getscriptbytecode(animate)
|
||||
assert(type(bytecode) == "string", "Did not return a string for Character.Animate (a " .. animate.ClassName .. ")")
|
||||
end)
|
||||
|
||||
test("getscripthash", {}, function()
|
||||
local animate = game:GetService("Players").LocalPlayer.Character.Animate:Clone()
|
||||
local hash = getscripthash(animate)
|
||||
local source = animate.Source
|
||||
animate.Source = "print('Hello, world!')"
|
||||
task.defer(function()
|
||||
animate.Source = source
|
||||
end)
|
||||
local newHash = getscripthash(animate)
|
||||
assert(hash ~= newHash, "Did not return a different hash for a modified script")
|
||||
assert(newHash == getscripthash(animate), "Did not return the same hash for a script with the same source")
|
||||
end)
|
||||
|
||||
test("getscripts", {}, function()
|
||||
local scripts = getscripts()
|
||||
assert(type(scripts) == "table", "Did not return a table")
|
||||
assert(#scripts > 0, "Did not return a table with any values")
|
||||
assert(typeof(scripts[1]) == "Instance", "First value is not an Instance")
|
||||
assert(scripts[1]:IsA("ModuleScript") or scripts[1]:IsA("LocalScript"), "First value is not a ModuleScript or LocalScript")
|
||||
end)
|
||||
|
||||
test("getsenv", {}, function()
|
||||
local animate = game:GetService("Players").LocalPlayer.Character.Animate
|
||||
local env = getsenv(animate)
|
||||
assert(type(env) == "table", "Did not return a table for Character.Animate (a " .. animate.ClassName .. ")")
|
||||
assert(env.script == animate, "The script global is not identical to Character.Animate")
|
||||
end)
|
||||
|
||||
test("getthreadidentity", {"getidentity", "getthreadcontext"}, function()
|
||||
assert(type(getthreadidentity()) == "number", "Did not return a number")
|
||||
end)
|
||||
|
||||
test("setthreadidentity", {"setidentity", "setthreadcontext"}, function()
|
||||
setthreadidentity(3)
|
||||
assert(getthreadidentity() == 3, "Did not set the thread identity")
|
||||
end)
|
||||
|
||||
-- Drawing
|
||||
|
||||
test("Drawing", {})
|
||||
|
||||
test("Drawing.new", {}, function()
|
||||
local drawing = Drawing.new("Square")
|
||||
drawing.Visible = false
|
||||
local canDestroy = pcall(function()
|
||||
drawing:Destroy()
|
||||
end)
|
||||
assert(canDestroy, "Drawing:Destroy() should not throw an error")
|
||||
end)
|
||||
|
||||
test("Drawing.Fonts", {}, function()
|
||||
assert(Drawing.Fonts.UI == 0, "Did not return the correct id for UI")
|
||||
assert(Drawing.Fonts.System == 1, "Did not return the correct id for System")
|
||||
assert(Drawing.Fonts.Plex == 2, "Did not return the correct id for Plex")
|
||||
assert(Drawing.Fonts.Monospace == 3, "Did not return the correct id for Monospace")
|
||||
end)
|
||||
|
||||
test("isrenderobj", {}, function()
|
||||
local drawing = Drawing.new("Image")
|
||||
drawing.Visible = true
|
||||
assert(isrenderobj(drawing) == true, "Did not return true for an Image")
|
||||
assert(isrenderobj(newproxy()) == false, "Did not return false for a blank table")
|
||||
end)
|
||||
|
||||
test("getrenderproperty", {}, function()
|
||||
local drawing = Drawing.new("Image")
|
||||
drawing.Visible = true
|
||||
assert(type(getrenderproperty(drawing, "Visible")) == "boolean", "Did not return a boolean value for Image.Visible")
|
||||
local success, result = pcall(function()
|
||||
return getrenderproperty(drawing, "Color")
|
||||
end)
|
||||
if not success or not result then
|
||||
return "Image.Color is not supported"
|
||||
end
|
||||
end)
|
||||
|
||||
test("setrenderproperty", {}, function()
|
||||
local drawing = Drawing.new("Square")
|
||||
drawing.Visible = true
|
||||
setrenderproperty(drawing, "Visible", false)
|
||||
assert(drawing.Visible == false, "Did not set the value for Square.Visible")
|
||||
end)
|
||||
|
||||
test("cleardrawcache", {}, function()
|
||||
cleardrawcache()
|
||||
end)
|
||||
|
||||
-- WebSocket
|
||||
|
||||
test("WebSocket", {})
|
||||
|
||||
test("WebSocket.connect", {}, function()
|
||||
local types = {
|
||||
Send = "function",
|
||||
Close = "function",
|
||||
OnMessage = {"table", "userdata"},
|
||||
OnClose = {"table", "userdata"},
|
||||
}
|
||||
local ws = WebSocket.connect("ws://echo.websocket.events")
|
||||
assert(type(ws) == "table" or type(ws) == "userdata", "Did not return a table or userdata")
|
||||
for k, v in pairs(types) do
|
||||
if type(v) == "table" then
|
||||
assert(table.find(v, type(ws[k])), "Did not return a " .. table.concat(v, ", ") .. " for " .. k .. " (a " .. type(ws[k]) .. ")")
|
||||
else
|
||||
assert(type(ws[k]) == v, "Did not return a " .. v .. " for " .. k .. " (a " .. type(ws[k]) .. ")")
|
||||
end
|
||||
end
|
||||
ws:Close()
|
||||
end)
|
||||
Reference in New Issue
Block a user