diff options
-rw-r--r-- | meta/3rd/busted/config.lua | 12 | ||||
-rw-r--r-- | meta/3rd/busted/library/busted.lua | 298 | ||||
-rw-r--r-- | meta/3rd/luassert/config.lua | 1 | ||||
-rw-r--r-- | meta/3rd/luassert/library/luassert.lua | 442 | ||||
-rw-r--r-- | meta/3rd/luassert/library/luassert/array.lua | 16 | ||||
-rw-r--r-- | meta/3rd/luassert/library/luassert/match.lua | 416 | ||||
-rw-r--r-- | meta/3rd/luassert/library/luassert/mock.lua | 28 | ||||
-rw-r--r-- | meta/3rd/luassert/library/luassert/spy.d.lua | 100 | ||||
-rw-r--r-- | meta/3rd/luassert/library/luassert/spy.lua | 81 | ||||
-rw-r--r-- | meta/3rd/luassert/library/luassert/stub.lua | 50 |
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 |