summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--meta/3rd/busted/config.lua12
-rw-r--r--meta/3rd/busted/library/busted.lua298
-rw-r--r--meta/3rd/luassert/config.lua1
-rw-r--r--meta/3rd/luassert/library/luassert.lua442
-rw-r--r--meta/3rd/luassert/library/luassert/array.lua16
-rw-r--r--meta/3rd/luassert/library/luassert/match.lua416
-rw-r--r--meta/3rd/luassert/library/luassert/mock.lua28
-rw-r--r--meta/3rd/luassert/library/luassert/spy.d.lua100
-rw-r--r--meta/3rd/luassert/library/luassert/spy.lua81
-rw-r--r--meta/3rd/luassert/library/luassert/stub.lua50
10 files changed, 1444 insertions, 0 deletions
diff --git a/meta/3rd/busted/config.lua b/meta/3rd/busted/config.lua
new file mode 100644
index 00000000..9a0b09f3
--- /dev/null
+++ b/meta/3rd/busted/config.lua
@@ -0,0 +1,12 @@
+files = {
+ ".*_spec%.lua",
+ ".*_test%.lua",
+}
+
+configs = {
+ {
+ key = "Lua.workspace.library",
+ action = "add",
+ value = "${3rd}/luassert/library",
+ },
+}
diff --git a/meta/3rd/busted/library/busted.lua b/meta/3rd/busted/library/busted.lua
new file mode 100644
index 00000000..10c06d60
--- /dev/null
+++ b/meta/3rd/busted/library/busted.lua
@@ -0,0 +1,298 @@
+---@meta
+
+assert = require("luassert")
+spy = require("luassert.spy")
+stub = require("luassert.stub")
+mock = require("luassert.mock")
+
+---Undocumented feature with unknown purpose.
+---@param filename string
+function file(filename) end
+
+---Mark a test as placeholder.
+---
+---This will not fail or pass, it will simply be marked as "pending".
+---@param name string
+---@param block fun()
+function pending(name, block) end
+
+---Define the start of an asynchronous test.
+---
+---Call `done()` at the end of your test to complete it.
+---
+---## Example
+---```
+---it("Makes an http request", function()
+--- async()
+--- http.get("https://github.com", function()
+--- print("Got Website!")
+--- done()
+--- end)
+---end)
+---```
+function async() end
+
+---Mark the end of an asynchronous test.
+---
+---Should be paired with a call to `async()`.
+function done() end
+
+---Used to define a set of tests. Can be nested to define sub-tests.
+---
+---## Example
+---```
+---describe("Test Item Class", function()
+--- it("Creates an item", function()
+--- --...
+--- end)
+--- describe("Test Tags", function()
+--- it("Creates a tag", function()
+--- --...
+--- end)
+--- end)
+---end)
+---```
+---@param name string
+---@param block fun()
+function describe(name, block) end
+
+context = describe
+
+---Functions like `describe()` except it exposes the test's environment to
+---outer contexts
+---
+---## Example
+---```
+---describe("Test exposing", function()
+--- expose("Exposes a value", function()
+--- _G.myValue = 10
+--- end)
+---
+---end)
+---
+---describe("Another test in the same file", function()
+--- assert.are.equal(10, myValue)
+---end)
+---```
+---@param name string
+---@param block fun()
+function expose(name, block) end
+
+---Functions like `describe()` except it insulates the test's environment to
+---only this context.
+---
+---This is the default behaviour of `describe()`.
+---
+---## Example
+---```
+---describe("Test exposing", function()
+--- insulate("Insulates a value", function()
+--- _G.myValue = 10
+--- end)
+---
+---end)
+---
+---describe("Another test in the same file", function()
+--- assert.is.Nil(myValue)
+---end)
+---```
+---@param name string
+---@param block fun()
+function insulate(name, block) end
+
+---Randomize tests nested in this block.
+---
+---## Example
+---```
+---describe("A randomized test", function()
+--- randomize()
+--- it("My order is random", function() end)
+--- it("My order is also random", function() end)
+---end)
+---```
+function randomize() end
+
+---Define a test that will pass, fail, or error.
+---
+---You can also use `spec()` and `test()` as aliases.
+---
+---## Example
+---```
+---describe("Test something", function()
+--- it("Runs a test", function()
+--- assert.is.True(10 == 10)
+--- end)
+---end)
+---```
+---@param name string
+---@param block fun()
+function it(name, block) end
+
+spec = it
+test = it
+
+---Define a function to run before each child test, this includes tests nested
+---in a child describe block.
+---
+---## Example
+---```
+---describe("Test Array Class", function()
+--- local a
+--- local b
+---
+--- before_each(function()
+--- a = Array.new(1, 2, 3, 4)
+--- b = Array.new(11, 12, 13, 14)
+--- end)
+---
+--- it("Assures instance is an Array", function()
+--- assert.True(Array.isArray(a))
+--- assert.True(Array.isArray(b))
+--- end)
+---
+--- describe("Nested tests", function()
+--- it("Also runs before_each", function()
+--- assert.are.same(
+--- { 1, 2, 3, 4, 11, 12, 13, 14 },
+--- a:concat(b))
+--- end)
+--- end)
+---end)
+---```
+---@param block fun()
+function before_each(block) end
+
+---Define a function to run after each child test, this includes tests nested
+---in a child describe block.
+---
+---## Example
+---```
+---describe("Test saving", function()
+--- local game
+---
+--- after_each(function()
+--- game.save.reset()
+--- end)
+---
+--- it("Creates game", function()
+--- game = game.new()
+--- game.save.save()
+--- end)
+---
+--- describe("Saves metadata", function()
+--- it("Saves objects", function()
+--- game = game.new()
+--- game.save.save()
+--- assert.is_not.Nil(game.save.objects)
+--- end)
+--- end)
+---end)
+---```
+---@param block fun()
+function after_each(block) end
+
+---Runs first in a context block before any tests.
+---
+---Will always run even if there are no child tests to run. If you don't want
+---them to run regardless, you can use `lazy_setup()` or use the `--lazy` flag
+---when running.
+---
+---## Example
+---```
+---describe("Test something", function()
+--- local helper
+---
+--- setup(function()
+--- helper = require("helper")
+--- end)
+---
+--- it("Can use helper", function()
+--- assert.is_not.Nil(helper)
+--- end)
+---end)
+---```
+---@param block fun()
+function setup(block) end
+
+strict_setup = setup
+
+---Runs first in a context block before any tests. Only runs if there are child
+---tests to run.
+---
+---## Example
+---```
+---describe("Test something", function()
+--- local helper
+---
+--- -- Will not run because there are no tests
+--- lazy_setup(function()
+--- helper = require("helper")
+--- end)
+---
+---end)
+---```
+---@param block fun()
+function lazy_setup(block) end
+
+---Runs last in a context block after all tests.
+---
+---Will run ever if no tests were run in this context. If you don't want this
+---to run regardless, you can use `lazy_teardown()` or use the `--lazy` flag
+---when running.
+---
+---## Example
+---```
+---describe("Remove persistent value", function()
+--- local persist
+---
+--- it("Sets a persistent value", function()
+--- persist = "hello"
+--- end)
+---
+--- teardown(function()
+--- persist = nil
+--- end)
+---
+---end)
+---```
+---@param block fun()
+function teardown(block) end
+
+strict_teardown = teardown
+
+---Runs last in a context block after all tests.
+---
+---Will only run if tests were run in this context.
+---
+---## Example
+---```
+---describe("Remove persistent value", function()
+--- local persist
+---
+--- -- Will not run because no tests were run
+--- lazy_teardown(function()
+--- persist = nil
+--- end)
+---
+---end)
+---```
+---@param block fun()
+function lazy_teardown(block) end
+
+---Runs last in a context block regardless of test outcome
+---
+---## Example
+---```
+---it("Read File Contents",function()
+--- local f = io.open("file", "r")
+---
+--- -- always close file after test
+--- finally(function()
+--- f:close()
+--- end)
+---
+--- -- do stuff with f
+---end)
+---```
+---@param block fun()
+function finally(block) end
diff --git a/meta/3rd/luassert/config.lua b/meta/3rd/luassert/config.lua
new file mode 100644
index 00000000..e99f802c
--- /dev/null
+++ b/meta/3rd/luassert/config.lua
@@ -0,0 +1 @@
+words = { "assert.%w+" }
diff --git a/meta/3rd/luassert/library/luassert.lua b/meta/3rd/luassert/library/luassert.lua
new file mode 100644
index 00000000..21f2fe9a
--- /dev/null
+++ b/meta/3rd/luassert/library/luassert.lua
@@ -0,0 +1,442 @@
+---@meta
+
+---@class luassert.internal
+local internal = {}
+
+---@class luassert:luassert.internal
+local luassert = {}
+
+--#region Assertions
+
+---Assert that `value == true`.
+---@param value any The value to confirm is `true`.
+function internal.True(value) end
+
+internal.is_true = internal.True
+internal.is_not_true = internal.True
+
+---Assert that `value == false`.
+---@param value any The value to confirm is `false`.
+function internal.False(value) end
+
+internal.is_false = internal.False
+internal.is_not_false = internal.False
+
+---Assert that `type(value) == "boolean"`.
+---@param value any The value to confirm is of type `boolean`.
+function internal.Boolean(value) end
+
+internal.boolean = internal.Boolean
+internal.is_boolean = internal.Boolean
+internal.is_not_boolean = internal.Boolean
+
+---Assert that `type(value) == "number"`.
+---@param value any The value to confirm is of type `number`.
+function internal.Number(value) end
+
+internal.number = internal.Number
+internal.is_number = internal.Number
+internal.is_not_number = internal.Number
+
+---Assert that `type(value) == "string"`.
+---@param value any The value to confirm is of type `string`.
+function internal.String(value) end
+
+internal.string = internal.String
+internal.is_string = internal.String
+internal.is_not_string = internal.String
+
+---Assert that `type(value) == "table"`.
+---@param value any The value to confirm is of type `table`.
+function internal.Table(value) end
+
+internal.table = internal.Table
+internal.is_table = internal.Table
+internal.is_not_table = internal.Table
+
+---Assert that `type(value) == "nil"`.
+---@param value any The value to confirm is of type `nil`.
+function internal.Nil(value) end
+
+internal.is_nil = internal.Nil
+internal.is_not_nil = internal.Nil
+
+---Assert that `type(value) == "userdata"`.
+---@param value any The value to confirm is of type `userdata`.
+function internal.Userdata(value) end
+
+internal.userdata = internal.Userdata
+internal.is_userdata = internal.Userdata
+internal.is_not_userdata = internal.Userdata
+
+---Assert that `type(value) == "function"`.
+---@param value any The value to confirm is of type `function`.
+function internal.Function(value) end
+
+internal.is_function = internal.Function
+internal.is_not_function = internal.Function
+
+---Assert that `type(value) == "thread"`.
+---@param value any The value to confirm is of type `thread`.
+function internal.Thread(value) end
+
+internal.thread = internal.Thread
+internal.is_thread = internal.Thread
+internal.is_not_thread = internal.Thread
+
+
+---Assert that a value is truthy.
+---@param value any The value to confirm is truthy.
+function internal.truthy(value) end
+
+internal.Truthy = internal.truthy
+internal.is_truthy = internal.truthy
+internal.is_not_truthy = internal.truthy
+
+---Assert that a value is falsy.
+---@param value any The value to confirm is falsy.
+function internal.falsy(value) end
+
+internal.Falsy = internal.falsy
+internal.is_falsy = internal.falsy
+internal.is_not_falsy = internal.falsy
+
+---Assert that a callback throws an error.
+---@param callback function A callback function that should error
+---@param error? string The specific error message that will be asserted
+function internal.error(callback, error) end
+
+internal.Error = internal.error
+internal.has_error = internal.error
+internal.no_error = internal.error
+internal.no_has_error = internal.error
+internal.has_no_error = internal.error
+
+--- the api is the same as string.find
+---@param pattern string
+---@param actual string
+---@param init? integer
+---@param plain? boolean
+---## Example
+--[[
+```lua
+ it("Checks matches() assertion does string matching", function()
+ assert.is.error(function() assert.matches('.*') end) -- minimum 2 arguments
+ assert.is.error(function() assert.matches(nil, 's') end) -- arg1 must be a string
+ assert.is.error(function() assert.matches('s', {}) end) -- arg2 must be convertable to string
+ assert.is.error(function() assert.matches('s', 's', 's', 's') end) -- arg3 or arg4 must be a number or nil
+ assert.matches("%w+", "test")
+ assert.has.match("%w+", "test")
+ assert.has_no.match("%d+", "derp")
+ assert.has.match("test", "test", nil, true)
+ assert.has_no.match("%w+", "test", nil, true)
+ assert.has.match("^test", "123 test", 5)
+ assert.has_no.match("%d+", "123 test", '4')
+ end)
+```
+]]
+function internal.matches(pattern, actual, init, plain) end
+
+internal.is_matches = internal.matches
+internal.is_not_matches = internal.matches
+
+internal.match = internal.matches
+internal.is_match = internal.matches
+internal.is_not_match = internal.matches
+
+---Assert that two values are near (equal to within a tolerance).
+---@param expected number The expected value
+---@param actual number The actual value
+---@param tolerance number The tolerable difference between the two values
+---## Example
+--[[
+ ```lua
+ it("Checks near() assertion handles tolerances", function()
+ assert.is.error(function() assert.near(0) end) -- minimum 3 arguments
+ assert.is.error(function() assert.near(0, 0) end) -- minimum 3 arguments
+ assert.is.error(function() assert.near('a', 0, 0) end) -- arg1 must be convertable to number
+ assert.is.error(function() assert.near(0, 'a', 0) end) -- arg2 must be convertable to number
+ assert.is.error(function() assert.near(0, 0, 'a') end) -- arg3 must be convertable to number
+ assert.is.near(1.5, 2.0, 0.5)
+ assert.is.near('1.5', '2.0', '0.5')
+ assert.is_not.near(1.5, 2.0, 0.499)
+ assert.is_not.near('1.5', '2.0', '0.499')
+ end)
+ ```
+]]
+function internal.near(expected, actual, tolerance) end
+
+internal.Near = internal.near
+internal.is_near = internal.near
+internal.is_not_near = internal.near
+
+---Check that two or more items are equal.
+---
+---When comparing tables, a reference check will be used.
+---@param expected any The expected value
+---@param ... any Values to check the equality of
+function internal.equal(expected, ...) end
+
+internal.Equal = internal.equal
+internal.are_equal = internal.equal
+internal.are_not_equal = internal.equal
+
+---Check that two or more items that are considered the "same".
+---
+---When comparing tables, a deep compare will be performed.
+---@param expected any The expected value
+---@param ... any Values to check
+function internal.same(expected, ...) end
+
+internal.Same = internal.same
+internal.are_same = internal.same
+internal.are_not_same = internal.same
+
+--- Number of return values of function
+---@param argument_number integer
+---@param func fun()
+function internal.returned_arguments(argument_number, func) end
+
+internal.not_returned_arguments = internal.returned_arguments
+
+--- check error message by string.match/string.find(`plain`=true)
+---@param func function
+---@param pattern string
+---@param init? integer
+---@param plain? boolean
+---##Example
+--[[
+```lua
+ it("Checks error_matches to accept only callable arguments", function()
+ local t_ok = setmetatable( {}, { __call = function() end } )
+ local t_nok = setmetatable( {}, { __call = function() error("some error") end } )
+ local f_ok = function() end
+ local f_nok = function() error("some error") end
+
+ assert.error_matches(f_nok, ".*")
+ assert.no_error_matches(f_ok, ".*")
+ assert.error_matches(t_nok, ".*")
+ assert.no_error_matches(t_ok, ".*")
+ end)
+```
+]]
+function internal.error_matches(func, pattern, init, plain) end
+
+internal.no_error_matches = internal.error_matches
+
+internal.error_match = internal.error_matches
+internal.no_error_match = internal.error_matches
+
+internal.matches_error = internal.error_matches
+internal.no_matches_error = internal.error_matches
+
+internal.match_error = internal.error_matches
+internal.no_match_error = internal.error_matches
+
+--#endregion
+
+--[[ Helpers ]]
+
+--#region
+
+---Assert that all numbers in two arrays are within a specified tolerance of
+---each other.
+---@param expected number[] The expected values
+---@param actual number[] The actual values
+---@param tolerance number The tolerable difference between the values in the two arrays
+function internal.all_near(expected, actual, tolerance) end
+
+internal.are_all_near = internal.all_near
+internal.are_not_all_near = internal.all_near
+
+--- array is uniqued
+---@param arr any[]
+---## Example
+---```lua
+---it("Checks to see if table1 only contains unique elements", function()
+--- local table2 = { derp = false}
+--- local table3 = { derp = true }
+--- local table1 = {table2,table3}
+--- local tablenotunique = {table2,table2}
+--- assert.is.unique(table1)
+--- assert.is_not.unique(tablenotunique)
+--- end)
+---```
+function internal.unique(arr) end
+
+internal.is_unique = internal.unique
+internal.is_not_unique = internal.unique
+
+--#endregion
+
+--#region Spies
+
+---Perform an assertion on a spy object. This will allow you to call further
+---functions to perform an assertion.
+---@param spy luassert.spy The spy object to begin asserting
+---@return luassert.spy.assert spyAssert A new object that has further assert function options
+function internal.spy(spy) end
+
+---Perform an assertion on a stub object. This will allow you to call further
+---functions to perform an assertion.
+---@param stub luassert.spy The stub object to begin asserting
+---@return luassert.spy.assert stubAssert A new object that has further assert function options
+function internal.stub(stub) end
+
+--#endregion
+
+--#region Array
+
+---Perform an assertion on an array object. This will allow you to call further
+---function to perform an assertion.
+---@param object table<integer, any> The array object to begin asserting
+---@return luassert.array arrayAssert A new object that has further assert function options
+function internal.array(object) end
+
+--#endregion
+
+--#region test apis
+
+--- register custom assertions
+---@param namespace 'assertion' | 'matcher' | 'modifier' | string
+---@param name string
+---@param callback function
+---@param positive_message string
+---@param negative_message string
+---## Example
+--[[
+```lua
+ it("Checks register creates custom assertions", function()
+ local say = require("say")
+
+ local function has_property(state, arguments)
+ local property = arguments[1]
+ local table = arguments[2]
+ for key, value in pairs(table) do
+ if key == property then
+ return true
+ end
+ end
+ return false
+ end
+
+ say:set_namespace("en")
+ say:set("assertion.has_property.positive", "Expected property %s in:\n%s")
+ say:set("assertion.has_property.negative", "Expected property %s to not be in:\n%s")
+ assert:register("assertion", "has_property", has_property, "assertion.has_property.positive", "assertion.has_property.negative")
+
+ assert.has_property("name", { name = "jack" })
+ assert.has.property("name", { name = "jack" })
+ assert.not_has_property("surname", { name = "jack" })
+ assert.Not.has.property("surname", { name = "jack" })
+ assert.has_error(function() assert.has_property("surname", { name = "jack" }) end)
+ assert.has_error(function() assert.has.property("surname", { name = "jack" }) end)
+ assert.has_error(function() assert.no_has_property("name", { name = "jack" }) end)
+ assert.has_error(function() assert.no.has.property("name", { name = "jack" }) end)
+ end)
+```
+]]
+function luassert:register(namespace, name, callback, positive_message, negative_message) end
+
+--[[
+ ### Customized formatters
+The formatters are functions taking a single argument that needs to be converted to a string representation. The formatter should examine the value provided, if it can format the value, it should return the formatted string, otherwise it should return `nil`.
+Formatters can be added through `assert:add_formatter(formatter_func)`, and removed by calling `assert:remove_formatter(formatter_func)`.
+
+Example using the included binary string formatter:
+```lua
+local binstring = require("luassert.formatters.binarystring")
+
+describe("Tests using a binary string formatter", function()
+
+ setup(function()
+ assert:add_formatter(binstring)
+ end)
+
+ teardown(function()
+ assert:remove_formatter(binstring)
+ end)
+
+ it("tests a string comparison with binary formatting", function()
+ local s1, s2 = "", ""
+ for n = 65,88 do
+ s1 = s1 .. string.char(n)
+ s2 = string.char(n) .. s2
+ end
+ assert.are.same(s1, s2)
+
+ end)
+
+end)
+```
+
+Because this formatter formats string values, and is added last, it will take precedence over the regular string formatter. The results will be:
+```
+Failure: ...ua projects\busted\formatter\spec\formatter_spec.lua @ 13
+tests a string comparison with binary formatting
+...ua projects\busted\formatter\spec\formatter_spec.lua:19: Expected objects to be the same. Passed in:
+Binary string length; 24 bytes
+58 57 56 55 54 53 52 51 50 4f 4e 4d 4c 4b 4a 49 XWVUTSRQ PONMLKJI
+48 47 46 45 44 43 42 41 HGFEDCBA
+
+Expected:
+Binary string length; 24 bytes
+41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 ABCDEFGH IJKLMNOP
+51 52 53 54 55 56 57 58 QRSTUVWX
+```
+]]
+---@param callback fun(obj:any):string|nil
+function luassert:add_formatter(callback) end
+
+---@param fmtr function
+function luassert:remove_formatter(fmtr) end
+
+--- To register state information 'parameters' can be used. The parameter is included in a snapshot and can hence be restored in between tests. For an example see `Configuring table depth display` below.
+---@param name any
+---@param value any
+---## Example
+--[[
+```lua
+assert:set_parameter("my_param_name", 1)
+local s = assert:snapshot()
+assert:set_parameter("my_param_name", 2)
+s:revert()
+assert.are.equal(1, assert:get_parameter("my_param_name"))
+```
+]]
+function luassert:set_parameter(name, value) end
+
+--- get current snapshot parameter
+---@param name any
+---@return any value
+function luassert:get_parameter(name) end
+
+---To be able to revert changes created by tests, inserting spies and stubs for example, luassert supports 'snapshots'. A snapshot includes the following;
+---@return {revert:fun()}
+function luassert:snapshot() end
+
+--#endregion
+
+--- unregister custom assertions
+---@param namespace 'assertion' | 'matcher' | 'modifier' | string
+---@param name string
+function luassert:unregister(namespace, name) end
+
+--#region modifier namespace
+
+internal.are = internal
+internal.is = internal
+internal.has = internal
+internal.does = internal
+
+internal.is_not = internal
+internal.are_not = internal
+internal.has_no = internal
+internal.no_has = internal
+internal.does_not = internal
+internal.no = internal
+internal.Not = internal
+
+--#endregion
+
+return luassert
diff --git a/meta/3rd/luassert/library/luassert/array.lua b/meta/3rd/luassert/library/luassert/array.lua
new file mode 100644
index 00000000..89253a12
--- /dev/null
+++ b/meta/3rd/luassert/library/luassert/array.lua
@@ -0,0 +1,16 @@
+---@meta
+
+---@class luassert.array
+local array = {}
+
+
+---Assert that an array has holes in it
+---@param length? integer The expected length of the array
+---@return integer|nil holeIndex The index of the first found hole or `nil` if there was no hole.
+function array.holes(length) end
+
+array.has = array
+
+array.no = array
+
+return array
diff --git a/meta/3rd/luassert/library/luassert/match.lua b/meta/3rd/luassert/library/luassert/match.lua
new file mode 100644
index 00000000..6a61b728
--- /dev/null
+++ b/meta/3rd/luassert/library/luassert/match.lua
@@ -0,0 +1,416 @@
+---@meta
+
+---Matchers are used to provide flexible argument matching for `called_with` and
+---`returned_with` asserts for spies. Just like with asserts, you can chain a
+---modifier value using `is` or `is_not`, followed by the matcher you wish to use.
+---@class luassert.match
+match = {}
+
+---Match a value from a spy
+match.is = {}
+
+---Match inverse values from a spy
+match.is_not = {}
+
+--- Wildcard match, matches anything.
+--
+---## Example
+---```
+---it("tests wildcard matcher", function()
+--- local s = spy.new(function() end)
+--- local _ = match._
+---
+--- s("foo")
+---
+--- assert.spy(s).was_called_with(_) -- matches any argument
+--- assert.spy(s).was_not_called_with(_, _) -- does not match two arguments
+---end)
+---```
+match._ = {}
+
+--[[ Modifiers ]]
+
+--#region
+
+---If you're creating a spy for functions that mutate any properties on a table
+---(like `self`) and you want to use `was_called_with`, you should use
+---`match.is_ref(obj)`.
+---
+---## Example
+---```lua
+---describe("combine matchers", function()
+--- local match = require("luassert.match")
+---
+--- it("tests ref matchers for passed in table", function()
+--- local t = { count = 0, }
+--- function t.incrby(t, i) t.count = t.count + i end
+---
+--- local s = spy.on(t, "incrby")
+---
+--- s(t, 2)
+---
+--- assert.spy(s).was_called_with(match.is_ref(t), 2)
+--- end)
+---
+--- it("tests ref matchers for self", function()
+--- local t = { count = 0, }
+--- function t:incrby(i) self.count = self.count + i end
+---
+--- local s = spy.on(t, "incrby")
+---
+--- t:incrby(2)
+---
+--- assert.spy(s).was_called_with(match.is_ref(t), 2)
+--- end)
+---end)
+---```
+---@param obj any
+function match.Ref(obj) end
+match.ref = match.Ref
+match.is.Ref = match.Ref
+match.is.ref = match.Ref
+match.is_ref = match.Ref
+
+
+---Combine matchers, matching all provided matchers.
+---@param ... table|function
+---```lua
+---describe("combine matchers", function()
+--- local match = require("luassert.match")
+---
+--- it("tests composite matchers", function()
+--- local s = spy.new(function() end)
+---
+--- s("foo")
+---
+--- assert.spy(s).was_called_with(match.is_all_of(
+--- match.is_not_nil(),
+--- match.is_not_number()
+--- ))
+--- end)
+---end)
+---```
+function match.all_of(...) end
+match.is_all_of = match.all_of
+match.is.all_of = match.all_of
+
+---Combine matchers, matching at least one provided matcher.
+---@param ... table|function
+---```lua
+---describe("combine matchers", function()
+--- local match = require("luassert.match")
+---
+--- it("tests composite matchers", function()
+--- local s = spy.new(function() end)
+---
+--- s("foo")
+---
+--- assert.spy(s).was_called_with(match.is_any_of(
+--- match.is_number(),
+--- match.is_string(),
+--- match.is_boolean()
+--- ))
+--- end)
+---end)
+---```
+function match.any_of(...) end
+match.is_any_of = match.any_of
+match.is.any_of = match.any_of
+
+---Combine matchers, matching none of the provided matchers.
+---@param ... table|function
+---```lua
+---describe("combine matchers", function()
+--- local match = require("luassert.match")
+---
+--- it("tests composite matchers", function()
+--- local s = spy.new(function() end)
+---
+--- s("foo")
+---
+--- assert.spy(s).was_called_with(match.is_none_of(
+--- match.is_number(),
+--- match.is_table(),
+--- match.is_boolean()
+--- ))
+--- end)
+---end)
+---```
+function match.none_of(...) end
+match.is_none_of = match.none_of
+match.is.none_of = match.none_of
+
+--#endregion
+
+
+--[[ Matchers ]]
+
+--#region
+
+---Check that the value is `true`.
+---@return boolean isTrue
+function match.True() end
+match.is.True = match.True
+match.is_true = match.True
+
+---Check that the value is `false`.
+---@return boolean isFalse
+function match.False() end
+match.is.True = match.False
+match.is_false = match.False
+
+---Check that the value is `nil`.
+---@return boolean isNil
+function match.Nil() end
+match.is.Nil = match.Nil
+match.is_nil = match.Nil
+
+---Check that the value is of type `boolean`.
+---@return boolean isBoolean
+function match.Boolean() end
+match.boolean = match.Boolean
+match.is.Boolean = match.Boolean
+match.is.boolean = match.Boolean
+match.is_boolean = match.Boolean
+
+---Check that the value is of type `number`.
+---@return boolean isNumber
+function match.Number() end
+match.number = match.Number
+match.is.Number = match.Number
+match.is.number = match.Number
+match.is_number = match.Number
+
+---Check that the value is of type `string`.
+---@return boolean isString
+function match.String() end
+match.string = match.String
+match.is.String = match.String
+match.is.string = match.String
+match.is_string = match.String
+
+---Check that the value is of type `table`.
+---@return boolean isTable
+function match.Table() end
+match.table = match.Table
+match.is.Table = match.Table
+match.is.table = match.Table
+match.is_table = match.Table
+
+---Check that the value is of type `function`.
+---@return boolean isFunction
+function match.Function() end
+match.is.Function = match.Function
+match.is_function = match.Function
+
+---Check that the value is of type `userdata`.
+---@return boolean isUserdata
+function match.Userdata() end
+match.userdata = match.Userdata
+match.is.Userdata = match.Userdata
+match.is.userdata = match.Userdata
+match.is_userdata = match.Userdata
+
+---Check that the value is of type `thread`.
+---@return boolean isThread
+function match.Thread() end
+match.thread = match.Thread
+match.is.thread = match.Thread
+match.is.Thread = match.Thread
+match.is_thread = match.Thread
+
+---Check that the value is truthy.
+---@return boolean isTruthy
+function match.truthy() end
+match.Truthy = match.truthy
+match.is.truthy = match.truthy
+match.is.Truthy = match.truthy
+match.is_truthy = match.truthy
+
+---Check that the value is falsy.
+---@return boolean isFalsy
+function match.falsy() end
+match.Falsy = match.falsy
+match.is.falsy = match.falsy
+match.is.Falsy = match.falsy
+match.is_falsy = match.falsy
+
+---Check that the two values are equal.
+---
+---When comparing tables, a reference check will be used.
+---@param value any The target value
+---@return boolean isEqual
+function match.Equals(value) end
+match.equals = match.Equals
+match.is.equals = match.Equals
+match.is.equals = match.Equals
+match.is_equals = match.Equals
+
+---Check that the two values are considered the "same".
+---
+---When comparing tables, a deep compare will be performed.
+---@param value any The target value
+---@return boolean isSame
+function match.Same(value) end
+match.same = match.Same
+match.is.same = match.Same
+match.is.same = match.Same
+match.is_same = match.Same
+
+---Match a table with unique values. Will pass if no values are duplicates.
+---@param deep boolean If a deep check should be performed or just the first level
+---@return boolean isUnique
+function match.Unique(deep) end
+match.unique = match.Unique
+match.is.unique = match.Unique
+match.is.unique = match.Unique
+match.is_unique = match.Unique
+
+---Match a certain numerical value with a specified +/- tolerance.
+---@param value number The target value
+---@param tolerance number The amount that the true value can be off by (inclusive)
+---@return boolean isNear
+function match.Near(value, tolerance) end
+match.near = match.Near
+match.is.near = match.Near
+match.is.near = match.Near
+match.is_near = match.Near
+
+---Perform a `string.find()` match.
+---@param pattern string String match pattern
+---@param init integer Index of character to start searching for a match at
+---@param plain boolean If the `pattern` should be treated as plain text instead of a pattern
+---@return boolean matches
+function match.Matches(pattern, init, plain) end
+match.matches = match.Matches
+match.is.matches = match.Matches
+match.is.matches = match.Matches
+match.is_matches = match.Matches
+match.match = match.Matches
+match.Match = match.matches
+match.is.match = match.Matches
+match.is.Matches = match.Matches
+match.is_match = match.Matches
+
+--#endregion
+
+
+--[[ Inverse Matchers ]]
+
+--#region
+
+---Check that the value is **NOT** `true`.
+---@return boolean isTrue
+function match.is_not.True() end
+match.is_not_true = match.is_not.True
+
+---Check that the value is **NOT** `false`.
+---@return boolean isFalse
+function match.is_not.False() end
+match.is_not_false = match.is_not.False
+
+---Check that the value is **NOT** `nil`.
+---@return boolean isNil
+function match.is_not.Nil() end
+match.is_not_nil = match.is_not.Nil
+
+---Check that the value is **NOT** of type `boolean`.
+---@return boolean isBoolean
+function match.is_not.Boolean() end
+match.is_not.boolean = match.is_not.Boolean
+match.is_not_boolean = match.is_not.Boolean
+
+---Check that the value is **NOT** of type `number`.
+---@return boolean isNumber
+function match.is_not.Number() end
+match.is_not.number = match.is_not.Number
+match.is_not_number = match.is_not.Number
+
+---Check that the value is **NOT** of type `string`.
+---@return boolean isString
+function match.is_not.String() end
+match.is_not.string = match.is_not.String
+match.is_not_string = match.is_not.String
+
+---Check that the value is **NOT** of type `table`.
+---@return boolean isTable
+function match.is_not.Table() end
+match.is_not.table = match.is_not.Table
+match.is_not_table = match.is_not.Table
+
+---Check that the value is **NOT** of type `function`.
+---@return boolean isFunction
+function match.is_not.Function() end
+match.is_not_function = match.is_not.Function
+
+---Check that the value is **NOT** of type `userdata`.
+---@return boolean isUserdata
+function match.is_not.Userdata() end
+match.is_not.userdata = match.is_not.Userdata
+match.is_not_userdata = match.is_not.Userdata
+
+---Check that the value is **NOT** of type `thread`.
+---@return boolean isThread
+function match.is_not.Thread() end
+match.is_not.Thread = match.is_not.Thread
+match.is_not_thread = match.is_not.Thread
+
+---Check that the value is **NOT** truthy.
+---@return boolean isTruthy
+function match.is_not.truthy() end
+match.is_not.Truthy = match.is_not.truthy
+match.is_not_truthy = match.is_not.truthy
+
+---Check that the value is **NOT** falsy.
+---@return boolean isFalsy
+function match.is_not.falsy() end
+match.is_not.Falsy = match.is_not.falsy
+match.is_not_falsy = match.is_not.falsy
+
+---Check that the two values are **NOT** equal.
+---
+---When comparing tables, a reference check will be used.
+---@param value any The target value
+---@return boolean isEqual
+function match.is_not.Equals(value) end
+match.is_not.equals = match.is_not.Equals
+match.is_not_equals = match.is_not.Equals
+
+---Check that the two values are **NOT** considered the "same".
+---
+---When comparing tables, a deep compare will be performed.
+---@param value any The target value
+---@return boolean isSame
+function match.is_not.Same(value) end
+match.is_not.same = match.is_not.Same
+match.is_not_same = match.is_not.Same
+
+---Match a table with **NOT** unique values. Will pass if at least one duplicate is found.
+---@param deep boolean If a deep check should be performed or just the first level
+---@return boolean isUnique
+function match.is_not.Unique(deep) end
+match.is_not.unique = match.is_not.Unique
+match.is_not_unique = match.is_not.Unique
+
+---Match a certain numerical value outside a specified +/- tolerance.
+---@param value number The target value
+---@param tolerance number The amount that the true value must be off by (inclusive)
+---@return boolean isNear
+function match.is_not.Near(value, tolerance) end
+match.is_not.near = match.is_not.Near
+match.is_not_near = match.is_not.Near
+
+---Perform a `string.find()` match to find a value that does **NOT** match.
+---@param pattern string String match pattern
+---@param init integer Index of character to start searching for a match at
+---@param plain boolean If the `pattern` should be treated as plain text instead of a pattern
+---@return boolean matches
+function match.is_not.Matches(pattern, init, plain) end
+match.is_not.matches = match.is_not.Matches
+match.is_not_matches = match.is_not.Matches
+match.is_not.match = match.is_not.Matches
+match.is_not_match = match.is_not.Matches
+
+--#endregion
+
+return match
diff --git a/meta/3rd/luassert/library/luassert/mock.lua b/meta/3rd/luassert/library/luassert/mock.lua
new file mode 100644
index 00000000..856bce4e
--- /dev/null
+++ b/meta/3rd/luassert/library/luassert/mock.lua
@@ -0,0 +1,28 @@
+---@meta
+
+---@alias luassert.mockeds table<string, luassert.mockeds | luassert.spy>
+
+---A mock wraps an entire table's functions in spies or mocks
+---@class luassert.mock : luassert.spy.factory
+local mock = {}
+---@generic T
+---Create a new mock from a table, wrapping all of it's functions in spies or mocks.
+---@param object T The table to wrap
+---@param doStubs? boolean If the table should be wrapped with stubs instead of spies
+---@param func? function Callback function used for stubs
+---@param self? table Table to replace with a spy
+---@param key? string The key of the method to replace in `self`
+---@return luassert.mockeds
+function mock(object, doStubs, func, self, key) end
+
+---@generic T
+---Create a new mock from a table, wrapping all of it's functions in spies or mocks.
+---@param object T The table to wrap
+---@param doStubs? boolean If the table should be wrapped with stubs instead of spies
+---@param func? function Callback function used for stubs
+---@param self? table Table to replace with a spy
+---@param key? string The key of the method to replace in `self`
+---@return luassert.mockeds
+function mock.new(object, doStubs, func, self, key) end
+
+return mock
diff --git a/meta/3rd/luassert/library/luassert/spy.d.lua b/meta/3rd/luassert/library/luassert/spy.d.lua
new file mode 100644
index 00000000..2789c93e
--- /dev/null
+++ b/meta/3rd/luassert/library/luassert/spy.d.lua
@@ -0,0 +1,100 @@
+---@meta
+--[[ Instance ]]
+
+--#region
+
+---An instance of a spy.
+---@class luassert.spy
+local spy = {}
+
+---Revert the spied on function to its state before being spied on.
+---
+---Effectively removes spy from spied-on function.
+function spy:revert() end
+
+---Clear the call history for this spy.
+function spy:clear() end
+
+---Check how many times this spy has been called.
+---@param times integer The expected number of calls
+---@param compare? fun(callCount, expected): any A compare function, whose result will be returned as the first return value
+---@return any result By default, `true` if the spy was called `times` times. Will be the result of `compare` if given
+---@return integer calls Number of times called
+function spy:called(times, compare) end
+
+---Check that the spy was called with the provided arguments.
+---@param args any[] An array of arguments that are expected to have been passed to this spy
+---@return boolean was If this spy was called with the provided arguments
+---@return any[] arguments If `was == false`, this will be an array of the arguments *last* given to this spy. If `was == true`, this will be an array of the arguments given to the matching call of this spy.
+function spy:called_with(args) end
+
+---Check that the spy returned the provided values
+---@pasram ... any An array of values that are expected to have been returned by this spy
+---@return boolean did If this spy did return the provided values.
+---@return any[] returns If `did == false`, this will be an array of the values *last* returned by this spy. If `did == true`, this will be an array of the values returned by the matching call of this spy.
+function spy:returned_with(...) end
+
+--#endregion
+
+--[[ Spy Assertion ]]
+
+--#region
+
+---The result of asserting a spy.
+---
+---Includes functions for performing assertions on a spy.
+---@class luassert.spy.assert
+local spy_assert = {}
+
+---Assert that the function being spied on was called.
+---@param times integer Assert the number of times the function was called
+function spy_assert.called(times) end
+
+---Assert that the function being spied on was called with the provided
+---parameters.
+---@param ... any The parameters that the function is expected to have been called with
+function spy_assert.called_with(...) end
+
+---Assert that the function being spied on was **NOT** called with the provided
+---parameters.
+---@param ... any The parameters that the function is expected to **NOT** have been called with
+function spy_assert.not_called_with(...) end
+
+---Assert that the function being spied on was called at **least** a specified
+---number of times.
+---@param times integer The minimum number of times that the spied-on function should have been called
+function spy_assert.called_at_least(times) end
+
+---Assert that the function being spied on was called at **most** a specified
+---number of times.
+---@param times integer The maximum number of times that the spied-on function should have been called
+function spy_assert.called_at_most(times) end
+
+---Assert that the function being spied on was called **more** than the
+---specified number of times.
+---@param times integer The number of times that the spied-on function should have been called more than
+function spy_assert.called_more_than(times) end
+
+---Assert that the function being spied on was called **less** than the
+---specified number of times.
+---@param times integer The number of times that the spied-on function should have been called less than
+function spy_assert.called_less_than(times) end
+
+---Check that the spy returned the provided values
+---@param ... any An array of values that are expected to have been returned by this spy
+---@return boolean did If this spy did return the provided values.
+---@return any[] returns If `did == false`, this will be an array of the values *last* returned by this spy. If `did == true`, this will be an array of the values returned by the matching call of this spy.
+function spy_assert.returned_with(...) end
+
+spy_assert.was = {
+ called = spy_assert.called,
+ called_with = spy_assert.called_with,
+ not_called_with = spy_assert.not_called_with,
+ called_at_least = spy_assert.called_at_least,
+ called_at_most = spy_assert.called_at_most,
+ called_more_than = spy_assert.called_more_than,
+ called_less_than = spy_assert.called_less_than,
+ returned_with = spy_assert.returned_with,
+}
+
+--#endregion
diff --git a/meta/3rd/luassert/library/luassert/spy.lua b/meta/3rd/luassert/library/luassert/spy.lua
new file mode 100644
index 00000000..4d1a7944
--- /dev/null
+++ b/meta/3rd/luassert/library/luassert/spy.lua
@@ -0,0 +1,81 @@
+---@meta
+
+---Spies allow you to wrap a function in order to track how that function was
+---called.
+---@class luassert.spy.factory
+---## Example
+---```
+---describe("New Spy", function()
+--- it("Registers a new function to spy on", function()
+--- local s = spy.new(function() end)
+---
+--- s(1, 2, 3)
+--- s(4, 5, 6)
+---
+--- assert.spy(s).was.called()
+--- assert.spy(s).was.called(2)
+--- assert.spy(s).was.called_with(1, 2, 3)
+--- end)
+---```
+---@overload fun(target:function):luassert.spy
+local spy_factory = {}
+
+--#region
+
+---Register a new function to spy on.
+---@param target function The function to spy on
+---@return luassert.spy spy A spy object that can be used to perform assertions
+---
+---## Example
+---```
+---describe("New Spy", function()
+--- it("Registers a new function to spy on", function()
+--- local s = spy.new(function() end)
+---
+--- s(1, 2, 3)
+--- s(4, 5, 6)
+---
+--- assert.spy(s).was.called()
+--- assert.spy(s).was.called(2)
+--- assert.spy(s).was.called_with(1, 2, 3)
+--- end)
+---```
+function spy_factory.new(target) end
+
+---Create a new spy that replaces a method in a table in place.
+---@param table table The table that the method is a part of
+---@param methodName string The method to spy on
+---@return luassert.spy spy A spy object that can be used to perform assertions
+---
+---## Example
+---```
+---describe("Spy On", function()
+--- it("Replaces a method in a table", function()
+--- local t = {
+--- greet = function(msg) print(msg) end
+--- }
+---
+--- local s = spy.on(t, "greet")
+---
+--- t.greet("Hey!") -- prints 'Hey!'
+--- assert.spy(t.greet).was_called_with("Hey!")
+---
+--- t.greet:clear() -- clears the call history
+--- assert.spy(s).was_not_called_with("Hey!")
+---
+--- t.greet:revert() -- reverts the stub
+--- t.greet("Hello!") -- prints 'Hello!', will not pass through the spy
+--- assert.spy(s).was_not_called_with("Hello!")
+--- end)
+---end)
+---```
+function spy_factory.on(table, methodName) end
+
+---Check that the provided object is a spy.
+---@param object any The object to confirm is a spy
+---@return boolean isSpy If the object is a spy or not
+function spy_factory.is_spy(object) end
+
+--#endregion
+
+return spy_factory
diff --git a/meta/3rd/luassert/library/luassert/stub.lua b/meta/3rd/luassert/library/luassert/stub.lua
new file mode 100644
index 00000000..6332d3ed
--- /dev/null
+++ b/meta/3rd/luassert/library/luassert/stub.lua
@@ -0,0 +1,50 @@
+---@meta
+
+---Function similarly to spies, except that stubs do not call the function that they replace.
+---@class luassert.stub
+local stub = {}
+
+---Creates a new stub that replaces a method in a table in place.
+---@param object table The object that the method is in
+---@param key string The key of the method in the `object` to replace
+---@param ... any A function that operates on the remaining passed in values and returns more values or just values to return
+---@return luassert.spy stub A stub object that can be used to perform assertions
+---@return any ... Values returned by a passed in function or just the values passed in
+function stub(object, key, ...) end
+
+---Creates a new stub that replaces a method in a table in place.
+---@param object table The object that the method is in
+---@param key string The key of the method in the `object` to replace
+---@param ... any A function that operates on the remaining passed in values and returns more values or just values to return
+---@return luassert.spy stub A stub object that can be used to perform assertions
+---@return any ... Values returned by a passed in function or just the values passed in
+---
+---## Example
+---```
+---describe("Stubs", function()
+--- local t = {
+--- lottery = function(...)
+--- print("Your numbers: " .. table.concat({ ... }, ","))
+--- end,
+--- }
+---
+--- it("Tests stubs", function()
+--- local myStub = stub.new(t, "lottery")
+---
+--- t.lottery(1, 2, 3) -- does not print
+--- t.lottery(4, 5, 6) -- does not print
+---
+--- assert.stub(myStub).called_with(1, 2, 3)
+--- assert.stub(myStub).called_with(4, 5, 6)
+--- assert.stub(myStub).called(2)
+--- assert.stub(myStub).called_less_than(3)
+---
+--- myStub:revert()
+---
+--- t.lottery(10, 11, 12) -- prints
+--- end)
+---end)
+---```
+function stub.new(object, key, ...) end
+
+return stub