pax_global_header00006660000000000000000000000064135054576110014521gustar00rootroot0000000000000052 comment=c1c8d66e7fc6068eee70a6ed55fd74d7a9174202 luassert-1.8.0/000077500000000000000000000000001350545761100133715ustar00rootroot00000000000000luassert-1.8.0/.busted000066400000000000000000000000771350545761100146640ustar00rootroot00000000000000return { default = { helper = "./spec/helper.lua" }, } luassert-1.8.0/.gitignore000066400000000000000000000000061350545761100153550ustar00rootroot00000000000000*.swp luassert-1.8.0/.travis.yml000066400000000000000000000010041350545761100154750ustar00rootroot00000000000000language: c env: global: - LUAROCKS=2.3.0 matrix: - LUA=lua5.1 - LUA=lua5.2 - LUA=lua5.3 - LUA=luajit - LUA=luajit2.0 - LUA=luajit2.1 before_install: - source .travis/setenv_lua.sh install: - luarocks make - luarocks install busted script: busted spec branches: only: - master notifications: webhooks: - http://hollow-mountain-1250.herokuapp.com/hubot/travis recipients: - engineers@olivinelabs.com email: on_success: always on_failure: always luassert-1.8.0/.travis/000077500000000000000000000000001350545761100147575ustar00rootroot00000000000000luassert-1.8.0/.travis/platform.sh000066400000000000000000000003711350545761100171400ustar00rootroot00000000000000if [ -z "${PLATFORM:-}" ]; then PLATFORM=$TRAVIS_OS_NAME; fi if [ "$PLATFORM" == "osx" ]; then PLATFORM="macosx"; fi if [ -z "$PLATFORM" ]; then if [ "$(uname)" == "Linux" ]; then PLATFORM="linux"; else PLATFORM="macosx"; fi; fi luassert-1.8.0/.travis/setenv_lua.sh000066400000000000000000000002231350545761100174550ustar00rootroot00000000000000export PATH=${PATH}:$HOME/.lua:$HOME/.local/bin:${TRAVIS_BUILD_DIR}/install/luarocks/bin bash .travis/setup_lua.sh eval `$HOME/.lua/luarocks path` luassert-1.8.0/.travis/setup_lua.sh000066400000000000000000000056671350545761100173320ustar00rootroot00000000000000#! /bin/bash # A script for setting up environment for travis-ci testing. # Sets up Lua and Luarocks. # LUA must be "lua5.1", "lua5.2", "lua5.3" or "luajit". # luajit2.0 - master v2.0 # luajit2.1 - master v2.1 set -eufo pipefail LUAJIT_VERSION="2.0.4" LUAJIT_BASE="LuaJIT-$LUAJIT_VERSION" source .travis/platform.sh LUA_HOME_DIR=$TRAVIS_BUILD_DIR/install/lua LR_HOME_DIR=$TRAVIS_BUILD_DIR/install/luarocks mkdir $HOME/.lua LUAJIT="no" if [ "$PLATFORM" == "macosx" ]; then if [ "$LUA" == "luajit" ]; then LUAJIT="yes"; fi if [ "$LUA" == "luajit2.0" ]; then LUAJIT="yes"; fi if [ "$LUA" == "luajit2.1" ]; then LUAJIT="yes"; fi; elif [ "$(expr substr $LUA 1 6)" == "luajit" ]; then LUAJIT="yes"; fi mkdir -p "$LUA_HOME_DIR" if [ "$LUAJIT" == "yes" ]; then if [ "$LUA" == "luajit" ]; then curl --location https://github.com/LuaJIT/LuaJIT/archive/v$LUAJIT_VERSION.tar.gz | tar xz; else git clone https://github.com/LuaJIT/LuaJIT.git $LUAJIT_BASE; fi cd $LUAJIT_BASE if [ "$LUA" == "luajit2.1" ]; then git checkout v2.1; # force the INSTALL_TNAME to be luajit perl -i -pe 's/INSTALL_TNAME=.+/INSTALL_TNAME= luajit/' Makefile fi make && make install PREFIX="$LUA_HOME_DIR" ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/luajit ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/lua; else if [ "$LUA" == "lua5.1" ]; then curl http://www.lua.org/ftp/lua-5.1.5.tar.gz | tar xz cd lua-5.1.5; elif [ "$LUA" == "lua5.2" ]; then curl http://www.lua.org/ftp/lua-5.2.4.tar.gz | tar xz cd lua-5.2.4; elif [ "$LUA" == "lua5.3" ]; then curl http://www.lua.org/ftp/lua-5.3.2.tar.gz | tar xz cd lua-5.3.2; fi # Build Lua without backwards compatibility for testing perl -i -pe 's/-DLUA_COMPAT_(ALL|5_2)//' src/Makefile make $PLATFORM make INSTALL_TOP="$LUA_HOME_DIR" install; ln -s $LUA_HOME_DIR/bin/lua $HOME/.lua/lua ln -s $LUA_HOME_DIR/bin/luac $HOME/.lua/luac; fi cd $TRAVIS_BUILD_DIR lua -v LUAROCKS_BASE=luarocks-$LUAROCKS curl --location http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz | tar xz cd $LUAROCKS_BASE if [ "$LUA" == "luajit" ]; then ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.0" --prefix="$LR_HOME_DIR"; elif [ "$LUA" == "luajit2.0" ]; then ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.0" --prefix="$LR_HOME_DIR"; elif [ "$LUA" == "luajit2.1" ]; then ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.1" --prefix="$LR_HOME_DIR"; else ./configure --with-lua="$LUA_HOME_DIR" --prefix="$LR_HOME_DIR" fi make build && make install ln -s $LR_HOME_DIR/bin/luarocks $HOME/.lua/luarocks cd $TRAVIS_BUILD_DIR luarocks --version rm -rf $LUAROCKS_BASE if [ "$LUAJIT" == "yes" ]; then rm -rf $LUAJIT_BASE; elif [ "$LUA" == "lua5.1" ]; then rm -rf lua-5.1.5; elif [ "$LUA" == "lua5.2" ]; then rm -rf lua-5.2.4; elif [ "$LUA" == "lua5.3" ]; then rm -rf lua-5.3.2; fi luassert-1.8.0/CONTRIBUTING.md000066400000000000000000000031431350545761100156230ustar00rootroot00000000000000Contributing to Luassert ======================== So you want to contribute to luassert? Fantastic! Here's a brief overview on how best to do so. ## What to change Here's some examples of things you might want to make a pull request for: * New language translations * New features * Bugfixes * Inefficient blocks of code If you have a more deeply-rooted problem with how the program is built or some of the stylistic decisions made in the code, it's best to [create an issue](https://github.com/Olivine-Labs/luassert/issues) before putting the effort into a pull request. The same goes for new features - it might be best to check the project's direction, existing pull requests, and currently open and closed issues first. ## Style * Two spaces, not tabs * Variables have_underscores, classes are Uppercase * Wrap everything in `local`, expose blocks of code using the module pattern Look at existing code to get a good feel for the patterns we use. ## Using Git appropriately 1. [Fork the repository](https://help.github.com/articles/fork-a-repo) to your Github account. 2. Create a *topical branch* - a branch whose name is succinct and explains what you're doing, such as "klingon-translations" 3. Make your changes, committing at logical breaks. 4. Push your branch to your personal account 5. [Create a pull request](https://help.github.com/articles/using-pull-requests) 6. Watch for comments or acceptance Please note - if you want to change multiple things that don't depend on each other, make sure you check the master branch back out before making more changes - that way we can take in each change separately. luassert-1.8.0/LICENSE000066400000000000000000000021271350545761100144000ustar00rootroot00000000000000MIT License Terms ================= Copyright (c) 2012 Olivine Labs, LLC. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. luassert-1.8.0/README.md000066400000000000000000000230671350545761100146600ustar00rootroot00000000000000Luassert ======== [![Build Status](https://secure.travis-ci.org/Olivine-Labs/luassert.png)](http://secure.travis-ci.org/Olivine-Labs/luassert) luassert extends Lua's built-in assertions to provide additional tests and the ability to create your own. You can modify chains of assertions with `not`. Check out [busted](http://www.olivinelabs.com/busted#asserts) for extended examples. ```lua assert = require("luassert") assert.True(true) assert.is.True(true) assert.is_true(true) assert.is_not.True(false) assert.is.Not.True(false) assert.is_not_true(false) assert.are.equal(1, 1) assert.has.errors(function() error("this should fail") end) ``` Extend your own: ```lua local assert = require("luassert") local say = require("say") --our i18n lib, installed through luarocks, included as a luassert dependency 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" }) ``` When writing your own assertions you can also use modifiers to set specific objects to work against. An example is the [`array` modifier](https://github.com/Olivine-Labs/luassert/blob/master/src/array.lua) with its accompanying `holes` assertion. Which can be used as; ```lua local arr = { "one", "two", "three" } assert.array(arr).has.no.holes() -- checks the array to not contain holes --> passes assert.array(arr).has.no.holes(4) -- sets explicit length to 4 --> fails ``` ## Implementation notes: * assertion/modifiers that are Lua keywords (`true`, `false`, `nil`, `function`, and `not`) cannot be used using '.' chaining because that results in compilation errors. Instead chain using '_' (underscore) or use one or more capitals in the reserved word (see code examples above), whatever your coding style prefers * Most assertions will only take 1 or 2 parameters and an optional failure message, except for the `returned_arguments` assertion, which does not take a failure message * To specify a custom failure message for the `returned_arguments` assertion, use the `message` modifier ```lua local f = function() end assert.message("the function 'f' did not return 2 arguments").returned_arguments(2, f()) ``` ## Matchers Argument matching can be performed on spies/stubs with the ability to create your own. This provides flexible argument matching for `called_with` and `returned_with` assertions. Like assertions, you can modify chains of matchers with `not`. Furthermore, matchers can be combined using composite matchers. ```lua local assert = require 'luassert' local match = require 'luassert.match' local spy = require 'luassert.spy' local s = spy.new(function() end) s('foo') s(1) s({}, 'foo') assert.spy(s).was.called_with(match._) -- arg1 is anything assert.spy(s).was.called_with(match.is_string()) -- arg1 is a string assert.spy(s).was.called_with(match.is_number()) -- arg1 is a number assert.spy(s).was.called_with(match.is_not_true()) -- arg1 is not true assert.spy(s).was.called_with(match.is_table(), match.is_string()) -- arg1 is a table, arg2 is a string assert.spy(s).was.called_with(match.has_match('.oo')) -- arg1 contains pattern ".oo" assert.spy(s).was.called_with({}, 'foo') -- you can still match without using matchers ``` Extend your own: ```lua local function is_even(state, arguments) return function(value) return (value % 2) == 0 end end local function is_gt(state, arguments) local expected = arguments[1] return function(value) return value > expected end end assert:register("matcher", "even", is_even) assert:register("matcher", "gt", is_gt) ``` ```lua local assert = require 'luassert' local match = require 'luassert.match' local spy = require 'luassert.spy' local s = spy.new(function() end) s(7) assert.spy(s).was.called_with(match.is_number()) -- arg1 was a number assert.spy(s).was.called_with(match.is_not_even()) -- arg1 was not even assert.spy(s).was.called_with(match.is_gt(5)) -- arg1 was greater than 5 ``` Composite matchers have the form: ```lua match.all_of(m1, m2, ...) -- argument matches all of the matchers m1 to mn match.any_of(m1, m2, ...) -- argument matches at least one of the matchers m1 to mn match.none_of(m1, m2, ...) -- argument does not match any of the matchers m1 to mn ``` If you're creating a spy for methods that mutate any properties on `self` you should should use `match.is_ref(obj)`: ```lua local t = { cnt = 0, } function t:incrby(i) self.cnt = self.cnt + i end local s = spy.on(t, "incrby") t:incrby(2) assert.spy(s).was_called_with(match.is_ref(t), 2) ``` ## Snapshots To be able to revert changes created by tests, inserting spies and stubs for example, luassert supports 'snapshots'. A snapshot includes the following; 1. spies and stubs 1. parameters 1. formatters Example: ```lua describe("Showing use of snapshots", function() local snapshot before_each(function() snapshot = assert:snapshot() end) after_each(function() snapshot:revert() end) it("does some test", function() -- spies or stubs registered here, parameters changed, or formatters added -- will be undone in the after_each() handler. end) end) ``` ## Parameters 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. 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")) ``` ## Customizing argument formatting luassert comes preloaded with argument formatters for common Lua types, but it is easy to roll your own. Customizing them is especially useful for limiting table depth and for userdata types. ### Configuring table depth display The default table formatter allows you to customize the levels displayed by setting the `TableFormatLevel` parameter (setting it to -1 displays all levels). Example: ```lua describe("Tests different levels of table display", function() local testtable = { hello = "hola", world = "mundo", liqour = { "beer", "wine", "water" }, fruit = { native = { "apple", "strawberry", "grape" }, tropical = { "banana", "orange", "mango" }, }, } it("tests display of 0 levels", function() assert:set_parameter("TableFormatLevel", 0) assert.are.same(testtable, {}) end) it("tests display of 2 levels", function() assert:set_parameter("TableFormatLevel", 2) assert.are.same(testtable, {}) end) end) ``` Will display the following output with the table pretty-printed to the requested depth: ``` Failure: ...ua projects\busted\formatter\spec\formatter_spec.lua @ 45 tests display of 0 levels ...ua projects\busted\formatter\spec\formatter_spec.lua:47: Expected objects to be the same. Passed in: (table): { } Expected: (table): { ... more } Failure: ...ua projects\busted\formatter\spec\formatter_spec.lua @ 50 tests display of 2 levels ...ua projects\busted\formatter\spec\formatter_spec.lua:52: Expected objects to be the same. Passed in: (table): { } Expected: (table): { [hello] = 'hola' [fruit] = { [tropical] = { ... more } [native] = { ... more } } [liqour] = { [1] = 'beer' [2] = 'wine' [3] = 'water' } [world] = 'mundo' } ``` ### 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 ``` luassert-1.8.0/luassert-1.8.0-0.rockspec000066400000000000000000000035631350545761100175740ustar00rootroot00000000000000package = "luassert" version = "1.8.0-0" source = { url = "https://github.com/Olivine-Labs/luassert/archive/v1.8.0.tar.gz", dir = "luassert-1.8.0" } description = { summary = "Lua Assertions Extension", detailed = [[ Adds a framework that allows registering new assertions without compromising builtin assertion functionality. ]], homepage = "http://olivinelabs.com/busted/", license = "MIT " } dependencies = { "lua >= 5.1", "say >= 1.2-1" } build = { type = "builtin", modules = { ["luassert.compatibility"] = "src/compatibility.lua", ["luassert.state"] = "src/state.lua", ["luassert.util"] = "src/util.lua", ["luassert.spy"] = "src/spy.lua", ["luassert.stub"] = "src/stub.lua", ["luassert.assert"] = "src/assert.lua", ["luassert.modifiers"] = "src/modifiers.lua", ["luassert.assertions"] = "src/assertions.lua", ["luassert.array"] = "src/array.lua", ["luassert.namespaces"] = "src/namespaces.lua", ["luassert.match"] = "src/match.lua", ["luassert.mock"] = "src/mock.lua", ["luassert.init"] = "src/init.lua", ["luassert.matchers.init"] = "src/matchers/init.lua", ["luassert.matchers.core"] = "src/matchers/core.lua", ["luassert.matchers.composite"] = "src/matchers/composite.lua", ["luassert.formatters.init"] = "src/formatters/init.lua", ["luassert.formatters.binarystring"] = "src/formatters/binarystring.lua", ["luassert.languages.en"] = "src/languages/en.lua", ["luassert.languages.ar"] = "src/languages/ar.lua", ["luassert.languages.fr"] = "src/languages/fr.lua", ["luassert.languages.nl"] = "src/languages/nl.lua", ["luassert.languages.ru"] = "src/languages/ru.lua", ["luassert.languages.ua"] = "src/languages/ua.lua", ["luassert.languages.zh"] = "src/languages/zh.lua", ["luassert.languages.ja"] = "src/languages/ja.lua", } } luassert-1.8.0/spec/000077500000000000000000000000001350545761100143235ustar00rootroot00000000000000luassert-1.8.0/spec/assertions_spec.lua000066400000000000000000000521131350545761100202340ustar00rootroot00000000000000local tablex = require 'pl.tablex' describe("Test Assertions", function() it("Tests backward compatible assert() functionality", function() local test = true local message = "the message" local third_arg = "three" local fourth_arg = "four" one, two, three, four, five = assert(test, message, third_arg, fourth_arg) assert(one == test and two == message and three == third_arg and four == fourth_arg and five == nil, "Expected input values to be outputted as well when an assertion does not fail") end) it("Checks assert() handles more than two return values", function() local res, err = pcall(assert, false, "some error", "a string") assert(not res) err = tostring(err) assert(not err:match("attempt to perform arithmetic on a string value", nil, true)) assert(err:match("some error", nil, true)) end) it("Checks level and get_level values", function() assert.equal(3, assert:get_level(assert:level(3))) assert.is.Nil(assert:get_level({})) assert.is.Nil(assert:get_level("hello world")) assert.is.Nil(assert:get_level(nil)) end) it("Checks asserts can be reused", function() local is_same = assert.is_same local orig_same = tablex.deepcopy(is_same) is_same({}, {}) assert.is_same(orig_same, is_same) end) it("Checks to see if tables 1 and 2 are the same", function() local table1 = { derp = false} local table2 = { derp = false} assert.same(table1, table2) if type(jit) == "table" then loadstring([[ local assert = require 'luassert' assert.same(0ULL, 0) assert.same(0, 0ULL) assert.same({0ULL}, {0}) assert.same({0}, {0ULL}) ]])() end end) it("Checks to see if tables 1 and 2 are not the same", function() local table1 = { derp = false} local table2 = { derp = true} assert.is_not.same(table1, table2) end) it("Checks the same() assertion for tables with protected metatables", function() local troubleSomeTable = {} setmetatable(troubleSomeTable, {__metatable = 0}) assert.are.same(troubleSomeTable, troubleSomeTable) end) it("Checks same() assertion to handle nils properly", function() assert.is.error(function() assert.same(nil) end) -- minimum 2 arguments assert.same(nil, nil) assert.is_not.same("a string", nil) assert.is_not.same(nil, "a string") end) it("Checks same() assertion ignores __pairs metamethod", function() local t1 = setmetatable({1,2,3}, {__pairs = function(t) return nil end}) local t2 = {1,2,3} assert.same(t1, t2) assert.same(t2, t1) end) it("Checks same() assertion to handle recursive tables", function() local t1 = { k1 = 1, k2 = 2 } local t2 = { k1 = 1, k2 = 2 } local t3 = { k1 = 1, k2 = 2, k3 = { k1 = 1, k2 = 2, k3 = t2 } } t1.k3 = t1 t2.k3 = t2 assert.same(t1, t2) assert.same(t1, t3) assert.same(t1, t3) end) it("Checks same() assertion to handle recursive tables that don't match", function() local t1 = {} local t2 = {} local a = {} local b = {} local c = {} local d = {} t1.k1 = a t2.k1 = b a.k1 = c b.k1 = d c.k2 = a d.k2 = d assert.is_table(t1.k1.k1.k2.k1) assert.is_nil(t2.k1.k1.k2.k1) assert.are_not_same(t1, t2) end) it("Checks same() assertion to handle recursive tables that don't match - deeper recursion", function() local cycle_root = {} local cycle_1 = {} local cycle_2 = {} cycle_root.k1 = cycle_1 cycle_1.k2 = cycle_2 cycle_2.k2 = cycle_root local mimic_root = {} local mimic_1 = {} local mimic_2 = {} local mimic_3 = {} local self_ref = {} mimic_root.k1 = mimic_1 mimic_1.k2 = mimic_2 mimic_2.k2 = mimic_3 mimic_3.k1 = self_ref self_ref.k2 = self_ref assert.is_table(cycle_root.k1.k2.k2.k1.k2.k2.k1) assert.is_nil(mimic_root.k1.k2.k2.k1.k2.k2.k1) assert.are_not_same(cycle_root, mimic_root) end) it("Checks same() assertion to handle recursive tables that don't match - multiple recursions", function() local c1, c2, c3, c4 = {}, {}, {}, {} local m1, m2, m3, m4, m5, m6, m7, m8, m9 = {}, {}, {}, {}, {}, {}, {}, {}, {} local r1, r2, r3 = {}, {}, {} r1[1] = r3 r2[1] = r2 r3[1] = r3 c2[1] = r2 c3[1] = r2 c4[1] = r2 m2[1] = r3 m3[1] = r3 m4[1] = r3 m6[1] = r3 m7[1] = r3 m8[1] = r3 c1[2] = c2 c2[3] = c3 c3[3] = c4 c4[3] = c1 m1[2] = m2 m2[3] = m3 m3[3] = m4 m4[3] = m5 m5[2] = m6 m6[3] = m7 m7[3] = m8 m8[3] = m9 m9[2] = r1 r1[3] = r1 assert.is_table(c1[2][3][3][3][2][3][3][3][2][3][3][3][2]) assert.is_nil(m1[2][3][3][3][2][3][3][3][2][3][3][3][2]) assert.are_not_same(c1, m1) end) it("Checks to see if tables 1 and 2 are equal", function() local table1 = { derp = false} local table2 = table1 assert.equals(table1, table2) end) it("Checks equals() assertion to handle nils properly", function() assert.is.error(function() assert.equals(nil) end) -- minimum 2 arguments assert.equals(nil, nil) assert.is_not.equals("a string", nil) assert.is_not.equals(nil, "a string") end) 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) 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) 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) it("Ensures the is operator doesn't change the behavior of equals", function() assert.is.equals(true, true) end) it("Ensures the is_not operator does change the behavior of equals", function() assert.is_not.equals(true, false) end) it("Ensures that error only throws an error when the first argument function does not throw an error", function() local test_function = function() error("test") end assert.has.error(test_function) assert.has.error(test_function, "test") assert.has_no.errors(test_function, "derp") end) it("Checks to see if var is truthy", function() assert.is_not.truthy(nil) assert.is.truthy(true) assert.is.truthy({}) assert.is.truthy(function() end) assert.is.truthy("") assert.is_not.truthy(false) assert.error(function() assert.truthy(false) end) end) it("Checks to see if var is falsy", function() assert.is.falsy(nil) assert.is_not.falsy(true) assert.is_not.falsy({}) assert.is_not.falsy(function() end) assert.is_not.falsy("") assert.is.falsy(false) end) it("Ensures the Not operator does change the behavior of equals", function() assert.is.Not.equal(true, false) end) it("Checks true() assertion", function() assert.is.True(true) assert.is.Not.True(123) assert.is.Not.True(nil) assert.is.Not.True("abc") assert.is.Not.True(false) assert.is.Not.True(function() end) end) it("Checks false() assertion", function() assert.is.False(false) assert.is.Not.False(123) assert.is.Not.False(nil) assert.is.Not.False("abc") assert.is.Not.False(true) assert.is.Not.False(function() end) end) it("Checks boolean() assertion", function() assert.is.boolean(false) assert.is.boolean(true) assert.is.Not.boolean(123) assert.is.Not.boolean(nil) assert.is.Not.boolean("abc") assert.is.Not.boolean(function() end) end) it("Checks number() assertion", function() assert.is.number(123) assert.is.number(-0.345) assert.is.Not.number(nil) assert.is.Not.number("abc") assert.is.Not.number(true) assert.is.Not.number(function() end) end) it("Checks string() assertion", function() assert.is.string("abc") assert.is.Not.string(123) assert.is.Not.string(nil) assert.is.Not.string(true) assert.is.Not.string(function() end) end) it("Checks table() assertion", function() assert.is.table({}) assert.is.Not.table("abc") assert.is.Not.table(123) assert.is.Not.table(nil) assert.is.Not.table(true) assert.is.Not.table(function() end) end) it("Checks nil() assertion", function() assert.is.Nil(nil) assert.is.Not.Nil(123) assert.is.Not.Nil("abc") assert.is.Not.Nil(true) assert.is.Not.Nil(function() end) end) it("Checks function() assertion", function() assert.is.Function(function() end) assert.is.Not.Function(nil) assert.is.Not.Function(123) assert.is.Not.Function("abc") assert.is.Not.Function(true) end) it("Checks userdata() assertion", function() local myfile = io.tmpfile() assert.is.userdata(myfile) myfile:close() assert.is.Not.userdata(nil) assert.is.Not.userdata(123) assert.is.Not.userdata("abc") assert.is.Not.userdata(true) assert.is.Not.userdata(function() end) end) it("Checks thread() assertion", function() local mythread = coroutine.create(function() end) assert.is.thread(mythread) assert.is.Not.thread(nil) assert.is.Not.thread(123) assert.is.Not.thread("abc") assert.is.Not.thread(true) assert.is.Not.thread(function() end) end) it("Checks '_' chaining of modifiers and assertions", function() assert.is_string("abc") assert.is_true(true) assert.is_not_string(123) assert.is_nil(nil) assert.is_not_nil({}) assert.is_not_true(false) assert.is_not_false(true) -- verify that failing assertions actually fail assert.has_error(function() assert.is_string(1) end) assert.has_error(function() assert.is_true(false) end) assert.has_error(function() assert.is_not_string('string!') end) assert.has_error(function() assert.is_nil({}) end) assert.has_error(function() assert.is_not_nil(nil) end) assert.has_error(function() assert.is_not_true(true) end) assert.has_error(function() assert.is_not_false(false) end) end) it("Checks '.' chaining of modifiers and assertions", function() assert.is.string("abc") assert.is.True(true) assert.is.Not.string(123) assert.is.Nil(nil) assert.is.Not.Nil({}) assert.is.Not.True(false) assert.is.Not.False(true) assert.equals.Not(true, false) assert.equals.Not.Not(true, true) assert.Not.equals.Not(true, true) -- verify that failing assertions actually fail assert.has.error(function() assert.is.string(1) end) assert.has.error(function() assert.is.True(false) end) assert.has.error(function() assert.is.Not.string('string!') end) assert.has.error(function() assert.is.Nil({}) end) assert.has.error(function() assert.is.Not.Nil(nil) end) assert.has.error(function() assert.is.Not.True(true) end) assert.has.error(function() assert.is.Not.False(false) end) assert.has.error(function() assert.equals.Not(true, true) end) assert.has.error(function() assert.equals.Not.Not(true, false) end) assert.has.error(function() assert.Not.equals.Not(true, false) end) end) it("Checks number of returned arguments", function() local fn = function() end local fn1 = function() return "something",2,3 end local fn2 = function() return nil end local fn3 = function() return nil, nil end local fn4 = function() return nil, 1, nil end assert.returned_arguments(0, fn()) assert.not_returned_arguments(2, fn1()) assert.returned_arguments(3, fn1()) assert.returned_arguments(1, fn2()) assert.returned_arguments(2, fn3()) assert.returned_arguments(3, fn4()) end) it("Checks has_error 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.has_error(f_nok) assert.has_no_error(f_ok) assert.has_error(t_nok) assert.has_no_error(t_ok) end) it("Checks has_error compares error strings", function() assert.has_error(function() error() end) assert.has_error(function() error("string") end, "string") end) it("Checks has_error compares error objects", function() local func = function() end assert.has_error(function() error({ "table" }) end, { "table" }) assert.has_error(function() error(func) end, func) assert.has_error(function() error(false) end, false) assert.has_error(function() error(true) end, true) assert.has_error(function() error(0) end, 0) assert.has_error(function() error(1.5) end, 1.5) assert.has_error(function() error(10.0^50) end, 10.0^50) assert.has_error(function() error(10.0^-50) end, 10.0^-50) assert.has_no_error(function() error(true) end, 0) assert.has_no_error(function() error(125) end, 1.5) end) it("Checks has_error compares error objects with strings", function() local mt = { __tostring = function(t) return t[1] end } assert.has_error(function() error(setmetatable({ "table" }, mt)) end, "table") end) it("Checks error_matches to accepts at least 2 arguments", function() assert.has_error(function() assert.error_matches(error) end) assert.has_no_error(function() assert.error_matches(function() error("foo") end, ".*") end) end) 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) it("Checks error_matches compares error strings with pattern", function() assert.error_matches(function() error() end, nil) assert.no_error_matches(function() end, nil) assert.does_error_match(function() error(123) end, "^%d+$") assert.error.matches(function() error("string") end, "^%w+$") assert.matches.error(function() error("string") end, "str", nil, true) assert.matches_error(function() error("123string") end, "^[^0-9]+", 4) assert.has_no_error.match(function() error("123string") end, "123", 4, true) assert.does_not.match_error(function() error("string") end, "^%w+$", nil, true) end) it("Checks error_matches does not compare error objects", function() local func = function() end assert.no_error_matches(function() error({ "table" }) end, "table") end) it("Checks error_matches compares error objects that are convertible to strings", function() local mt = { __tostring = function(t) return t[1] end } assert.error_matches(function() error(setmetatable({ "table" }, mt)) end, "^table$") end) 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) it("Checks unregister removes assertions", function() assert.has_no_error(function() assert.has_property("name", { name = "jack" }) end) assert:unregister("assertion", "has_property") assert.has_error(function() assert.has_property("name", { name = "jack" }) end, "luassert: unknown modifier/assertion: 'has_property'") end) it("Checks asserts return all their arguments on success", function() assert.is_same({true, "string"}, {assert(true, "string")}) assert.is_same({true, "bar"}, {assert.is_true(true, "bar")}) assert.is_same({false, "foobar"}, {assert.is_false(false, "foobar")}) assert.is_same({"", "truthy"}, {assert.is_truthy("", "truthy")}) assert.is_same({nil, "falsy"}, {assert.is_falsy(nil, "falsy")}) assert.is_same({true, "boolean"}, {assert.is_boolean(true, "boolean")}) assert.is_same({false, "still boolean"}, {assert.is_boolean(false, "still boolean")}) assert.is_same({0, "is number"}, {assert.is_number(0, "is number")}) assert.is_same({"string", "is string"}, {assert.is_string("string", "is string")}) assert.is_same({{}, "empty table"}, {assert.is_table({}, "empty table")}) assert.is_same({nil, "string"}, {assert.is_nil(nil, "string")}) assert.is_same({{1, 2, 3}, "unique message"}, {assert.is_unique({1, 2, 3}, "unique message")}) assert.is_same({"foo", "foo", "bar"}, {assert.is_equal("foo", "foo", "bar")}) assert.is_same({"foo", "foo", "string"}, {assert.is_same("foo", "foo", "string")}) assert.is_same({0, 1, 2, "message"}, {assert.is_near(0, 1, 2, "message")}) end) it("Checks assert.has_match returns captures from match on success", function() assert.is_same({"string"}, {assert.has_match("(.*)", "string", "message")}) assert.is_same({"s", "n"}, {assert.has_match("(s).*(n)", "string", "message")}) assert.is_same({"tri"}, {assert.has_match("tri", "string", "message")}) assert.is_same({"ing"}, {assert.has_match("ing", "string", nil, true, "message")}) assert.is_same({}, {assert.has_no_match("%d+", "string", "message")}) assert.is_same({}, {assert.has_no_match("%d+", "string", nil, true, "message")}) end) it("Checks assert.has_error returns thrown error on success", function() assert.is_same({"err message", "err message"}, {assert.has_error(function() error("err message") end, "err message")}) assert.is_same({"err", "err"}, {assert.has_error(function() error(setmetatable({},{__tostring = function() return "err" end})) end, "err")}) assert.is_same({{}, {}}, {assert.has_error(function() error({}) end, {})}) assert.is_same({'0', 0}, {assert.has_error(function() error(0) end, 0)}) assert.is_same({nil, nil}, {assert.has_error(function() error(nil) end, nil)}) assert.is_same({nil, "string"}, {assert.has_no_error(function() end, "string")}) end) it("Checks assert.error_matches returns captures of thrown error on success", function() assert.is_same({"err", "message"}, {assert.error_matches(function() error("err message") end, "(err) (%w+)$")}) assert.is_same({"err"}, {assert.error_matches(function() error(setmetatable({},{__tostring = function() return "err" end})) end, "err", nil, true)}) assert.is_same({}, {assert.error_matches(function() error(nil) end, nil)}) end) it("Checks assert.no_error_matches returns thrown error on success", function() assert.is_same({nil, "string"}, {assert.no_error_matches(function() end, "string")}) assert.is_same({"error", "string"}, {assert.no_error_matches(function() error("error") end, "string")}) end) it("Checks 'array' modifier and 'holes' assertion", function() local arr = { true, true, true } assert.array(arr).has.no.holes() assert.array(arr).has.holes(4) assert.has.error(function() assert.array(arr).has.holes() end) assert.has.error(function() assert.has.holes() end) assert.has.error(function() assert.array(arr).array({}).has.holes() end) end) end) luassert-1.8.0/spec/formatters_spec.lua000066400000000000000000000142241350545761100202310ustar00rootroot00000000000000local function returnnils() -- force the return of nils in an argument array local a,b return a, b, "this is not nil" end describe("Test Formatters", function() setup(function() end) local snapshot before_each(function() snapshot = assert:snapshot() end) after_each(function() snapshot:revert() end) it("Checks to see if types are returned as strings", function() assert.is.same(assert:format({ "a string", ["n"] = 1 })[1], "(string) 'a string'") assert.is.same(assert:format({ true, ["n"] = 1 })[1], "(boolean) true") assert.is.same(assert:format({ 1234, ["n"] = 1 })[1], "(number) 1234") assert.is.same(assert:format({ returnnils(), ["n"] = 3 })[1], "(nil)") local f = function() end local expected = tostring(f) assert.is.same(assert:format({ f, ["n"] = 1 })[1]:sub(1, #expected), expected) end) it("Checks to see if numbers are serialized correctly", function() assert.is.same(assert:format({ 1.0, ["n"] = 1 })[1], "(number) "..tostring(1.0)) assert.is.same(assert:format({ 23456789012E66, ["n"] = 1 })[1], "(number) 2.3456789012000000698e+76") assert.is.same(assert:format({ 0/0, ["n"] = 1 })[1], "(number) NaN") assert.is.same(assert:format({ 1/0, ["n"] = 1 })[1], "(number) Inf") assert.is.same(assert:format({ -1/0, ["n"] = 1 })[1], "(number) -Inf") end) it("Checks to see if tables are recursively serialized", function() local t = {} assert.is.same(assert:format({ t, ["n"] = 1 })[1], "("..tostring(t)..") { }") t = { 2, 3, 4, [-5] = 7} assert.is.same(assert:format({ t, ["n"] = 1 })[1], [[(]]..tostring(t)..[[) { [1] = 2 [2] = 3 [3] = 4 [-5] = 7 }]]) t = { 1, ["k1"] = "v1", ["k2"] = "v2"} assert.is.same(assert:format({ t, ["n"] = 1 })[1], [[(]]..tostring(t)..[[) { [1] = 1 [k1] = 'v1' [k2] = 'v2' }]]) t = { "{\n }\n" } assert.is.same(assert:format({ t, ["n"] = 1 })[1], [[(]]..tostring(t)..[[) { [1] = '{ } ' }]]) end) it("Checks to see if TableFormatLevel parameter limits table formatting depth", function() local t = { { { { 1 } } } } assert.is.same(assert:format({ t, ["n"] = 1 })[1], [[(]]..tostring(t)..[[) { [1] = { [1] = { [1] = { ... more } } } }]]) t = { { { } } } assert.is.same(assert:format({ t, ["n"] = 1 })[1], [[(]]..tostring(t)..[[) { [1] = { [1] = { } } }]]) assert:set_parameter("TableFormatLevel", 0) t = { } assert.is.same(assert:format({ t, ["n"] = 1 })[1], "("..tostring(t)..") { }") t = { 1 } assert.is.same(assert:format({ t, ["n"] = 1 })[1], "("..tostring(t)..") { ... more }") end) it("Checks to see if TableFormatLevel parameter can display all levels", function() assert:set_parameter("TableFormatLevel", -1) local t = { { { { 1 } } } } assert.is.same(assert:format({ t, ["n"] = 1 })[1], [[(]]..tostring(t)..[[) { [1] = { [1] = { [1] = { [1] = 1 } } } }]]) end) it("Checks to see if error character is applied only to key chain marked with crumbs", function() local t = {{1,2},{3,4}} local fmtargs = { {crumbs = {1,2}} } local formatted = assert:format({t, n = 1, fmtargs = fmtargs})[1] local expected = "("..tostring(t)..") {\n [1] = {\n [1] = 1\n [2] = 2 }\n *[2] = {\n *[1] = 3\n [2] = 4 } }" assert.is.equal(expected, formatted) end) it("Checks to see if TableErrorHighlightCharacter changes error character", function() assert:set_parameter("TableErrorHighlightCharacter", "**") local t = {1,2,3} local fmtargs = { {crumbs = {2}} } local formatted = assert:format({t, n = 1, fmtargs = fmtargs})[1] local expected = "("..tostring(t)..") {\n [1] = 1\n**[2] = 2\n [3] = 3 }" assert.is.equal(expected, formatted) end) it("Checks to see if TableErrorHighlightColor changes error color", function() local ok, colors = pcall(require, "term.colors") if not ok then pending("lua term.colors not available") end assert:set_parameter("TableErrorHighlightColor", "red") local t = {1,2,3} local fmtargs = { {crumbs = {2}} } local formatted = assert:format({t, n = 1, fmtargs = fmtargs})[1] local expected = string.format("("..tostring(t)..") {\n [1] = 1\n %s[2] = 2\n [3] = 3 }", colors.red("*")) assert.is.equal(expected, formatted) end) it("Checks to see if self referencing tables can be formatted", function() local t = {1,2} t[3] = t assert:set_parameter("TableFormatShowRecursion", true) local formatted = assert:format({t, n = 1})[1] local expected = "("..tostring(t)..") {\n [1] = 1\n [2] = 2\n [3] = { ... recursive } }" assert.is.equal(expected, formatted) end) it("Checks to see if table with 0 count is returned empty/0-count", function() local t = { ["n"] = 0 } local formatted = assert:format(t) assert.equals(type(formatted), "table") formatted.n = nil assert.equals(next(formatted), nil) end) it("Checks to see if empty table is returned empty", function() local t = {} local formatted = assert:format(t) assert.equals(type(formatted), "table") assert.equals(next(formatted), nil) end) it("Checks to see if table containing nils is returned with same number of entries #test", function() local t = { returnnils(), ["n"] = 3 } formatted = assert:format(t) assert.is.same(type(formatted[1]), "string") assert.is.same(type(formatted[2]), "string") assert.is.same(type(formatted[3]), "string") assert.is.same(type(formatted[4]), "nil") end) it("checks arguments not being formatted if set to do so", function() local arg1 = "argument1" local arg2 = "argument2" local arguments = { arg1, arg2 , ["n"] = 2} arguments.nofmt = { true } -- first arg not to be formatted arguments = assert:format(arguments) assert.is.same(arg1, arguments[1]) end) it("checks extra formatters inserted to be called first", function() local expected = "formatted result" local f = function(value) if type(value) == "string" then return expected end end local s = spy.new(f) assert:add_formatter(s) assert.are_equal(expected, assert:format({"some string"})[1]) assert.spy(s).was.called(1) assert:remove_formatter(s) end) end) luassert-1.8.0/spec/helper.lua000066400000000000000000000014521350545761100163070ustar00rootroot00000000000000-- busted helper file to prevent crashes on LuaJIT ffi module being -- garbage collected due to Busted cleaning up the test enviornment -- -- usage: -- busted --helper=spec/helper.lua -- only apply when we're running LuaJIT local isJit = (tostring(assert):match('builtin') ~= nil) if isJit then -- pre-load the ffi module, such that it becomes part of the environment -- and Busted will not try to GC and reload it. The ffi is not suited -- for that and will occasionally segfault if done so. local ffi = require "ffi" -- Now patch ffi.cdef to only be called once with each definition, as it -- will error on re-registering. local old_cdef = ffi.cdef local exists = {} ffi.cdef = function(def) if exists[def] then return end exists[def] = true return old_cdef(def) end end luassert-1.8.0/spec/matchers_spec.lua000066400000000000000000000352711350545761100176560ustar00rootroot00000000000000local match = require 'luassert.match' assert(type(match) == "table") describe("Test Matchers", function() it("Checks wildcard() matcher", function() assert.is_true(match._(nil)) assert.is_true(match._(true)) assert.is_true(match._(false)) assert.is_true(match._(123)) assert.is_true(match._("")) assert.is_true(match._({})) assert.is_true(match._(function() end)) end) it("Checks truthy() matcher", function() assert.is_false(match.truthy()(nil)) assert.is_true(match.truthy()(true)) assert.is_false(match.truthy()(false)) assert.is_true(match.truthy()(123)) assert.is_true(match.truthy()("")) assert.is_true(match.truthy()({})) assert.is_true(match.truthy()(function() end)) end) it("Checks falsy() matcher", function() assert.is_true(match.falsy()(nil)) assert.is_false(match.falsy()(true)) assert.is_true(match.falsy()(false)) assert.is_false(match.falsy()(123)) assert.is_false(match.falsy()("")) assert.is_false(match.falsy()({})) assert.is_false(match.falsy()(function() end)) end) it("Checks true() matcher", function() assert.is_false(match.is_true()(nil)) assert.is_true(match.is_true()(true)) assert.is_false(match.is_true()(false)) assert.is_false(match.is_true()(123)) assert.is_false(match.is_true()("")) assert.is_false(match.is_true()({})) assert.is_false(match.is_true()(function() end)) end) it("Checks false() matcher", function() assert.is_false(match.is_false()(nil)) assert.is_false(match.is_false()(true)) assert.is_true(match.is_false()(false)) assert.is_false(match.is_false()(123)) assert.is_false(match.is_false()("")) assert.is_false(match.is_false()({})) assert.is_false(match.is_false()(function() end)) end) it("Checks nil() matcher", function() assert.is_true(match.is_nil()(nil)) assert.is_false(match.is_nil()(true)) assert.is_false(match.is_nil()(false)) assert.is_false(match.is_nil()(123)) assert.is_false(match.is_nil()("")) assert.is_false(match.is_nil()({})) assert.is_false(match.is_nil()(function() end)) end) it("Checks boolean() matcher", function() assert.is_false(match.is_boolean()(nil)) assert.is_true(match.is_boolean()(true)) assert.is_true(match.is_boolean()(false)) assert.is_false(match.is_boolean()(123)) assert.is_false(match.is_boolean()("")) assert.is_false(match.is_boolean()({})) assert.is_false(match.is_boolean()(function() end)) end) it("Checks number() matcher", function() assert.is_false(match.is_number()(nil)) assert.is_false(match.is_number()(true)) assert.is_false(match.is_number()(false)) assert.is_true(match.is_number()(123)) assert.is_false(match.is_number()("")) assert.is_false(match.is_number()({})) assert.is_false(match.is_number()(function() end)) end) it("Checks string() matcher", function() assert.is_false(match.is_string()(nil)) assert.is_false(match.is_string()(true)) assert.is_false(match.is_string()(false)) assert.is_false(match.is_string()(123)) assert.is_true(match.is_string()("")) assert.is_false(match.is_string()({})) assert.is_false(match.is_string()(function() end)) end) it("Checks table() matcher", function() assert.is_false(match.is_boolean()(nil)) assert.is_false(match.is_table()(nil)) assert.is_false(match.is_table()(true)) assert.is_false(match.is_table()(false)) assert.is_false(match.is_table()(123)) assert.is_false(match.is_table()("")) assert.is_true(match.is_table()({})) assert.is_false(match.is_table()(function() end)) end) it("Checks function() matcher", function() assert.is_false(match.is_function()(nil)) assert.is_false(match.is_function()(true)) assert.is_false(match.is_function()(false)) assert.is_false(match.is_function()(123)) assert.is_false(match.is_function()("")) assert.is_false(match.is_function()({})) assert.is_true(match.is_function()(function() end)) end) it("Checks userdata() matcher", function() assert.is_true(match.is_userdata()(io.stdout)) assert.is_false(match.is_userdata()(nil)) assert.is_false(match.is_userdata()(true)) assert.is_false(match.is_userdata()(false)) assert.is_false(match.is_userdata()(123)) assert.is_false(match.is_userdata()("")) assert.is_false(match.is_userdata()({})) assert.is_false(match.is_userdata()(function() end)) end) it("Checks thread() matcher", function() local mythread = coroutine.create(function() end) assert.is_true(match.is_thread()(mythread)) assert.is_false(match.is_thread()(nil)) assert.is_false(match.is_thread()(true)) assert.is_false(match.is_thread()(false)) assert.is_false(match.is_thread()(123)) assert.is_false(match.is_thread()("")) assert.is_false(match.is_thread()({})) assert.is_false(match.is_thread()(function() end)) end) it("Checks to see if tables 1 and 2 are equal", function() local table1 = { derp = false} local table2 = table1 assert.is_true(match.is_equal(table1)(table2)) assert.is_true(match.is_equal(table2)(table1)) end) it("Checks equals() matcher to handle nils properly", function() assert.is.error(function() match.is_equals() end) -- minimum 1 argument assert.is_true(match.is_equal(nil)(nil)) assert.is_false(match.is_equal("a string")(nil)) assert.is_false(match.is_equal(nil)("a string")) end) it("Checks the same() matcher for tables with protected metatables", function() local troubleSomeTable = {} setmetatable(troubleSomeTable, {__metatable = 0}) assert.is_true(match.is_same(troubleSomeTable)(troubleSomeTable)) end) it("Checks same() matcher to handle nils properly", function() assert.is.error(function() match.same()() end) -- minimum 1 arguments assert.is_true(match.is_same(nil)(nil)) assert.is_false(match.is_same("a string")(nil)) assert.is_false(match.is_same(nil)("a string")) end) it("Checks ref() matcher", function() local t = {} local func = function() end local mythread = coroutine.create(func) assert.is.error(function() match.is_ref() end) -- minimum 1 arguments assert.is.error(function() match.is_ref(0) end) -- arg1 must be an object assert.is.error(function() match.is_ref('') end) -- arg1 must be an object assert.is.error(function() match.is_ref(nil) end) -- arg1 must be an object assert.is.error(function() match.is_ref(true) end) -- arg1 must be an object assert.is.error(function() match.is_ref(false) end) -- arg1 must be an object assert.is_true(match.is_ref(t)(t)) assert.is_true(match.is_ref(func)(func)) assert.is_true(match.is_ref(mythread)(mythread)) assert.is_false(match.is_ref(t)(func)) assert.is_false(match.is_ref(t)(mythread)) assert.is_false(match.is_ref(t)(nil)) assert.is_false(match.is_ref(t)(true)) assert.is_false(match.is_ref(t)(false)) assert.is_false(match.is_ref(t)(123)) assert.is_false(match.is_ref(t)("")) assert.is_false(match.is_ref(t)({})) assert.is_false(match.is_ref(t)(function() end)) end) it("Checks matches() matcher does string matching", function() assert.is.error(function() match.matches() end) -- minimum 1 arguments assert.is.error(function() match.matches({}) end) -- arg1 must be a string assert.is.error(function() match.matches('s', 's') end) -- arg2 must be a number or nil assert.is_true(match.matches("%w+")("test")) assert.is_true(match.has.match("%w+")("test")) assert.is_false(match.matches("%d+")("derp")) assert.is_true(match.has_match("test", nil, true)("test")) assert.is_false(match.has_match("%w+", nil, true)("test")) assert.is_true(match.has_match("^test", 5)("123 test")) assert.is_false(match.has_match("%d+", '4')("123 test")) end) it("Checks near() matcher handles tolerances", function() assert.is.error(function() match.near(0) end) -- minimum 2 arguments assert.is.error(function() match.near('a', 0) end) -- arg1 must be convertable to number assert.is.error(function() match.near(0, 'a') end) -- arg2 must be convertable to number assert.is_true(match.is.near(1.5, 0.5)(2.0)) assert.is_true(match.is.near('1.5', '0.5')('2.0')) assert.is_true(match.is_not.near(1.5, 0.499)(2.0)) assert.is_true(match.is_not.near('1.5', '0.499')('2.0')) end) 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_true(match.is.unique()(table1)) assert.is_true(match.is_not.unique()(tablenotunique)) end) it("Checks '_' chaining of modifiers and match", function() assert.is_true(match.is_string()("abc")) assert.is_true(match.is_true()(true)) assert.is_true(match.is_not_string()(123)) assert.is_true(match.is_nil()(nil)) assert.is_true(match.is_not_nil()({})) assert.is_true(match.is_not_true()(false)) assert.is_true(match.is_not_false()(true)) -- verify that failing match return false assert.is_false(match.is_string()(1)) assert.is_false(match.is_true()(false)) assert.is_false(match.is_not_string()('string!')) assert.is_false(match.is_nil()({})) assert.is_false(match.is_not_nil()(nil)) assert.is_false(match.is_not_true()(true)) assert.is_false(match.is_not_false()(false)) end) it("Checks '.' chaining of modifiers and match", function() assert.is_true(match.is.string()("abc")) assert.is_true(match.is.True()(true)) assert.is_true(match.is.Not.string()(123)) assert.is_true(match.is.Nil()(nil)) assert.is_true(match.is.Not.Nil()({})) assert.is_true(match.is.Not.True()(false)) assert.is_true(match.is.Not.False()(true)) assert.is_true(match.equals.Not(true)(false)) assert.is_true(match.equals.Not.Not(true)(true)) assert.is_true(match.Not.equals.Not(true)(true)) -- verify that failing match return false assert.is_false(match.is.string()(1)) assert.is_false(match.is.True()(false)) assert.is_false(match.is.Not.string()('string!')) assert.is_false(match.is.Nil()({})) assert.is_false(match.is.Not.Nil()(nil)) assert.is_false(match.is.Not.True()(true)) assert.is_false(match.is.Not.False()(false)) assert.is_false(match.equals.Not(true)(true)) assert.is_false(match.equals.Not.Not(true)(false)) assert.is_false(match.Not.equals.Not(true)(false)) end) it("Checks called_with() argument matching for spies", function() local s = spy.new(function() return "foo" end) s(1) s(nil, "") s({}, "") s(function() end, "") s(1, 2, 3) s("a", "b", "c", "d") assert.spy(s).was.called_with(match._) assert.spy(s).was.called_with(match.is_number()) assert.spy(s).was.called_with(match.is_number(), match.is_number(), match.is_number()) assert.spy(s).was_not.called_with(match.is_string()) assert.spy(s).was.called_with(match.is_string(), match.is_string(), match.is_string(), match.is_string()) assert.spy(s).was.called_with(match.is_nil(), match._) assert.spy(s).was.called_with(match.is_table(), match._) assert.spy(s).was.called_with(match.is_function(), match._) assert.spy(s).was_not.called_with(match.is_nil()) assert.spy(s).was_not.called_with(match.is_table()) assert.spy(s).was_not.called_with(match.is_function()) end) it("Checks returned_with() argument matching for spies", function() local s = spy.new(function() return "foo" end) s() assert.spy(s).was.returned_with(match._) assert.spy(s).was.returned_with(match.is_string()) assert.spy(s).was.returned_with(match.is_not_number()) assert.spy(s).was.returned_with(match.is_not_table()) assert.spy(s).was_not.returned_with(match.is_number()) assert.spy(s).was_not.returned_with(match.is_table()) end) it("Checks on_call_with() argument matching for stubs", function() local test = {} local s = stub(test, "key").returns("foo") s.on_call_with(match.is_string()).returns("bar") s.on_call_with(match.is_number()).returns(555) s.on_call_with(match.is_table()).returns({"foo"}) s(0) s("") s({}) assert.spy(s).was.returned_with(555) assert.spy(s).was.returned_with("bar") assert.spy(s).was.returned_with({"foo"}) end) it("Checks returned_with() argument matching for spies", function() local s = spy.new(function() return "foo" end) s() assert.spy(s).was.returned_with(match._) assert.spy(s).was.returned_with(match.is_string()) assert.spy(s).was.returned_with(match.is_not_nil()) assert.spy(s).was.returned_with(match.is_not_number()) assert.spy(s).was.returned_with(match.is_not_table()) assert.spy(s).was.returned_with(match.is_not_function()) end) it("Checks none() composite matcher", function() assert.has.error(function() match.none_of() end) -- minimum 1 arguments assert.has.error(function() match.none_of('') end) -- arg must be a matcher assert.has.error(function() match.none_of('', 0) end) -- all args must be a match assert.is_false(match.none_of(match.is_string())('')) assert.is_true(match.none_of(match.is_number())('')) assert.is_true(match.none_of(match.is_number(), match.is_function())('')) assert.is_false(match.none_of(match.is_number(), match.is_not_function())('')) assert.is_false(match.not_none_of(match.is_number(), match.is_function())('')) end) it("Checks any() composite matcher", function() assert.has.error(function() match.any_of() end) -- minimum 1 arguments assert.has.error(function() match.any_of('') end) -- arg must be a matcher assert.has.error(function() match.any_of('', 0) end) -- all args must be a match assert.is_true(match.any_of(match.is_string())('')) assert.is_false(match.any_of(match.is_number())('')) assert.is_false(match.any_of(match.is_number(), match.is_function())('')) assert.is_true(match.any_of(match.is_number(), match.is_not_function())('')) assert.is_true(match.not_any_of(match.is_number(), match.is_function())('')) end) it("Checks all() composite matcher", function() assert.has.error(function() match.all_of() end) -- minimum 1 arguments assert.has.error(function() match.all_of('') end) -- arg must be a matcher assert.has.error(function() match.all_of('', 0) end) -- all args must be a match assert.is_true(match.all_of(match.is_string())('')) assert.is_false(match.all_of(match.is_number())('')) assert.is_false(match.all_of(match.is_number(), match.is_function())('')) assert.is_false(match.all_of(match.is_number(), match.is_not_function())('')) assert.is_true(match.not_all_of(match.is_number(), match.is_function())('')) assert.is_true(match.all_of(match.is_not_number(), match.is_not_function())('')) end) end) luassert-1.8.0/spec/mocks_spec.lua000066400000000000000000000030111350545761100171470ustar00rootroot00000000000000describe("Tests dealing with mocks", function() local test = {} before_each(function() test = { key = function() return "derp" end } end) it("makes sure we're returning the same table", function() local val = tostring(test) assert(type(mock(test)) == "table") assert(tostring(mock(test)) == val) end) it("makes sure function calls are spies", function() assert(type(test.key) == "function") mock(test) assert(type(test.key) == "table") assert(test.key() == "derp") end) it("makes sure function calls are stubs when specified", function() assert(type(test.key) == "function") mock(test, true) assert(type(test.key) == "table") assert(test.key() == nil) end) it("makes sure call history can be cleared", function() test.foo = { bar = function() return "foobar" end } mock(test) test.key() test.key("test") test.foo.bar() test.foo.bar("hello world") assert.spy(test.key).was.called() assert.spy(test.foo.bar).was.called() mock.clear(test) assert.spy(test.key).was_not.called() assert.spy(test.foo.bar).was_not.called() end) it("makes sure table can be reverted to pre-mock state", function() local val = tostring(test) mock(test) mock.revert(test) assert(type(test.key) == "function") assert(test.key() == "derp") assert(tostring(test) == val) end) it("makes sure cycles are detected", function() test.foo = test mock(test) assert(test.foo == test) end) end) luassert-1.8.0/spec/output_spec.lua000066400000000000000000000556761350545761100174230ustar00rootroot00000000000000local unpack = require 'luassert.compatibility'.unpack describe("Output testing using string comparison with the equal assertion", function() local getoutput = function(...) local success, message = pcall(assert.are.equal, ...) if message == nil then return nil end return tostring(message) end it("Should compare strings correctly; nil-string", function() --assert.are.equal(nil, "string") local output = getoutput(nil, "string") local ok = output:find("Passed in:\n%(string%) 'string'") assert(ok, "Output check 1 failed, comparing nil-string;\n " .. output:gsub("\n","\n ")) local ok = output:find("Expected:\n%(nil%)") assert(ok, "Output check 2 failed, comparing nil-string;\n " .. output:gsub("\n","\n ")) end) it("Should compare strings correctly; string-nil", function() --assert.are.equal("string", nil) local output = getoutput("string", nil) local ok = output:find("Passed in:\n%(nil%)") assert(ok, "Output check 1 failed, comparing string-nil;\n " .. output:gsub("\n","\n ")) local ok = output:find("Expected:\n%(string%) 'string'") assert(ok, "Output check 2 failed, comparing string-nil;\n " .. output:gsub("\n","\n ")) end) end) describe("Output testing using string comparison with the has_error assertion", function() local getoutput = function(...) local success, message = pcall(assert.has_error, ...) if message == nil then return nil end return tostring(message) end it("Should report no error caught, but error expected; noerror-nil", function() --assert.has_error(function() end) local output = getoutput(function() end) local ok = output:find("Caught:\n%(no error%)") assert(ok, "Output check 1 failed, comparing noerror-nil;\n " .. output:gsub("\n","\n ")) local ok = output:find("Expected:\n%(error%)") assert(ok, "Output check 2 failed, comparing noerror-nil;\n " .. output:gsub("\n","\n ")) end) it("Should report no error caught, but error string expected; noerror-string", function() --assert.has_error(function() end, "string") local output = getoutput(function() end, 'string') local ok = output:find("Caught:\n%(no error%)") assert(ok, "Output check 1 failed, comparing noerror-string;\n " .. output:gsub("\n","\n ")) local ok = output:find("Expected:\n%(string%) 'string'") assert(ok, "Output check 2 failed, comparing noerror-string;\n " .. output:gsub("\n","\n ")) end) it("Should compare error strings correctly; nil-string", function() --assert.has_error(function() error() end, "string") local output = getoutput(function() error() end, "string") local ok = output:find("Caught:\n%(nil%)") assert(ok, "Output check 1 failed, comparing nil-string;\n " .. output:gsub("\n","\n ")) local ok = output:find("Expected:\n%(string%) 'string'") assert(ok, "Output check 2 failed, comparing nil-string;\n " .. output:gsub("\n","\n ")) end) it("Should compare error strings correctly; string-string", function() --assert.has_error(function() error("string") end, "string_") local output = getoutput(function() error("string") end, "string_") local ok = output:find("Caught:\n%(string%) '.*string'") assert(ok, "Output check 1 failed, comparing string-string;\n " .. output:gsub("\n","\n ")) local ok = output:find("Expected:\n%(string%) 'string_'") assert(ok, "Output check 2 failed, comparing string-string;\n " .. output:gsub("\n","\n ")) end) it("Should compare error strings correctly; table-string", function() --assert.has_error(function() error({}) end, "string") local t = {} local output = getoutput(function() error(t) end, "string") local ok = output:find("Caught:\n%("..tostring(t).."%) { }") assert(ok, "Output check 1 failed, comparing table-string;\n " .. output:gsub("\n","\n ")) local ok = output:find("Expected:\n%(string%) 'string'") assert(ok, "Output check 2 failed, comparing table-string;\n " .. output:gsub("\n","\n ")) end) it("Should compare error strings correctly; string-table", function() --assert.has_error(function() error("string") end, {}) local t = {} local output = getoutput(function() error("string") end, t) local ok = output:find("Caught:\n%(string%) 'string'") assert(ok, "Output check 1 failed, comparing string-table;\n " .. output:gsub("\n","\n ")) local ok = output:find("Expected:\n%("..tostring(t).."%) { }") assert(ok, "Output check 2 failed, comparing string-table;\n " .. output:gsub("\n","\n ")) end) it("Should compare error objects correctly; table-table", function() --assert.has_error(function() error({}) end, { "table" }) local t = {} local t2 = { "table" } local output = getoutput(function() error(t) end, t2) local ok = output:find("Caught:\n%("..tostring(t).."%) { }") assert(ok, "Output check 1 failed, comparing table-table;\n " .. output:gsub("\n","\n ")) local ok = output:find("Expected:\n%("..tostring(t2).."%) {\n %[1] = 'table' }") assert(ok, "Output check 2 failed, comparing table-table;\n " .. output:gsub("\n","\n ")) end) end) describe("Output testing using string comparison with the same assertion", function() local getoutput = function(...) local success, message = pcall(assert.are.same, ...) if message == nil then return nil end return tostring(message) end it("Should compare tables correctly", function() -- assert.are.same({1}, {2}) local t1, t2 = {1}, {2} local output = getoutput(t1, t2) local ok = output:find("Passed in:\n("..tostring(t2)..") {\n *[1] = 2 }", nil, true) assert(ok, "Output check 1 failed, comparing table-table;\n " .. output:gsub("\n","\n ")) local ok = output:find("Expected:\n("..tostring(t1)..") {\n *[1] = 1 }", nil, true) assert(ok, "Output check 2 failed, comparing table-table;\n " .. output:gsub("\n","\n ")) end) it("Should compare tables correctly and highlight differences", function() -- assert.are.same(t1, t2) local t1 = {1, {"a", "b", {"foo", "bar"} }, "c"} local t2 = {1, {"a", "b", {"bar", "bar"} }, "c"} local output = getoutput(t1, t2) local ok = output:find("Passed in:\n.*%*%[2].*%*%[3].*%*%[1] = 'bar'\n") assert(ok, "Output check 1 failed, comparing table-table;\n " .. output:gsub("\n","\n ")) local ok = output:find("Expected:\n.*%*%[2].*%*%[3].*%*%[1] = 'foo'\n") assert(ok, "Output check 2 failed, comparing table-table;\n " .. output:gsub("\n","\n ")) end) end) describe("Output testing using custom failure message", function() local geterror = function(key, ...) local argcnt = select("#", ...) local args = {...} args[argcnt+1] = key .. " fails" local success, message = pcall(assert[key], unpack(args, 1, argcnt+1)) if message == nil then return nil end message = tostring(message):gsub("\n.*", ""):gsub("^.-:%d+: ", "", 1) return message end local geterror2 = function(key, ...) local success, message = pcall(assert.message(key .. " fails")[key], ...) if message == nil then return nil end message = tostring(message):gsub("\n.*", ""):gsub("^.-:%d+: ", "", 1) return message end it("Should use failure message for is_true assertion", function() assert.is_equal("is_true fails", geterror("is_true", false)) assert.is_equal("is_true fails", geterror2("is_true", false)) assert.is_equal("is_not_true fails", geterror("is_not_true", true)) assert.is_equal("is_not_true fails", geterror2("is_not_true", true)) end) it("Should use failure message for is_false assertion", function() assert.is_equal("is_false fails", geterror("is_false", true)) assert.is_equal("is_false fails", geterror2("is_false", true)) assert.is_equal("is_not_false fails", geterror("is_not_false", false)) assert.is_equal("is_not_false fails", geterror2("is_not_false", false)) end) it("Should use failure message for is_truthy assertion", function() assert.is_equal("is_truthy fails", geterror("is_truthy", false)) assert.is_equal("is_truthy fails", geterror2("is_truthy", false)) assert.is_equal("is_not_truthy fails", geterror("is_not_truthy", true)) assert.is_equal("is_not_truthy fails", geterror2("is_not_truthy", true)) end) it("Should use failure message for is_falsy assertion", function() assert.is_equal("is_falsy fails", geterror("is_falsy", true)) assert.is_equal("is_falsy fails", geterror2("is_falsy", true)) assert.is_equal("is_not_falsy fails", geterror("is_not_falsy", false)) assert.is_equal("is_not_falsy fails", geterror2("is_not_falsy", false)) end) it("Should use failure message for is_type assertions", function() assert.is_equal("is_boolean fails", geterror("is_boolean", nil)) assert.is_equal("is_number fails", geterror("is_number", nil)) assert.is_equal("is_string fails", geterror("is_string", nil)) assert.is_equal("is_table fails", geterror("is_table", nil)) assert.is_equal("is_nil fails", geterror("is_nil", "nil")) assert.is_equal("is_userdata fails", geterror("is_userdata", nil)) assert.is_equal("is_function fails", geterror("is_function", nil)) assert.is_equal("is_thread fails", geterror("is_thread", nil)) assert.is_equal("is_boolean fails", geterror2("is_boolean", nil)) assert.is_equal("is_number fails", geterror2("is_number", nil)) assert.is_equal("is_string fails", geterror2("is_string", nil)) assert.is_equal("is_table fails", geterror2("is_table", nil)) assert.is_equal("is_nil fails", geterror2("is_nil", "nil")) assert.is_equal("is_userdata fails", geterror2("is_userdata", nil)) assert.is_equal("is_function fails", geterror2("is_function", nil)) assert.is_equal("is_thread fails", geterror2("is_thread", nil)) local thread = coroutine.create(function() end) assert.is_equal("is_not_boolean fails", geterror("is_not_boolean", true)) assert.is_equal("is_not_number fails", geterror("is_not_number", 0)) assert.is_equal("is_not_string fails", geterror("is_not_string", '')) assert.is_equal("is_not_table fails", geterror("is_not_table", {})) assert.is_equal("is_not_nil fails", geterror("is_not_nil", nil)) assert.is_equal("is_not_userdata fails", geterror("is_not_userdata", io.stdin)) assert.is_equal("is_not_function fails", geterror("is_not_function", function()end)) assert.is_equal("is_not_thread fails", geterror("is_not_thread", thread)) assert.is_equal("is_not_boolean fails", geterror2("is_not_boolean", true)) assert.is_equal("is_not_number fails", geterror2("is_not_number", 0)) assert.is_equal("is_not_string fails", geterror2("is_not_string", '')) assert.is_equal("is_not_table fails", geterror2("is_not_table", {})) assert.is_equal("is_not_nil fails", geterror2("is_not_nil", nil)) assert.is_equal("is_not_userdata fails", geterror2("is_not_userdata", io.stdin)) assert.is_equal("is_not_function fails", geterror2("is_not_function", function()end)) assert.is_equal("is_not_thread fails", geterror2("is_not_thread", thread)) end) it("Should use failure message for is_equal assertion", function() assert.is_equal("equals fails", geterror("equals", true, false)) assert.is_equal("equals fails", geterror2("equals", true, false)) assert.is_equal("not_equals fails", geterror("not_equals", true, true)) assert.is_equal("not_equals fails", geterror2("not_equals", true, true)) end) it("Should use failure message for is_same assertion", function() assert.is_equal("same fails", geterror("same", true, false)) assert.is_equal("same fails", geterror2("same", true, false)) assert.is_equal("not_same fails", geterror("not_same", true, true)) assert.is_equal("not_same fails", geterror2("not_same", true, true)) end) it("Should use failure message for is_same assertion: table-table", function() assert.is_equal("same fails", geterror("same", {}, {1})) assert.is_equal("same fails", geterror2("same", {}, {1})) assert.is_equal("not_same fails", geterror("not_same", {}, {})) assert.is_equal("not_same fails", geterror2("not_same", {}, {})) end) it("Should use failure message for is_unique assertion: shallow compare", function() assert.is_equal("unique fails", geterror("unique", {1, 1})) assert.is_equal("unique fails", geterror2("unique", {1, 1})) assert.is_equal("not_unique fails", geterror("not_unique", {1, 0})) assert.is_equal("not_unique fails", geterror2("not_unique", {1, 0})) end) it("Should use failure message for is_unique assertion: nil deep compare", function() assert.is_equal("unique fails", geterror("unique", {1, 1}, nil)) assert.is_equal("unique fails", geterror2("unique", {1, 1}, nil)) assert.is_equal("not_unique fails", geterror("not_unique", {1, 0}, nil)) assert.is_equal("not_unique fails", geterror2("not_unique", {1, 0}, nil)) end) it("Should use failure message for is_unique assertion: deep compare", function() assert.is_equal("unique fails", geterror("unique", {{1}, {1}}, true)) assert.is_equal("unique fails", geterror2("unique", {{1}, {1}}, true)) assert.is_equal("not_unique fails", geterror("not_unique", {{0}, {1}}, true)) assert.is_equal("not_unique fails", geterror2("not_unique", {{0}, {1}}, true)) end) it("Should use failure message for is_unique assertion: deep compare 2", function() local err1 = geterror("unique", {{1}, {1}}, "unique deep compare 2 fails", true) local err2 = geterror("not_unique", {{0}, {1}}, "not unique deep compare 2 fails", true) assert.is_equal("unique deep compare 2 fails", err1) assert.is_equal("not unique deep compare 2 fails", err2) end) it("Should use failure message for is_near assertion", function() assert.is_equal("is_near fails", geterror("is_near", 0, 1, 0.5)) assert.is_equal("is_near fails", geterror2("is_near", 0, 1, 0.5)) assert.is_equal("is_not_near fails", geterror("is_not_near", 0, 1, 1.5)) assert.is_equal("is_not_near fails", geterror2("is_not_near", 0, 1, 1.5)) end) it("Should use failure message for matches assertion", function() assert.is_equal("matches fails", geterror("matches", "%d+", "foobar")) assert.is_equal("matches fails", geterror("matches", "%d+", "0foobar", 2)) assert.is_equal("matches fails", geterror("matches", "%d+", "foobar", 1, true)) assert.is_equal("matches fails", geterror("matches", "%d+", "foobar", '2', true)) assert.is_equal("matches fails", geterror2("matches", "%d+", "foobar")) assert.is_equal("no_match fails", geterror("no_match", "%w+", "12345")) assert.is_equal("no_match fails", geterror2("no_match", "%w+", "12345")) end) it("Should use failure message for has_error assertion", function() assert.is_equal("has_error fails", geterror("has_error", function()end, nil)) assert.is_equal("has_error fails", geterror2("has_error", function()end, nil)) assert.is_equal("has_no_error fails", geterror("has_no_error", error, nil)) assert.is_equal("has_no_error fails", geterror2("has_no_error", error, nil)) end) it("Should use failure message for error_matches assertion", function() assert.is_equal("error_matches fails", geterror("error_matches", function()end, "")) assert.is_equal("error_matches fails", geterror("error_matches", function() error("1string") end, "%d+", 2)) assert.is_equal("error_matches fails", geterror("error_matches", function() error("1string") end, "xyz", 2, true)) assert.is_equal("error_matches fails", geterror2("error_matches", function()end, "")) assert.is_equal("no_error_matches fails", geterror("no_error_matches", function() error("string") end, "string")) assert.is_equal("no_error_matches fails", geterror2("no_error_matches", function() error("string") end, "string")) end) it("Should use failure message for returned_arguments assertion", function() assert.is_equal("returned_arguments fails", geterror2("returned_arguments", 4, 1, 2, 3)) assert.is_equal("not_returned_arguments fails", geterror2("not_returned_arguments", 4, 1, 2, 3, 4)) end) it("Should convert objects to string", function() local t = {} local t_tostring = setmetatable({},{__tostring=function(t) return "empty table" end}) assert.is_equal("("..tostring(t)..") { }", geterror("is_true", false, t)) assert.is_equal("(number) 999", geterror("is_true", false, 999)) assert.is_equal("(boolean) true", geterror("is_true", false, true)) assert.is_equal("(boolean) false", geterror("is_true", false, false)) assert.is_equal("empty table", geterror("is_true", false, t_tostring)) assert.is_equal("("..tostring(t)..") { }", geterror2("is_true", false, t)) assert.is_equal("(number) 999", geterror2("is_true", false, 999)) assert.is_equal("(boolean) true", geterror2("is_true", false, true)) assert.is_equal("(boolean) false", geterror2("is_true", false, false)) assert.is_equal("empty table", geterror2("is_true", false, t_tostring)) end) end) for _,ss in ipairs({"spy", "stub"}) do describe("Output testing " .. ss .. " using custom failure message", function() local test = {key = function() return "derp" end} local geterror = function(key, args, ...) local err = select('#', ...) == 0 and key .. " failed" or ... local success, message = pcall(assert[ss](test.key, err)[key], unpack(args)) if message == nil then return nil end message = tostring(message):gsub("\n.*", ""):gsub("^.-:%d+: ", "", 1) return message end local geterror2 = function(key, args, ...) local err = select('#', ...) == 0 and key .. " failed" or ... local success, message = pcall(assert.message(err).spy(test.key)[key], unpack(args)) if message == nil then return nil end message = tostring(message):gsub("\n.*", ""):gsub("^.-:%d+: ", "", 1) return message end before_each(function() if ss == "spy" then spy.on(test, "key") else stub(test, "key").returns("derp") end end) after_each(function() test.key:revert() end) it("Should use standard failure message if none provided for called", function() local err1 = geterror("was_called", {}, nil) local err2 = geterror2("was_called", {}, nil) local ok1 = err1:find("^Expected") local ok2 = err2:find("^Expected") assert(ok1, "Output check for called failed\n " .. err1:gsub("\n","\n ")) assert(ok2, "Output check for called failed\n " .. err2:gsub("\n","\n ")) end) it("Should use failure message for " .. ss .. " called assertion", function() assert.is_equal("was_called failed", geterror("was_called", {})) assert.is_equal("was_called failed", geterror2("was_called", {})) assert.is_equal("was_not_called failed", geterror("was_not_called", {0})) assert.is_equal("was_not_called failed", geterror2("was_not_called", {0})) end) it("Should use failure message for " .. ss .. " called_at_least assertion", function() assert.is_equal("was_called_at_least failed", geterror("was_called_at_least", {1})) assert.is_equal("was_called_at_least failed", geterror2("was_called_at_least", {1})) assert.is_equal("was_not_called_at_least failed", geterror("was_not_called_at_least", {0})) assert.is_equal("was_not_called_at_least failed", geterror2("was_not_called_at_least", {0})) end) it("Should use failure message for " .. ss .. " called_at_most assertion", function() test.key() assert.is_equal("was_called_at_most failed", geterror("was_called_at_most", {0})) assert.is_equal("was_called_at_most failed", geterror2("was_called_at_most", {0})) assert.is_equal("was_not_called_at_most failed", geterror("was_not_called_at_most", {1})) assert.is_equal("was_not_called_at_most failed", geterror2("was_not_called_at_most", {1})) end) it("Should use failure message for " .. ss .. " called_more_than assertion", function() test.key() assert.is_equal("was_called_more_than failed", geterror("was_called_more_than", {1})) assert.is_equal("was_called_more_than failed", geterror2("was_called_more_than", {1})) assert.is_equal("was_not_called_more_than failed", geterror("was_not_called_more_than", {0})) assert.is_equal("was_not_called_more_than failed", geterror2("was_not_called_more_than", {0})) end) it("Should use failure message for " .. ss .. " called_less_than assertion", function() test.key() assert.is_equal("was_called_less_than failed", geterror("was_called_less_than", {1})) assert.is_equal("was_called_less_than failed", geterror2("was_called_less_than", {1})) assert.is_equal("was_not_called_less_than failed", geterror("was_not_called_less_than", {2})) assert.is_equal("was_not_called_less_than failed", geterror2("was_not_called_less_than", {2})) end) it("Should use standard failure message if none provided for called_with", function() local err1 = geterror("was_called_with", {}, nil) local err2 = geterror("was_called_with", {}, nil) local ok1 = err1:find("^Function") local ok2 = err2:find("^Function") assert(ok1, "Output check for called_with failed\n " .. err1:gsub("\n","\n ")) assert(ok2, "Output check for called_with failed\n " .. err2:gsub("\n","\n ")) end) it("Should use failure message for " .. ss .. " called_with assertion", function() test.key() assert.is_equal("was_called_with failed", geterror("was_called_with", {1})) assert.is_equal("was_called_with failed", geterror2("was_called_with", {1})) assert.is_equal("was_not_called_with failed", geterror("was_not_called_with", {})) assert.is_equal("was_not_called_with failed", geterror2("was_not_called_with", {})) end) it("Should use failure message for " .. ss .. " returned_with assertion", function() test.key() assert.is_equal("was_returned_with failed", geterror("was_returned_with", {1})) assert.is_equal("was_returned_with failed", geterror2("was_returned_with", {1})) assert.is_equal("was_not_returned_with failed", geterror("was_not_returned_with", {"derp"})) assert.is_equal("was_not_returned_with failed", geterror2("was_not_returned_with", {"derp"})) end) it("Should convert objects to string", function() local t = {} local t_tostring = setmetatable({},{__tostring=function(t) return "empty table" end}) assert.is_equal("("..tostring(t)..") { }", geterror("was_called", {}, t)) assert.is_equal("(number) 999", geterror("was_called", {}, 999)) assert.is_equal("(boolean) true", geterror("was_called", {}, true)) assert.is_equal("(boolean) false", geterror("was_called", {}, false)) assert.is_equal("empty table", geterror("was_called", {}, t_tostring)) assert.is_equal("("..tostring(t)..") { }", geterror2("was_called", {}, t)) assert.is_equal("(number) 999", geterror2("was_called", {}, 999)) assert.is_equal("(boolean) true", geterror2("was_called", {}, true)) assert.is_equal("(boolean) false", geterror2("was_called", {}, false)) assert.is_equal("empty table", geterror2("was_called", {}, t_tostring)) end) end) end luassert-1.8.0/spec/spies_spec.lua000066400000000000000000000155721350545761100171750ustar00rootroot00000000000000local match = require 'luassert.match' describe("Tests dealing with spies", function() local test = {} before_each(function() test = {key = function() return "derp" end} end) it("checks if a spy actually executes the internal function", function() spy.on(test, "key") assert(test.key() == "derp") end) it("checks to see if spy keeps track of arguments", function() spy.on(test, "key") test.key("derp") assert.spy(test.key).was.called_with("derp") assert.errors(function() assert.spy(test.key).was.called_with("herp") end) end) it("checks to see if spy keeps track of returned arguments", function() spy.on(test, "key") test.key() assert.spy(test.key).was.returned_with("derp") assert.errors(function() assert.spy(test.key).was.returned_with("herp") end) end) it("checks to see if spy keeps track of number of calls", function() spy.on(test, "key") test.key() test.key("test") assert.spy(test.key).was.called(2) end) it("checks returned_with() assertions", function() local s = spy.new(function(...) return ... end) local t = { foo = { bar = { "test" } } } local _ = match._ s(1, 2, 3) s("a", "b", "c") s(t) t.foo.bar = "value" assert.spy(s).was.returned_with(1, 2, 3) assert.spy(s).was_not.returned_with({1, 2, 3}) -- mind the accolades assert.spy(s).was.returned_with(_, 2, 3) -- matches don't care assert.spy(s).was.returned_with(_, _, _) -- matches multiple don't cares assert.spy(s).was_not.returned_with(_, _, _, _) -- does not match if too many args assert.spy(s).was.returned_with({ foo = { bar = { "test" } } }) -- matches original table assert.spy(s).was_not.returned_with(t) -- does not match modified table assert.has_error(function() assert.spy(s).was.returned_with(5, 6) end) end) it("checks called() and called_with() assertions", function() local s = spy.new(function() end) local t = { foo = { bar = { "test" } } } local _ = match._ s(1, 2, 3) s("a", "b", "c") s(t) t.foo.bar = "value" assert.spy(s).was.called() assert.spy(s).was.called(3) -- 3 times! assert.spy(s).was_not.called(4) assert.spy(s).was_not.called_with({1, 2, 3}) -- mind the accolades assert.spy(s).was.called_with(1, 2, 3) assert.spy(s).was.called_with(_, 2, 3) -- matches don't care assert.spy(s).was.called_with(_, _, _) -- matches multiple don't cares assert.spy(s).was_not.called_with(_, _, _, _) -- does not match if too many args assert.spy(s).was.called_with({ foo = { bar = { "test" } } }) -- matches original table assert.spy(s).was_not.called_with(t) -- does not match modified table assert.has_error(function() assert.spy(s).was.called_with(5, 6) end) end) it("checks called() and called_with() assertions using refs", function() local s = spy.new(function() end) local t1 = { foo = { bar = { "test" } } } local t2 = { foo = { bar = { "test" } } } s(t1) t1.foo.bar = "value" assert.spy(s).was.called_with(t2) assert.spy(s).was_not.called_with(match.is_ref(t2)) assert.spy(s).was.called_with(match.is_ref(t1)) end) it("checks called_with(aspy) assertions", function() local s = spy.new(function() end) s(s) assert.spy(s).was.called_with(s) end) it("checks called_at_least() assertions", function() local s = spy.new(function() end) s(1, 2, 3) s("a", "b", "c") assert.spy(s).was.called.at_least(1) assert.spy(s).was.called.at_least(2) assert.spy(s).was_not.called.at_least(3) assert.has_error(function() assert.spy(s).was.called.at_least() end) end) it("checks called_at_most() assertions", function() local s = spy.new(function() end) s(1, 2, 3) s("a", "b", "c") assert.spy(s).was.called.at_most(3) assert.spy(s).was.called.at_most(2) assert.spy(s).was_not.called.at_most(1) assert.has_error(function() assert.spy(s).was.called.at_most() end) end) it("checks called_more_than() assertions", function() local s = spy.new(function() end) s(1, 2, 3) s("a", "b", "c") assert.spy(s).was.called.more_than(0) assert.spy(s).was.called.more_than(1) assert.spy(s).was_not.called.more_than(2) assert.has_error(function() assert.spy(s).was.called.more_than() end) end) it("checks called_less_than() assertions", function() local s = spy.new(function() end) s(1, 2, 3) s("a", "b", "c") assert.spy(s).was.called.less_than(4) assert.spy(s).was.called.less_than(3) assert.spy(s).was_not.called.less_than(2) assert.has_error(function() assert.spy(s).was.called.less_than() end) end) it("checkis if called()/called_with assertions fail on non-spies ", function() assert.has_error(assert.was.called) assert.has_error(assert.was.called_at_least) assert.has_error(assert.was.called_at_most) assert.has_error(assert.was.called_more_than) assert.has_error(assert.was.called_less_than) assert.has_error(assert.was.called_with) assert.has_error(assert.was.returned_with) end) it("checks spies to fail when spying on non-callable elements", function() local s local testfunc = function() spy.new(s) end -- try some types to fail s = "some string"; assert.has_error(testfunc) s = 10; assert.has_error(testfunc) s = true; assert.has_error(testfunc) -- try some types to succeed s = function() end; assert.has_no_error(testfunc) s = setmetatable( {}, { __call = function() end } ); assert.has_no_error(testfunc) end) it("checks reverting a spy.on call", function() local old = test.key local s = spy.on(test, "key") test.key() test.key("test") assert.spy(test.key).was.called(2) -- revert and call again s:revert() assert.are.equal(old, test.key) test.key() test.key("test") assert.spy(s).was.called(2) -- still two, spy was removed end) it("checks reverting a spy.new call", function() local calls = 0 local old = function() calls = calls + 1 end local s = spy.new(old) assert.is_table(s) s() s() assert.spy(s).was.called(2) assert.are.equal(calls, 2) local old_s = s s = s:revert() assert.are.equal(s, old) s() assert.spy(old_s).was.called(2) -- still two, spy was removed assert.are.equal(calls, 3) end) it("checks clearing a spy.on call history", function() local s = spy.on(test, "key") test.key() test.key("test") s:clear() assert.spy(s).was.called(0) end) it("checks clearing a spy.new call history", function() local s = spy.new(function() return "foobar" end) s() s("test") s:clear() assert.spy(s).was.called(0) assert.spy(s).was_not.returned_with("foobar") end) it("checks spy.new can be constructed without arguments", function() local s = spy.new() s() assert.spy(s).was.called(1) end) end) luassert-1.8.0/spec/state_spec.lua000066400000000000000000000116401350545761100171620ustar00rootroot00000000000000describe("Tests states of the assert engine", function() it("checks levels created/reverted", function() local start = assert:snapshot() assert.is_nil(start.next) local snapshot1 = assert:snapshot() assert.is.table(start.next) assert.are.equal(start.next, snapshot1) assert.are.equal(start, snapshot1.previous) assert.is_nil(snapshot1.next) local snapshot2 = assert:snapshot() assert.is.table(snapshot1.next) assert.are.equal(snapshot2, snapshot1.next) assert.are.equal(snapshot2.previous, snapshot1) assert.is_nil(snapshot2.next) snapshot2:revert() assert.is.table(start.next) assert.are.equal(start.next, snapshot1) assert.are.equal(start, snapshot1.previous) assert.is_nil(snapshot1.next) snapshot1:revert() assert.is_nil(start.next) end) it("checks to see if a formatter is reversed", function() -- add a state level by creating a snapshot local snapshot1 = assert:snapshot() -- register extra formatters local fmt1 = function(value) if type(value) == "string" then return "ok" end end assert:add_formatter(fmt1) local fmt2 = function(value) if type(value) == "number" then return "1" end end assert:add_formatter(fmt2) -- check formatters assert.are.equal(#snapshot1.formatters, 2) assert.are.equal(snapshot1.formatters[2], fmt1) assert.are.equal(snapshot1.formatters[1], fmt2) assert.are.equal("ok", assert:format({"some value"})[1]) assert.are.equal("1", assert:format({123})[1]) -- add another state level by creating a snapshot local snapshot2 = assert:snapshot() -- register extra formatter local fmt3 = function(value) if type(value) == "number" then return "2" end end assert:add_formatter(fmt3) assert.are.equal(#snapshot2.formatters, 1) assert.are.equal(snapshot2.formatters[1], fmt3) -- check formatter newest level assert.are.equal("2", assert:format({123})[1]) -- check formatter previous level assert.are.equal("ok", assert:format({"some value"})[1]) -- check formatter initial level assert.are.equal("(boolean) true", assert:format({true})[1]) -- revert 1 state up snapshot2:revert() assert.is_nil(snapshot1.next) assert.are.equal(2, #snapshot1.formatters) -- check formatter reverted level assert.are.equal("1", assert:format({123})[1]) -- check formatter unchanged level assert.are.equal("ok", assert:format({"some value"})[1]) -- check formatter unchanged level assert.are.equal("(boolean) true", assert:format({true})[1]) -- revert 1 more up, to initial level snapshot1:revert() assert.are.equal("(number) 123", assert:format({123})[1]) assert.are.equal("(string) 'some value'", assert:format({"some value"})[1]) assert.are.equal("(boolean) true", assert:format({true})[1]) end) it("checks to see if a parameter is reversed", function() -- add a state level by creating a snapshot local snapshot1 = assert:snapshot() assert.is_nil(assert:get_parameter("Test_1")) assert.is_nil(assert:get_parameter("Test_2")) assert:set_parameter("Test_1", 1) assert:set_parameter("Test_2", 2) assert.are.equal(1, assert:get_parameter("Test_1")) assert.are.equal(2, assert:get_parameter("Test_2")) -- add another state level by creating a snapshot local snapshot2 = assert:snapshot() assert.are.equal(1, assert:get_parameter("Test_1")) assert.are.equal(2, assert:get_parameter("Test_2")) assert:set_parameter("Test_1", "one") assert:set_parameter("Test_2", nil) -- test setting to nil assert.are.equal("one", assert:get_parameter("Test_1")) assert.is_nil(assert:get_parameter("Test_2")) -- revert 1 state up snapshot2:revert() assert.are.equal(1, assert:get_parameter("Test_1")) assert.are.equal(2, assert:get_parameter("Test_2")) -- revert 1 more up, to initial level snapshot1:revert() assert.is_nil(assert:get_parameter("Test_1")) assert.is_nil(assert:get_parameter("Test_2")) end) it("checks to see if a spy/stub is reversed", function() local c1, c2 = 0, 0 local test = { f1 = function() c1 = c1 + 1 end, f2 = function() c2 = c2 + 1 end, } local f1 = test.f1 local f2 = test.f2 -- add a state level by creating a snapshot local snapshot1 = assert:snapshot() -- create spy/stub local s1 = spy.on(test, "f1") local s2 = stub(test, "f2") -- call them both test.f1() test.f2() assert.spy(test.f1).was.called(1) assert.spy(test.f2).was.called(1) assert.is_equal(1, c1) assert.is_equal(0, c2) -- 0, because it's a stub -- revert to initial level snapshot1:revert() test.f1() test.f2() -- check count is still 1 for both assert.spy(s1).was.called(1) assert.spy(s2).was.called(1) assert.is_equal(2, c1) assert.is_equal(1, c2) end) end) luassert-1.8.0/spec/stub_spec.lua000066400000000000000000000174341350545761100170260ustar00rootroot00000000000000local match = require 'luassert.match' describe("Tests dealing with stubs", function() local test = {} before_each(function() test = {key = function() return "derp" end} end) it("checks to see if stub keeps track of arguments", function() stub(test, "key") test.key("derp") assert.stub(test.key).was.called_with("derp") assert.errors(function() assert.stub(test.key).was.called_with("herp") end) end) it("checks to see if stub keeps track of number of calls", function() stub(test, "key") test.key() test.key("test") assert.stub(test.key).was.called(2) end) it("checks called() and called_with() assertions", function() local s = stub.new(test, "key") s(1, 2, 3) s("a", "b", "c") assert.stub(s).was.called() assert.stub(s).was.called(2) -- twice! assert.stub(s).was_not.called(3) assert.stub(s).was_not.called_with({1, 2, 3}) -- mind the accolades assert.stub(s).was.called_with(1, 2, 3) assert.has_error(function() assert.stub(s).was.called_with(5, 6) end) end) it("checks stub to fail when spying on non-callable elements", function() local s local testfunc = function() local t = { key = s} stub.new(t, "key") end -- try some types to fail s = "some string"; assert.has_error(testfunc) s = 10; assert.has_error(testfunc) s = true; assert.has_error(testfunc) -- try some types to succeed s = function() end; assert.has_no_error(testfunc) s = setmetatable( {}, { __call = function() end } ); assert.has_no_error(testfunc) end) it("checks reverting a stub call", function() local calls = 0 local old = function() calls = calls + 1 end test.key = old local s = stub.new(test, "key") assert.is_table(s) s() s() assert.stub(s).was.called(2) assert.are.equal(calls, 0) -- its a stub, so no calls local old_s = s s = s:revert() s() assert.stub(old_s).was.called(2) -- still two, stub was removed assert.are.equal(s, old) assert.are.equal(calls, 1) -- restored, so now 1 call end) it("checks reverting a stub call on a nil value", function() test = {} local s = stub.new(test, "key") assert.is_table(s) s() s() assert.stub(s).was.called(2) local old_s = s s = s:revert() assert.is_nil(s) end) it("checks creating and reverting a 'blank' stub", function() local s = stub.new() -- use no parameters to create a blank assert.is_table(s) s() s() assert.stub(s).was.called(2) local old_s = s s = s:revert() assert.is_nil(s) end) it("checks clearing a stub only clears call history", function() local s = stub.new(test, "key") s.returns("value") s.on_call_with("foo").returns("bar") s() s("foo") s:clear() assert.stub(s).was_not.called() assert.stub(s).was_not.returned_with("value") assert.stub(s).was_not.returned_with("bar") s("foo") assert.stub(s).was.returned_with("bar") end) it("returns nil by default", function() stub(test, "key") assert.is_nil(test.key()) end) it("returns a given return value", function() stub(test, "key", "foo") assert.is.equal("foo", test.key()) end) it("returns multiple given values", function() stub(test, "key", "foo", nil, "bar") local arg1, arg2, arg3 = test.key() assert.is.equal("foo", arg1) assert.is.equal(nil, arg2) assert.is.equal("bar", arg3) end) it("calls specified stub function", function() stub(test, "key", function(a, b, c) return c, b, a end) local arg1, arg2, arg3 = test.key("bar", nil, "foo") assert.is.equal("foo", arg1) assert.is.equal(nil, arg2) assert.is.equal("bar", arg3) end) it("calls specified stub callable object", function() local callable = setmetatable({}, { __call = function(self, a, b, c) return c, b, a end}) stub(test, "key", callable) local arg1, arg2, arg3 = test.key("bar", nil, "foo") assert.is.equal("foo", arg1) assert.is.equal(nil, arg2) assert.is.equal("bar", arg3) end) it("returning multiple given values overrides stub function", function() local function foo() end stub(test, "key", foo, nil, "bar") local arg1, arg2, arg3 = test.key() assert.is.equal(foo, arg1) assert.is.equal(nil, arg2) assert.is.equal("bar", arg3) end) it("returns default stub arguments", function() stub(test, "key").returns(nil, "foo", "bar") local arg1, arg2, arg3 = test.key("bar", nil, "foo") assert.is.equal(nil, arg1) assert.is.equal("foo", arg2) assert.is.equal("bar", arg3) end) it("invokes default stub function", function() stub(test, "key").invokes(function(a, b, c) return c, b, a end) local arg1, arg2, arg3 = test.key("bar", nil, "foo") assert.is.equal("foo", arg1) assert.is.equal(nil, arg2) assert.is.equal("bar", arg3) end) it("returns stub arguments by default", function() stub(test, "key").by_default.returns("foo", "bar") local arg1, arg2 = test.key() assert.is.equal("foo", arg1) assert.is.equal("bar", arg2) end) it("invokes stub function by default", function() stub(test, "key").by_default.invokes(function(a, b) return b, a end) local arg1, arg2 = test.key("bar", "foo") assert.is.equal("foo", arg1) assert.is.equal("bar", arg2) end) it("on_call_with returns specified arguments", function() stub(test, "key").returns("foo bar") test.key.on_call_with("bar").returns("foo", nil, "bar") test.key.on_call_with(match._, "foo").returns("foofoo") local arg1, arg2, arg3 = test.key("bar") local foofoo1 = test.key(1, "foo") local foofoo2 = test.key(2, "foo") local foofoo3 = test.key(nil, "foo") local foobar = test.key() assert.is.equal("foo", arg1) assert.is.equal(nil, arg2) assert.is.equal("bar", arg3) assert.is.equal("foo bar", foobar) assert.is.equal("foofoo", foofoo1) assert.is.equal("foofoo", foofoo2) assert.is.equal("foofoo", foofoo3) end) it("on_call_with invokes stub function", function() stub(test, "key").returns("foo foo") test.key.on_call_with("foo").invokes(function(a, b, c) return "bar", nil, "bar" end) local arg1, arg2, arg3 = test.key("foo") local foo = test.key() assert.is.equal("bar", arg1) assert.is.equal(nil, arg2) assert.is.equal("bar", arg3) assert.is.equal("foo foo", foo) end) it("on_call_with matches arguments for returns", function() local t = { foo = { bar = { "test" } } } stub(test, "key").returns("foo foo") test.key.on_call_with(t).returns("bar") t.foo.bar = "value" local bar = test.key({ foo = { bar = { "test" } } }) local foofoo = test.key(t) assert.is.equal("bar", bar) assert.is.equal("foo foo", foofoo) end) it("on_call_with matches arguments for invokes", function() local t = { foo = { bar = { "test" } } } stub(test, "key").returns("foo foo") test.key.on_call_with(t).invokes(function() return "bar bar" end) t.foo.bar = "value" local bar = test.key({ foo = { bar = { "test" } } }) local foofoo = test.key(t) assert.is.equal("bar bar", bar) assert.is.equal("foo foo", foofoo) end) it("on_call_with matches arguments using refs", function() local t1 = { foo = { bar = { "test" } } } local t2 = { foo = { bar = { "test" } } } stub(test, "key").returns("foo foo") test.key.on_call_with(match.is_ref(t1)).returns("bar") t1.foo.bar = "value" t2.foo.bar = "value" local bar = test.key(t1) local foo = test.key(t2) local foofoo = test.key({ foo = { bar = { "test" } } }) assert.is.equal("bar", bar) assert.is.equal("foo foo", foo) assert.is.equal("foo foo", foofoo) end) end) luassert-1.8.0/src/000077500000000000000000000000001350545761100141605ustar00rootroot00000000000000luassert-1.8.0/src/array.lua000066400000000000000000000047061350545761100160100ustar00rootroot00000000000000local assert = require('luassert.assert') local say = require('say') -- Example usage: -- local arr = { "one", "two", "three" } -- -- assert.array(arr).has.no.holes() -- checks the array to not contain holes --> passes -- assert.array(arr).has.no.holes(4) -- sets explicit length to 4 --> fails -- -- local first_hole = assert.array(arr).has.holes(4) -- check array of size 4 to contain holes --> passes -- assert.equal(4, first_hole) -- passes, as the index of the first hole is returned -- Unique key to store the object we operate on in the state object -- key must be unique, to make sure we do not have name collissions in the shared state object local ARRAY_STATE_KEY = "__array_state" -- The modifier, to store the object in our state local function array(state, args, level) assert(args.n > 0, "No array provided to the array-modifier") assert(rawget(state, ARRAY_STATE_KEY) == nil, "Array already set") rawset(state, ARRAY_STATE_KEY, args[1]) return state end -- The actual assertion that operates on our object, stored via the modifier local function holes(state, args, level) local length = args[1] local arr = rawget(state, ARRAY_STATE_KEY) -- retrieve previously set object -- only check against nil, metatable types are allowed assert(arr ~= nil, "No array set, please use the array modifier to set the array to validate") if length == nil then length = 0 for i in pairs(arr) do if type(i) == "number" and i > length and math.floor(i) == i then length = i end end end assert(type(length) == "number", "expected array length to be of type 'number', got: "..tostring(length)) -- let's do the actual assertion local missing for i = 1, length do if arr[i] == nil then missing = i break end end -- format arguments for output strings; args[1] = missing args.n = missing and 1 or 0 return missing ~= nil, { missing } -- assert result + first missing index as return value end -- Register the proper assertion messages say:set("assertion.array_holes.positive", [[ Expected array to have holes, but none was found. ]]) say:set("assertion.array_holes.negative", [[ Expected array to not have holes, hole found at position: %s ]]) -- Register the assertion, and the modifier assert:register("assertion", "holes", holes, "assertion.array_holes.positive", "assertion.array_holes.negative") assert:register("modifier", "array", array) luassert-1.8.0/src/assert.lua000066400000000000000000000116021350545761100161640ustar00rootroot00000000000000local s = require 'say' local astate = require 'luassert.state' local util = require 'luassert.util' local unpack = require 'luassert.compatibility'.unpack local obj -- the returned module table local level_mt = {} -- list of namespaces local namespace = require 'luassert.namespaces' local function geterror(assertion_message, failure_message, args) if util.hastostring(failure_message) then failure_message = tostring(failure_message) elseif failure_message ~= nil then failure_message = astate.format_argument(failure_message) end local message = s(assertion_message, obj:format(args)) if message and failure_message then message = failure_message .. "\n" .. message end return message or failure_message end local __state_meta = { __call = function(self, ...) local keys = util.extract_keys("assertion", self.tokens) local assertion for _, key in ipairs(keys) do assertion = namespace.assertion[key] or assertion end if assertion then for _, key in ipairs(keys) do if namespace.modifier[key] then namespace.modifier[key].callback(self) end end local arguments = {...} arguments.n = select('#', ...) -- add argument count for trailing nils local val, retargs = assertion.callback(self, arguments, util.errorlevel()) if not val == self.mod then local message = assertion.positive_message if not self.mod then message = assertion.negative_message end local err = geterror(message, rawget(self,"failure_message"), arguments) error(err or "assertion failed!", util.errorlevel()) end if retargs then return unpack(retargs) end return ... else local arguments = {...} arguments.n = select('#', ...) self.tokens = {} for _, key in ipairs(keys) do if namespace.modifier[key] then namespace.modifier[key].callback(self, arguments, util.errorlevel()) end end end return self end, __index = function(self, key) for token in key:lower():gmatch('[^_]+') do table.insert(self.tokens, token) end return self end } obj = { state = function() return setmetatable({mod=true, tokens={}}, __state_meta) end, -- registers a function in namespace register = function(self, nspace, name, callback, positive_message, negative_message) local lowername = name:lower() if not namespace[nspace] then namespace[nspace] = {} end namespace[nspace][lowername] = { callback = callback, name = lowername, positive_message=positive_message, negative_message=negative_message } end, -- unregisters a function in a namespace unregister = function(self, nspace, name) local lowername = name:lower() if not namespace[nspace] then namespace[nspace] = {} end namespace[nspace][lowername] = nil end, -- registers a formatter -- a formatter takes a single argument, and converts it to a string, or returns nil if it cannot format the argument add_formatter = function(self, callback) astate.add_formatter(callback) end, -- unregisters a formatter remove_formatter = function(self, fmtr) astate.remove_formatter(fmtr) end, format = function(self, args) -- args.n specifies the number of arguments in case of 'trailing nil' arguments which get lost local nofmt = args.nofmt or {} -- arguments in this list should not be formatted local fmtargs = args.fmtargs or {} -- additional arguments to be passed to formatter for i = 1, (args.n or #args) do -- cannot use pairs because table might have nils if not nofmt[i] then local val = args[i] local valfmt = astate.format_argument(val, nil, fmtargs[i]) if valfmt == nil then valfmt = tostring(val) end -- no formatter found args[i] = valfmt end end return args end, set_parameter = function(self, name, value) astate.set_parameter(name, value) end, get_parameter = function(self, name) return astate.get_parameter(name) end, add_spy = function(self, spy) astate.add_spy(spy) end, snapshot = function(self) return astate.snapshot() end, level = function(self, level) return setmetatable({ level = level }, level_mt) end, -- returns the level if a level-value, otherwise nil get_level = function(self, level) if getmetatable(level) ~= level_mt then return nil -- not a valid error-level end return level.level end, } local __meta = { __call = function(self, bool, message, level, ...) if not bool then local err_level = (self:get_level(level) or 1) + 1 error(message or "assertion failed!", err_level) end return bool , message , level , ... end, __index = function(self, key) return rawget(self, key) or self.state()[key] end, } return setmetatable(obj, __meta) luassert-1.8.0/src/assertions.lua000066400000000000000000000333151350545761100170620ustar00rootroot00000000000000-- module will not return anything, only register assertions with the main assert engine -- assertions take 2 parameters; -- 1) state -- 2) arguments list. The list has a member 'n' with the argument count to check for trailing nils -- 3) level The level of the error position relative to the called function -- returns; boolean; whether assertion passed local assert = require('luassert.assert') local astate = require ('luassert.state') local util = require ('luassert.util') local s = require('say') local function format(val) return astate.format_argument(val) or tostring(val) end local function set_failure_message(state, message) if message ~= nil then state.failure_message = message end end local function unique(state, arguments, level) local list = arguments[1] local deep local argcnt = arguments.n if type(arguments[2]) == "boolean" or (arguments[2] == nil and argcnt > 2) then deep = arguments[2] set_failure_message(state, arguments[3]) else if type(arguments[3]) == "boolean" then deep = arguments[3] end set_failure_message(state, arguments[2]) end for k,v in pairs(list) do for k2, v2 in pairs(list) do if k ~= k2 then if deep and util.deepcompare(v, v2, true) then return false else if v == v2 then return false end end end end end return true end local function near(state, arguments, level) local level = (level or 1) + 1 local argcnt = arguments.n assert(argcnt > 2, s("assertion.internal.argtolittle", { "near", 3, tostring(argcnt) }), level) local expected = tonumber(arguments[1]) local actual = tonumber(arguments[2]) local tolerance = tonumber(arguments[3]) local numbertype = "number or object convertible to a number" assert(expected, s("assertion.internal.badargtype", { 1, "near", numbertype, format(arguments[1]) }), level) assert(actual, s("assertion.internal.badargtype", { 2, "near", numbertype, format(arguments[2]) }), level) assert(tolerance, s("assertion.internal.badargtype", { 3, "near", numbertype, format(arguments[3]) }), level) -- switch arguments for proper output message util.tinsert(arguments, 1, util.tremove(arguments, 2)) arguments[3] = tolerance arguments.nofmt = arguments.nofmt or {} arguments.nofmt[3] = true set_failure_message(state, arguments[4]) return (actual >= expected - tolerance and actual <= expected + tolerance) end local function matches(state, arguments, level) local level = (level or 1) + 1 local argcnt = arguments.n assert(argcnt > 1, s("assertion.internal.argtolittle", { "matches", 2, tostring(argcnt) }), level) local pattern = arguments[1] local actual = nil if util.hastostring(arguments[2]) or type(arguments[2]) == "number" then actual = tostring(arguments[2]) end local err_message local init_arg_num = 3 for i=3,argcnt,1 do if arguments[i] and type(arguments[i]) ~= "boolean" and not tonumber(arguments[i]) then if i == 3 then init_arg_num = init_arg_num + 1 end err_message = util.tremove(arguments, i) break end end local init = arguments[3] local plain = arguments[4] local stringtype = "string or object convertible to a string" assert(type(pattern) == "string", s("assertion.internal.badargtype", { 1, "matches", "string", type(arguments[1]) }), level) assert(actual, s("assertion.internal.badargtype", { 2, "matches", stringtype, format(arguments[2]) }), level) assert(init == nil or tonumber(init), s("assertion.internal.badargtype", { init_arg_num, "matches", "number", type(arguments[3]) }), level) -- switch arguments for proper output message util.tinsert(arguments, 1, util.tremove(arguments, 2)) set_failure_message(state, err_message) local retargs local ok if plain then ok = (actual:find(pattern, init, plain) ~= nil) retargs = ok and { pattern } or {} else retargs = { actual:match(pattern, init) } ok = (retargs[1] ~= nil) end return ok, retargs end local function equals(state, arguments, level) local level = (level or 1) + 1 local argcnt = arguments.n assert(argcnt > 1, s("assertion.internal.argtolittle", { "equals", 2, tostring(argcnt) }), level) local result = arguments[1] == arguments[2] -- switch arguments for proper output message util.tinsert(arguments, 1, util.tremove(arguments, 2)) set_failure_message(state, arguments[3]) return result end local function same(state, arguments, level) local level = (level or 1) + 1 local argcnt = arguments.n assert(argcnt > 1, s("assertion.internal.argtolittle", { "same", 2, tostring(argcnt) }), level) if type(arguments[1]) == 'table' and type(arguments[2]) == 'table' then local result, crumbs = util.deepcompare(arguments[1], arguments[2], true) -- switch arguments for proper output message util.tinsert(arguments, 1, util.tremove(arguments, 2)) arguments.fmtargs = arguments.fmtargs or {} arguments.fmtargs[1] = { crumbs = crumbs } arguments.fmtargs[2] = { crumbs = crumbs } set_failure_message(state, arguments[3]) return result end local result = arguments[1] == arguments[2] -- switch arguments for proper output message util.tinsert(arguments, 1, util.tremove(arguments, 2)) set_failure_message(state, arguments[3]) return result end local function truthy(state, arguments, level) set_failure_message(state, arguments[2]) return arguments[1] ~= false and arguments[1] ~= nil end local function falsy(state, arguments, level) return not truthy(state, arguments, level) end local function has_error(state, arguments, level) local level = (level or 1) + 1 local retargs = util.shallowcopy(arguments) local func = arguments[1] local err_expected = arguments[2] local failure_message = arguments[3] assert(util.callable(func), s("assertion.internal.badargtype", { 1, "error", "function or callable object", type(func) }), level) local ok, err_actual = pcall(func) if type(err_actual) == 'string' then -- remove 'path/to/file:line: ' from string err_actual = err_actual:gsub('^.-:%d+: ', '', 1) end retargs[1] = err_actual arguments.nofmt = {} arguments.n = 2 arguments[1] = (ok and '(no error)' or err_actual) arguments[2] = (err_expected == nil and '(error)' or err_expected) arguments.nofmt[1] = ok arguments.nofmt[2] = (err_expected == nil) set_failure_message(state, failure_message) if ok or err_expected == nil then return not ok, retargs end if type(err_expected) == 'string' then -- err_actual must be (convertible to) a string if util.hastostring(err_actual) then err_actual = tostring(err_actual) retargs[1] = err_actual end if type(err_actual) == 'string' then return err_expected == err_actual, retargs end elseif type(err_expected) == 'number' then if type(err_actual) == 'string' then return tostring(err_expected) == tostring(tonumber(err_actual)), retargs end end return same(state, {err_expected, err_actual, ["n"] = 2}), retargs end local function error_matches(state, arguments, level) local level = (level or 1) + 1 local retargs = util.shallowcopy(arguments) local argcnt = arguments.n local func = arguments[1] local pattern = arguments[2] assert(argcnt > 1, s("assertion.internal.argtolittle", { "error_matches", 2, tostring(argcnt) }), level) assert(util.callable(func), s("assertion.internal.badargtype", { 1, "error_matches", "function or callable object", type(func) }), level) assert(pattern == nil or type(pattern) == "string", s("assertion.internal.badargtype", { 2, "error", "string", type(pattern) }), level) local failure_message local init_arg_num = 3 for i=3,argcnt,1 do if arguments[i] and type(arguments[i]) ~= "boolean" and not tonumber(arguments[i]) then if i == 3 then init_arg_num = init_arg_num + 1 end failure_message = util.tremove(arguments, i) break end end local init = arguments[3] local plain = arguments[4] assert(init == nil or tonumber(init), s("assertion.internal.badargtype", { init_arg_num, "matches", "number", type(arguments[3]) }), level) local ok, err_actual = pcall(func) if type(err_actual) == 'string' then -- remove 'path/to/file:line: ' from string err_actual = err_actual:gsub('^.-:%d+: ', '', 1) end retargs[1] = err_actual arguments.nofmt = {} arguments.n = 2 arguments[1] = (ok and '(no error)' or err_actual) arguments[2] = pattern arguments.nofmt[1] = ok arguments.nofmt[2] = false set_failure_message(state, failure_message) if ok then return not ok, retargs end if err_actual == nil and pattern == nil then return true, {} end -- err_actual must be (convertible to) a string if util.hastostring(err_actual) then err_actual = tostring(err_actual) retargs[1] = err_actual end if type(err_actual) == 'string' then local ok local retargs_ok if plain then retargs_ok = { pattern } ok = (err_actual:find(pattern, init, plain) ~= nil) else retargs_ok = { err_actual:match(pattern, init) } ok = (retargs_ok[1] ~= nil) end if ok then retargs = retargs_ok end return ok, retargs end return false, retargs end local function is_true(state, arguments, level) util.tinsert(arguments, 2, true) set_failure_message(state, arguments[3]) return arguments[1] == arguments[2] end local function is_false(state, arguments, level) util.tinsert(arguments, 2, false) set_failure_message(state, arguments[3]) return arguments[1] == arguments[2] end local function is_type(state, arguments, level, etype) util.tinsert(arguments, 2, "type " .. etype) arguments.nofmt = arguments.nofmt or {} arguments.nofmt[2] = true set_failure_message(state, arguments[3]) return arguments.n > 1 and type(arguments[1]) == etype end local function returned_arguments(state, arguments, level) arguments[1] = tostring(arguments[1]) arguments[2] = tostring(arguments.n - 1) arguments.nofmt = arguments.nofmt or {} arguments.nofmt[1] = true arguments.nofmt[2] = true if arguments.n < 2 then arguments.n = 2 end return arguments[1] == arguments[2] end local function set_message(state, arguments, level) state.failure_message = arguments[1] end local function is_boolean(state, arguments, level) return is_type(state, arguments, level, "boolean") end local function is_number(state, arguments, level) return is_type(state, arguments, level, "number") end local function is_string(state, arguments, level) return is_type(state, arguments, level, "string") end local function is_table(state, arguments, level) return is_type(state, arguments, level, "table") end local function is_nil(state, arguments, level) return is_type(state, arguments, level, "nil") end local function is_userdata(state, arguments, level) return is_type(state, arguments, level, "userdata") end local function is_function(state, arguments, level) return is_type(state, arguments, level, "function") end local function is_thread(state, arguments, level) return is_type(state, arguments, level, "thread") end assert:register("modifier", "message", set_message) assert:register("assertion", "true", is_true, "assertion.same.positive", "assertion.same.negative") assert:register("assertion", "false", is_false, "assertion.same.positive", "assertion.same.negative") assert:register("assertion", "boolean", is_boolean, "assertion.same.positive", "assertion.same.negative") assert:register("assertion", "number", is_number, "assertion.same.positive", "assertion.same.negative") assert:register("assertion", "string", is_string, "assertion.same.positive", "assertion.same.negative") assert:register("assertion", "table", is_table, "assertion.same.positive", "assertion.same.negative") assert:register("assertion", "nil", is_nil, "assertion.same.positive", "assertion.same.negative") assert:register("assertion", "userdata", is_userdata, "assertion.same.positive", "assertion.same.negative") assert:register("assertion", "function", is_function, "assertion.same.positive", "assertion.same.negative") assert:register("assertion", "thread", is_thread, "assertion.same.positive", "assertion.same.negative") assert:register("assertion", "returned_arguments", returned_arguments, "assertion.returned_arguments.positive", "assertion.returned_arguments.negative") assert:register("assertion", "same", same, "assertion.same.positive", "assertion.same.negative") assert:register("assertion", "matches", matches, "assertion.matches.positive", "assertion.matches.negative") assert:register("assertion", "match", matches, "assertion.matches.positive", "assertion.matches.negative") assert:register("assertion", "near", near, "assertion.near.positive", "assertion.near.negative") assert:register("assertion", "equals", equals, "assertion.equals.positive", "assertion.equals.negative") assert:register("assertion", "equal", equals, "assertion.equals.positive", "assertion.equals.negative") assert:register("assertion", "unique", unique, "assertion.unique.positive", "assertion.unique.negative") assert:register("assertion", "error", has_error, "assertion.error.positive", "assertion.error.negative") assert:register("assertion", "errors", has_error, "assertion.error.positive", "assertion.error.negative") assert:register("assertion", "error_matches", error_matches, "assertion.error.positive", "assertion.error.negative") assert:register("assertion", "error_match", error_matches, "assertion.error.positive", "assertion.error.negative") assert:register("assertion", "matches_error", error_matches, "assertion.error.positive", "assertion.error.negative") assert:register("assertion", "match_error", error_matches, "assertion.error.positive", "assertion.error.negative") assert:register("assertion", "truthy", truthy, "assertion.truthy.positive", "assertion.truthy.negative") assert:register("assertion", "falsy", falsy, "assertion.falsy.positive", "assertion.falsy.negative") luassert-1.8.0/src/compatibility.lua000066400000000000000000000000561350545761100175350ustar00rootroot00000000000000return { unpack = table.unpack or unpack, } luassert-1.8.0/src/formatters/000077500000000000000000000000001350545761100163465ustar00rootroot00000000000000luassert-1.8.0/src/formatters/binarystring.lua000066400000000000000000000014121350545761100215620ustar00rootroot00000000000000local format = function (str) if type(str) ~= "string" then return nil end local result = "Binary string length; " .. tostring(#str) .. " bytes\n" local i = 1 local hex = "" local chr = "" while i <= #str do local byte = str:byte(i) hex = string.format("%s%2x ", hex, byte) if byte < 32 then byte = string.byte(".") end chr = chr .. string.char(byte) if math.floor(i/16) == i/16 or i == #str then -- reached end of line hex = hex .. string.rep(" ", 16 * 3 - #hex) chr = chr .. string.rep(" ", 16 - #chr) result = result .. hex:sub(1, 8 * 3) .. " " .. hex:sub(8*3+1, -1) .. " " .. chr:sub(1,8) .. " " .. chr:sub(9,-1) .. "\n" hex = "" chr = "" end i = i + 1 end return result end return format luassert-1.8.0/src/formatters/init.lua000066400000000000000000000127611350545761100200230ustar00rootroot00000000000000-- module will not return anything, only register formatters with the main assert engine local assert = require('luassert.assert') local colors = setmetatable({ none = function(c) return c end },{ __index = function(self, key) local ok, term = pcall(require, 'term') local isatty = io.type(io.stdout) == 'file' and ok and term.isatty(io.stdout) if not ok or not isatty or not term.colors then return function(c) return c end end return function(c) for token in key:gmatch("[^%.]+") do c = term.colors[token](c) end return c end end }) local function fmt_string(arg) if type(arg) == "string" then return string.format("(string) '%s'", arg) end end -- A version of tostring which formats numbers more precisely. local function tostr(arg) if type(arg) ~= "number" then return tostring(arg) end if arg ~= arg then return "NaN" elseif arg == 1/0 then return "Inf" elseif arg == -1/0 then return "-Inf" end local str = string.format("%.20g", arg) if math.type and math.type(arg) == "float" and not str:find("[%.,]") then -- Number is a float but looks like an integer. -- Insert ".0" after first run of digits. str = str:gsub("%d+", "%0.0", 1) end return str end local function fmt_number(arg) if type(arg) == "number" then return string.format("(number) %s", tostr(arg)) end end local function fmt_boolean(arg) if type(arg) == "boolean" then return string.format("(boolean) %s", tostring(arg)) end end local function fmt_nil(arg) if type(arg) == "nil" then return "(nil)" end end local type_priorities = { number = 1, boolean = 2, string = 3, table = 4, ["function"] = 5, userdata = 6, thread = 7 } local function is_in_array_part(key, length) return type(key) == "number" and 1 <= key and key <= length and math.floor(key) == key end local function get_sorted_keys(t) local keys = {} local nkeys = 0 for key in pairs(t) do nkeys = nkeys + 1 keys[nkeys] = key end local length = #t local function key_comparator(key1, key2) local type1, type2 = type(key1), type(key2) local priority1 = is_in_array_part(key1, length) and 0 or type_priorities[type1] or 8 local priority2 = is_in_array_part(key2, length) and 0 or type_priorities[type2] or 8 if priority1 == priority2 then if type1 == "string" or type1 == "number" then return key1 < key2 elseif type1 == "boolean" then return key1 -- put true before false end else return priority1 < priority2 end end table.sort(keys, key_comparator) return keys, nkeys end local function fmt_table(arg, fmtargs) if type(arg) ~= "table" then return end local tmax = assert:get_parameter("TableFormatLevel") local showrec = assert:get_parameter("TableFormatShowRecursion") local errchar = assert:get_parameter("TableErrorHighlightCharacter") or "" local errcolor = assert:get_parameter("TableErrorHighlightColor") or "none" local crumbs = fmtargs and fmtargs.crumbs or {} local cache = {} local type_desc if getmetatable(arg) == nil then type_desc = "(" .. tostring(arg) .. ") " elseif not pcall(setmetatable, arg, getmetatable(arg)) then -- cannot set same metatable, so it is protected, skip id type_desc = "(table) " else -- unprotected metatable, temporary remove the mt local mt = getmetatable(arg) setmetatable(arg, nil) type_desc = "(" .. tostring(arg) .. ") " setmetatable(arg, mt) end local function ft(t, l, with_crumbs) if showrec and cache[t] and cache[t] > 0 then return "{ ... recursive }" end if next(t) == nil then return "{ }" end if l > tmax and tmax >= 0 then return "{ ... more }" end local result = "{" local keys, nkeys = get_sorted_keys(t) cache[t] = (cache[t] or 0) + 1 local crumb = crumbs[#crumbs - l + 1] for i = 1, nkeys do local k = keys[i] local v = t[k] local use_crumbs = with_crumbs and k == crumb if type(v) == "table" then v = ft(v, l + 1, use_crumbs) elseif type(v) == "string" then v = "'"..v.."'" end local ch = use_crumbs and errchar or "" local indent = string.rep(" ",l * 2 - ch:len()) local mark = (ch:len() == 0 and "" or colors[errcolor](ch)) result = result .. string.format("\n%s%s[%s] = %s", indent, mark, tostr(k), tostr(v)) end cache[t] = cache[t] - 1 return result .. " }" end return type_desc .. ft(arg, 1, true) end local function fmt_function(arg) if type(arg) == "function" then local debug_info = debug.getinfo(arg) return string.format("%s @ line %s in %s", tostring(arg), tostring(debug_info.linedefined), tostring(debug_info.source)) end end local function fmt_userdata(arg) if type(arg) == "userdata" then return string.format("(userdata) '%s'", tostring(arg)) end end local function fmt_thread(arg) if type(arg) == "thread" then return string.format("(thread) '%s'", tostring(arg)) end end assert:add_formatter(fmt_string) assert:add_formatter(fmt_number) assert:add_formatter(fmt_boolean) assert:add_formatter(fmt_nil) assert:add_formatter(fmt_table) assert:add_formatter(fmt_function) assert:add_formatter(fmt_userdata) assert:add_formatter(fmt_thread) -- Set default table display depth for table formatter assert:set_parameter("TableFormatLevel", 3) assert:set_parameter("TableFormatShowRecursion", false) assert:set_parameter("TableErrorHighlightCharacter", "*") assert:set_parameter("TableErrorHighlightColor", "none") luassert-1.8.0/src/init.lua000066400000000000000000000007761350545761100156400ustar00rootroot00000000000000local assert = require('luassert.assert') assert._COPYRIGHT = "Copyright (c) 2018 Olivine Labs, LLC." assert._DESCRIPTION = "Extends Lua's built-in assertions to provide additional tests and the ability to create your own." assert._VERSION = "Luassert 1.8.0" -- load basic asserts require('luassert.assertions') require('luassert.modifiers') require('luassert.array') require('luassert.matchers') require('luassert.formatters') -- load default language require('luassert.languages.en') return assert luassert-1.8.0/src/languages/000077500000000000000000000000001350545761100161265ustar00rootroot00000000000000luassert-1.8.0/src/languages/ar.lua000066400000000000000000000032361350545761100172370ustar00rootroot00000000000000local s = require('say') s:set_namespace("ar") s:set("assertion.same.positive", "تُوُقِّعَ تَماثُلُ الكائِنات.\nتَمَّ إدخال:\n %s.\nبَينَما كانَ مِن المُتَوقَّع:\n %s.") s:set("assertion.same.negative", "تُوُقِّعَ إختِلافُ الكائِنات.\nتَمَّ إدخال:\n %s.\nبَينَما كانَ مِن غَيرِ المُتَوقَّع:\n %s.") s:set("assertion.equals.positive", "تُوُقِّعَ أن تَتَساوىْ الكائِنات.\nتمَّ إِدخال:\n %s.\nبَينَما كانَ من المُتَوقَّع:\n %s.") s:set("assertion.equals.negative", "تُوُقِّعَ ألّا تَتَساوىْ الكائِنات.\nتمَّ إِدخال:\n %s.\nبَينَما كانَ مِن غير المُتًوقَّع:\n %s.") s:set("assertion.unique.positive", "تُوُقِّعَ أَنْ يَكونَ الكائِنٌ فَريد: \n%s") s:set("assertion.unique.negative", "تُوُقِّعَ أنْ يَكونَ الكائِنٌ غَيرَ فَريد: \n%s") s:set("assertion.error.positive", "تُوُقِّعَ إصدارُ خطأْ.") s:set("assertion.error.negative", "تُوُقِّعَ عدم إصدارِ خطأ.") s:set("assertion.truthy.positive", "تُوُقِّعَت قيمةٌ صَحيحة، بينما كانت: \n%s") s:set("assertion.truthy.negative", "تُوُقِّعَت قيمةٌ غيرُ صَحيحة، بينما كانت: \n%s") s:set("assertion.falsy.positive", "تُوُقِّعَت قيمةٌ خاطِئة، بَينَما كانت: \n%s") s:set("assertion.falsy.negative", "تُوُقِّعَت قيمةٌ غيرُ خاطِئة، بَينَما كانت: \n%s") luassert-1.8.0/src/languages/de.lua000066400000000000000000000062431350545761100172260ustar00rootroot00000000000000local s = require('say') s:set_namespace('de') s:set("assertion.same.positive", "Erwarte gleiche Objekte.\nGegeben:\n%s\nErwartet:\n%s") s:set("assertion.same.negative", "Erwarte ungleiche Objekte.\nGegeben:\n%s\nNicht erwartet:\n%s") s:set("assertion.equals.positive", "Erwarte dieselben Objekte.\nGegeben:\n%s\nErwartet:\n%s") s:set("assertion.equals.negative", "Erwarte nicht dieselben Objekte.\nGegeben:\n%s\nNicht erwartet:\n%s") s:set("assertion.near.positive", "Erwarte annähernd gleiche Werte.\nGegeben:\n%s\nErwartet:\n%s +/- %s") s:set("assertion.near.negative", "Erwarte keine annähernd gleichen Werte.\nGegeben:\n%s\nNicht erwartet:\n%s +/- %s") s:set("assertion.matches.positive", "Erwarte identische Zeichenketten.\nGegeben:\n%s\nErwartet:\n%s") s:set("assertion.matches.negative", "Erwarte unterschiedliche Zeichenketten.\nGegeben:\n%s\nNicht erwartet:\n%s") s:set("assertion.unique.positive", "Erwarte einzigartiges Objekt:\n%s") s:set("assertion.unique.negative", "Erwarte nicht einzigartiges Objekt:\n%s") s:set("assertion.error.positive", "Es wird ein Fehler erwartet.") s:set("assertion.error.negative", "Es wird kein Fehler erwartet, aber folgender Fehler trat auf:\n%s") s:set("assertion.truthy.positive", "Erwarte, dass der Wert 'wahr' (truthy) ist.\nGegeben:\n%s") s:set("assertion.truthy.negative", "Erwarte, dass der Wert 'unwahr' ist (falsy).\nGegeben:\n%s") s:set("assertion.falsy.positive", "Erwarte, dass der Wert 'unwahr' ist (falsy).\nGegeben:\n%s") s:set("assertion.falsy.negative", "Erwarte, dass der Wert 'wahr' (truthy) ist.\nGegeben:\n%s") s:set("assertion.called.positive", "Erwarte, dass die Funktion %s-mal aufgerufen wird, anstatt %s mal.") s:set("assertion.called.negative", "Erwarte, dass die Funktion nicht genau %s-mal aufgerufen wird.") s:set("assertion.called_at_least.positive", "Erwarte, dass die Funktion mindestens %s-mal aufgerufen wird, anstatt %s-mal") s:set("assertion.called_at_most.positive", "Erwarte, dass die Funktion höchstens %s-mal aufgerufen wird, anstatt %s-mal") s:set("assertion.called_more_than.positive", "Erwarte, dass die Funktion mehr als %s-mal aufgerufen wird, anstatt %s-mal") s:set("assertion.called_less_than.positive", "Erwarte, dass die Funktion weniger als %s-mal aufgerufen wird, anstatt %s-mal") s:set("assertion.called_with.positive", "Erwarte, dass die Funktion mit den gegebenen Parametern aufgerufen wird.") s:set("assertion.called_with.negative", "Erwarte, dass die Funktion nicht mit den gegebenen Parametern aufgerufen wird.") s:set("assertion.returned_with.positive", "Die Funktion wurde nicht mit den Argumenten zurückgegeben.") s:set("assertion.returned_with.negative", "Die Funktion wurde mit den Argumenten zurückgegeben.") s:set("assertion.returned_arguments.positive", "Erwarte den Aufruf mit %s Argument(en), aber der Aufruf erfolgte mit %s") s:set("assertion.returned_arguments.negative", "Erwarte nicht den Aufruf mit %s Argument(en), der Aufruf erfolgte dennoch mit %s") -- errors s:set("assertion.internal.argtolittle", "Die Funktion '%s' erwartet mindestens %s Parameter, gegeben: %s") s:set("assertion.internal.badargtype", "bad argument #%s: Die Funktion '%s' erwartet einen Parameter vom Typ %s, gegeben: %s") luassert-1.8.0/src/languages/en.lua000066400000000000000000000056431350545761100172430ustar00rootroot00000000000000local s = require('say') s:set_namespace('en') s:set("assertion.same.positive", "Expected objects to be the same.\nPassed in:\n%s\nExpected:\n%s") s:set("assertion.same.negative", "Expected objects to not be the same.\nPassed in:\n%s\nDid not expect:\n%s") s:set("assertion.equals.positive", "Expected objects to be equal.\nPassed in:\n%s\nExpected:\n%s") s:set("assertion.equals.negative", "Expected objects to not be equal.\nPassed in:\n%s\nDid not expect:\n%s") s:set("assertion.near.positive", "Expected values to be near.\nPassed in:\n%s\nExpected:\n%s +/- %s") s:set("assertion.near.negative", "Expected values to not be near.\nPassed in:\n%s\nDid not expect:\n%s +/- %s") s:set("assertion.matches.positive", "Expected strings to match.\nPassed in:\n%s\nExpected:\n%s") s:set("assertion.matches.negative", "Expected strings not to match.\nPassed in:\n%s\nDid not expect:\n%s") s:set("assertion.unique.positive", "Expected object to be unique:\n%s") s:set("assertion.unique.negative", "Expected object to not be unique:\n%s") s:set("assertion.error.positive", "Expected a different error.\nCaught:\n%s\nExpected:\n%s") s:set("assertion.error.negative", "Expected no error, but caught:\n%s") s:set("assertion.truthy.positive", "Expected to be truthy, but value was:\n%s") s:set("assertion.truthy.negative", "Expected to not be truthy, but value was:\n%s") s:set("assertion.falsy.positive", "Expected to be falsy, but value was:\n%s") s:set("assertion.falsy.negative", "Expected to not be falsy, but value was:\n%s") s:set("assertion.called.positive", "Expected to be called %s time(s), but was called %s time(s)") s:set("assertion.called.negative", "Expected not to be called exactly %s time(s), but it was.") s:set("assertion.called_at_least.positive", "Expected to be called at least %s time(s), but was called %s time(s)") s:set("assertion.called_at_most.positive", "Expected to be called at most %s time(s), but was called %s time(s)") s:set("assertion.called_more_than.positive", "Expected to be called more than %s time(s), but was called %s time(s)") s:set("assertion.called_less_than.positive", "Expected to be called less than %s time(s), but was called %s time(s)") s:set("assertion.called_with.positive", "Function was not called with the arguments") s:set("assertion.called_with.negative", "Function was called with the arguments") s:set("assertion.returned_with.positive", "Function was not returned with the arguments") s:set("assertion.returned_with.negative", "Function was returned with the arguments") s:set("assertion.returned_arguments.positive", "Expected to be called with %s argument(s), but was called with %s") s:set("assertion.returned_arguments.negative", "Expected not to be called with %s argument(s), but was called with %s") -- errors s:set("assertion.internal.argtolittle", "the '%s' function requires a minimum of %s arguments, got: %s") s:set("assertion.internal.badargtype", "bad argument #%s to '%s' (%s expected, got %s)") luassert-1.8.0/src/languages/fr.lua000066400000000000000000000066111350545761100172440ustar00rootroot00000000000000local s = require('say') s:set_namespace('fr') s:set("assertion.called.positive", "Prévu pour être appelé %s fois(s), mais a été appelé %s fois(s).") s:set("assertion.called.negative", "Prévu de ne pas être appelé exactement %s fois(s), mais ceci a été le cas.") s:set("assertion.called_at_least.positive", "Prévu pour être appelé au moins %s fois(s), mais a été appelé %s fois(s).") s:set("assertion.called_at_most.positive", "Prévu pour être appelé au plus %s fois(s), mais a été appelé %s fois(s).") s:set("assertion.called_more_than.positive", "Devrait être appelé plus de %s fois(s), mais a été appelé %s fois(s).") s:set("assertion.called_less_than.positive", "Devrait être appelé moins de %s fois(s), mais a été appelé %s fois(s).") s:set("assertion.called_with.positive", "La fonction n'a pas été appelée avec les arguments.") s:set("assertion.called_with.negative", "La fonction a été appelée avec les arguments.") s:set("assertion.equals.positive", "Les objets attendus doivent être égaux. \n Argument passé en: \n %s \n Attendu: \n %s.") s:set("assertion.equals.negative", "Les objets attendus ne doivent pas être égaux. \n Argument passé en: \n %s \n Non attendu: \n %s.") s:set("assertion.error.positive", "Une erreur différente est attendue. \n Prise: \n %s \n Attendue: \n %s.") s:set("assertion.error.negative", "Aucune erreur attendue, mais prise: \n %s.") s:set("assertion.falsy.positive", "Assertion supposée etre fausse mais de valeur: \n %s") s:set("assertion.falsy.negative", "Assertion supposée etre vraie mais de valeur: \n %s") -- errors s:set("assertion.internal.argtolittle", "La fonction '%s' requiert un minimum de %s arguments, obtenu: %s.") s:set("assertion.internal.badargtype", "Mauvais argument #%s pour '%s' (%s attendu, obtenu %s).") -- errors s:set("assertion.matches.positive", "Chaînes attendues pour correspondre. \n Argument passé en: \n %s \n Attendu: \n %s.") s:set("assertion.matches.negative", "Les chaînes attendues ne doivent pas correspondre. \n Argument passé en: \n %s \n Non attendu: \n %s.") s:set("assertion.near.positive", "Les valeurs attendues sont proches. \n Argument passé en: \n %s \n Attendu: \n %s +/- %s.") s:set("assertion.near.negative", "Les valeurs attendues ne doivent pas être proches. \n Argument passé en: \n %s \n Non attendu: \n %s +/- %s.") s:set("assertion.returned_arguments.positive", "Attendu pour être appelé avec le(s) argument(s) %s, mais a été appelé avec %s.") s:set("assertion.returned_arguments.negative", "Attendu pour ne pas être appelé avec le(s) argument(s) %s, mais a été appelé avec %s.") s:set("assertion.returned_with.positive", "La fonction n'a pas été retournée avec les arguments.") s:set("assertion.returned_with.negative", "La fonction a été retournée avec les arguments.") s:set("assertion.same.positive", "Les objets attendus sont les mêmes. \n Argument passé en: \n %s \n Attendu: \n %s.") s:set("assertion.same.negative", "Les objets attendus ne doivent pas être les mêmes. \n Argument passé en: \n %s \n Non attendu: \n %s.") s:set("assertion.truthy.positive", "Assertion supposee etre vraie mais de valeur: \n %s") s:set("assertion.truthy.negative", "Assertion supposee etre fausse mais de valeur: \n %s") s:set("assertion.unique.positive", "Objet attendu pour être unique: \n %s.") s:set("assertion.unique.negative", "Objet attendu pour ne pas être unique: \n %s.") luassert-1.8.0/src/languages/ja.lua000066400000000000000000000050541350545761100172270ustar00rootroot00000000000000local s = require('say') s:set_namespace('ja') s:set("assertion.same.positive", "オブジェクトの内容が同一であることが期待されています。\n実際の値:\n%s\n期待されている値:\n%s") s:set("assertion.same.negative", "オブジェクトの内容が同一でないことが期待されています。\n実際の値:\n%s\n期待されていない値:\n%s") s:set("assertion.equals.positive", "オブジェクトが同一であることが期待されています。\n実際の値:\n%s\n期待されている値:\n%s") s:set("assertion.equals.negative", "オブジェクトが同一でないことが期待されています。\n実際の値:\n%s\n期待されていない値:\n%s") s:set("assertion.unique.positive", "オブジェクトがユニークであることが期待されています。:\n%s") s:set("assertion.unique.negative", "オブジェクトがユニークでないことが期待されています。:\n%s") s:set("assertion.error.positive", "エラーが発生することが期待されています。") s:set("assertion.error.negative", "エラーが発生しないことが期待されています。") s:set("assertion.truthy.positive", "真であることが期待されていますが、値は:\n%s") s:set("assertion.truthy.negative", "真でないことが期待されていますが、値は:\n%s") s:set("assertion.falsy.positive", "偽であることが期待されていますが、値は:\n%s") s:set("assertion.falsy.negative", "偽でないことが期待されていますが、値は:\n%s") s:set("assertion.called.positive", "回呼ばれることを期待されていますが、実際には%s回呼ばれています。") s:set("assertion.called.negative", "回呼ばれることを期待されていますが、実際には%s回呼ばれています。") s:set("assertion.called_with.positive", "関数が期待されている引数で呼ばれていません") s:set("assertion.called_with.negative", "関数が期待されている引数で呼ばれています") s:set("assertion.returned_arguments.positive", "期待されている返り値の数は%sですが、実際の返り値の数は%sです。") s:set("assertion.returned_arguments.negative", "期待されていない返り値の数は%sですが、実際の返り値の数は%sです。") -- errors s:set("assertion.internal.argtolittle", "関数には最低%s個の引数が必要ですが、実際の引数の数は: %s") s:set("assertion.internal.badargtype", "bad argument #%s: 関数には%s個の引数が必要ですが、実際に引数の数は: %s") luassert-1.8.0/src/languages/nl.lua000066400000000000000000000026551350545761100172520ustar00rootroot00000000000000local s = require('say') s:set_namespace('nl') s:set("assertion.same.positive", "Verwachtte objecten die vergelijkbaar zijn.\nAangeboden:\n%s\nVerwachtte:\n%s") s:set("assertion.same.negative", "Verwachtte objecten die niet vergelijkbaar zijn.\nAangeboden:\n%s\nVerwachtte niet:\n%s") s:set("assertion.equals.positive", "Verwachtte objecten die hetzelfde zijn.\nAangeboden:\n%s\nVerwachtte:\n%s") s:set("assertion.equals.negative", "Verwachtte objecten die niet hetzelfde zijn.\nAangeboden:\n%s\nVerwachtte niet:\n%s") s:set("assertion.unique.positive", "Verwachtte objecten die uniek zijn:\n%s") s:set("assertion.unique.negative", "Verwachtte objecten die niet uniek zijn:\n%s") s:set("assertion.error.positive", "Verwachtte een foutmelding.") s:set("assertion.error.negative", "Verwachtte geen foutmelding.\n%s") s:set("assertion.truthy.positive", "Verwachtte een 'warige' (thruthy) waarde, maar was:\n%s") s:set("assertion.truthy.negative", "Verwachtte een niet 'warige' (thruthy) waarde, maar was:\n%s") s:set("assertion.falsy.positive", "Verwachtte een 'onwarige' (falsy) waarde, maar was:\n%s") s:set("assertion.falsy.negative", "Verwachtte een niet 'onwarige' (falsy) waarde, maar was:\n%s") -- errors s:set("assertion.internal.argtolittle", "de '%s' functie verwacht minimaal %s parameters, maar kreeg er: %s") s:set("assertion.internal.badargtype", "bad argument #%s: de '%s' functie verwacht een %s als parameter, maar kreeg een: %s") luassert-1.8.0/src/languages/ru.lua000066400000000000000000000025631350545761100172650ustar00rootroot00000000000000local s = require('say') s:set_namespace("ru") s:set("assertion.same.positive", "Ожидали одинаковые объекты.\nПередали:\n%s\nОжидали:\n%s") s:set("assertion.same.negative", "Ожидали разные объекты.\nПередали:\n%s\nНе ожидали:\n%s") s:set("assertion.equals.positive", "Ожидали эквивалентные объекты.\nПередали:\n%s\nОжидали:\n%s") s:set("assertion.equals.negative", "Ожидали не эквивалентные объекты.\nПередали:\n%s\nНе ожидали:\n%s") s:set("assertion.unique.positive", "Ожидали, что объект будет уникальным:\n%s") s:set("assertion.unique.negative", "Ожидали, что объект не будет уникальным:\n%s") s:set("assertion.error.positive", "Ожидали ошибку.") s:set("assertion.error.negative", "Не ожидали ошибку.\n%s") s:set("assertion.truthy.positive", "Ожидали true, но значние оказалось:\n%s") s:set("assertion.truthy.negative", "Ожидали не true, но значние оказалось:\n%s") s:set("assertion.falsy.positive", "Ожидали false, но значние оказалось:\n%s") s:set("assertion.falsy.negative", "Ожидали не false, но значние оказалось:\n%s") luassert-1.8.0/src/languages/ua.lua000066400000000000000000000026611350545761100172430ustar00rootroot00000000000000local s = require('say') s:set_namespace("ua") s:set("assertion.same.positive", "Очікували однакові обєкти.\nПередали:\n%s\nОчікували:\n%s") s:set("assertion.same.negative", "Очікували різні обєкти.\nПередали:\n%s\nНе очікували:\n%s") s:set("assertion.equals.positive", "Очікували еквівалентні обєкти.\nПередали:\n%s\nОчікували:\n%s") s:set("assertion.equals.negative", "Очікували не еквівалентні обєкти.\nПередали:\n%s\nНе очікували:\n%s") s:set("assertion.unique.positive", "Очікували, що обєкт буде унікальним:\n%s") s:set("assertion.unique.negative", "Очікували, що обєкт не буде унікальним:\n%s") s:set("assertion.error.positive", "Очікували помилку.") s:set("assertion.error.negative", "Не очікували помилку.\n%s") s:set("assertion.truthy.positive", "Очікували true, проте значння виявилось:\n%s") s:set("assertion.truthy.negative", "Очікували не true, проте значння виявилось:\n%s") s:set("assertion.falsy.positive", "Очікували false, проте значння виявилось:\n%s") s:set("assertion.falsy.negative", "Очікували не false, проте значння виявилось:\n%s") luassert-1.8.0/src/languages/zh.lua000066400000000000000000000031321350545761100172510ustar00rootroot00000000000000local s = require('say') s:set_namespace('zh') s:set("assertion.same.positive", "希望对象应该相同.\n实际值:\n%s\n希望值:\n%s") s:set("assertion.same.negative", "希望对象应该不相同.\n实际值:\n%s\n不希望与:\n%s\n相同") s:set("assertion.equals.positive", "希望对象应该相等.\n实际值:\n%s\n希望值:\n%s") s:set("assertion.equals.negative", "希望对象应该不相等.\n实际值:\n%s\n不希望等于:\n%s") s:set("assertion.unique.positive", "希望对象是唯一的:\n%s") s:set("assertion.unique.negative", "希望对象不是唯一的:\n%s") s:set("assertion.error.positive", "希望有错误被抛出.") s:set("assertion.error.negative", "希望没有错误被抛出.\n%s") s:set("assertion.truthy.positive", "希望结果为真,但是实际为:\n%s") s:set("assertion.truthy.negative", "希望结果不为真,但是实际为:\n%s") s:set("assertion.falsy.positive", "希望结果为假,但是实际为:\n%s") s:set("assertion.falsy.negative", "希望结果不为假,但是实际为:\n%s") s:set("assertion.called.positive", "希望被调用%s次, 但实际被调用了%s次") s:set("assertion.called.negative", "不希望正好被调用%s次, 但是正好被调用了那么多次.") s:set("assertion.called_with.positive", "希望没有参数的调用函数") s:set("assertion.called_with.negative", "希望有参数的调用函数") -- errors s:set("assertion.internal.argtolittle", "函数'%s'需要最少%s个参数, 实际有%s个参数\n") s:set("assertion.internal.badargtype", "bad argument #%s: 函数'%s'需要一个%s作为参数, 实际为: %s\n") luassert-1.8.0/src/match.lua000066400000000000000000000037241350545761100157650ustar00rootroot00000000000000local namespace = require 'luassert.namespaces' local util = require 'luassert.util' local matcher_mt = { __call = function(self, value) return self.callback(value) == self.mod end, } local state_mt = { __call = function(self, ...) local keys = util.extract_keys("matcher", self.tokens) self.tokens = {} local matcher for _, key in ipairs(keys) do matcher = namespace.matcher[key] or matcher end if matcher then for _, key in ipairs(keys) do if namespace.modifier[key] then namespace.modifier[key].callback(self) end end local arguments = {...} arguments.n = select('#', ...) -- add argument count for trailing nils local matches = matcher.callback(self, arguments, util.errorlevel()) return setmetatable({ name = matcher.name, mod = self.mod, callback = matches, }, matcher_mt) else local arguments = {...} arguments.n = select('#', ...) -- add argument count for trailing nils for _, key in ipairs(keys) do if namespace.modifier[key] then namespace.modifier[key].callback(self, arguments, util.errorlevel()) end end end return self end, __index = function(self, key) for token in key:lower():gmatch('[^_]+') do table.insert(self.tokens, token) end return self end } local match = { _ = setmetatable({mod=true, callback=function() return true end}, matcher_mt), state = function() return setmetatable({mod=true, tokens={}}, state_mt) end, is_matcher = function(object) return type(object) == "table" and getmetatable(object) == matcher_mt end, is_ref_matcher = function(object) local ismatcher = (type(object) == "table" and getmetatable(object) == matcher_mt) return ismatcher and object.name == "ref" end, } local mt = { __index = function(self, key) return rawget(self, key) or self.state()[key] end, } return setmetatable(match, mt) luassert-1.8.0/src/matchers/000077500000000000000000000000001350545761100157665ustar00rootroot00000000000000luassert-1.8.0/src/matchers/composite.lua000066400000000000000000000034411350545761100204750ustar00rootroot00000000000000local assert = require('luassert.assert') local match = require ('luassert.match') local s = require('say') local function none(state, arguments, level) local level = (level or 1) + 1 local argcnt = arguments.n assert(argcnt > 0, s("assertion.internal.argtolittle", { "none", 1, tostring(argcnt) }), level) for i = 1, argcnt do assert(match.is_matcher(arguments[i]), s("assertion.internal.badargtype", { 1, "none", "matcher", type(arguments[i]) }), level) end return function(value) for _, matcher in ipairs(arguments) do if matcher(value) then return false end end return true end end local function any(state, arguments, level) local level = (level or 1) + 1 local argcnt = arguments.n assert(argcnt > 0, s("assertion.internal.argtolittle", { "any", 1, tostring(argcnt) }), level) for i = 1, argcnt do assert(match.is_matcher(arguments[i]), s("assertion.internal.badargtype", { 1, "any", "matcher", type(arguments[i]) }), level) end return function(value) for _, matcher in ipairs(arguments) do if matcher(value) then return true end end return false end end local function all(state, arguments, level) local level = (level or 1) + 1 local argcnt = arguments.n assert(argcnt > 0, s("assertion.internal.argtolittle", { "all", 1, tostring(argcnt) }), level) for i = 1, argcnt do assert(match.is_matcher(arguments[i]), s("assertion.internal.badargtype", { 1, "all", "matcher", type(arguments[i]) }), level) end return function(value) for _, matcher in ipairs(arguments) do if not matcher(value) then return false end end return true end end assert:register("matcher", "none_of", none) assert:register("matcher", "any_of", any) assert:register("matcher", "all_of", all) luassert-1.8.0/src/matchers/core.lua000066400000000000000000000145341350545761100174300ustar00rootroot00000000000000-- module will return the list of matchers, and registers matchers with the main assert engine -- matchers take 1 parameters; -- 1) state -- 2) arguments list. The list has a member 'n' with the argument count to check for trailing nils -- 3) level The level of the error position relative to the called function -- returns; function (or callable object); a function that, given an argument, returns a boolean local assert = require('luassert.assert') local astate = require('luassert.state') local util = require('luassert.util') local s = require('say') local function format(val) return astate.format_argument(val) or tostring(val) end local function unique(state, arguments, level) local deep = arguments[1] return function(value) local list = value for k,v in pairs(list) do for k2, v2 in pairs(list) do if k ~= k2 then if deep and util.deepcompare(v, v2, true) then return false else if v == v2 then return false end end end end end return true end end local function near(state, arguments, level) local level = (level or 1) + 1 local argcnt = arguments.n assert(argcnt > 1, s("assertion.internal.argtolittle", { "near", 2, tostring(argcnt) }), level) local expected = tonumber(arguments[1]) local tolerance = tonumber(arguments[2]) local numbertype = "number or object convertible to a number" assert(expected, s("assertion.internal.badargtype", { 1, "near", numbertype, format(arguments[1]) }), level) assert(tolerance, s("assertion.internal.badargtype", { 2, "near", numbertype, format(arguments[2]) }), level) return function(value) local actual = tonumber(value) if not actual then return false end return (actual >= expected - tolerance and actual <= expected + tolerance) end end local function matches(state, arguments, level) local level = (level or 1) + 1 local argcnt = arguments.n assert(argcnt > 0, s("assertion.internal.argtolittle", { "matches", 1, tostring(argcnt) }), level) local pattern = arguments[1] local init = arguments[2] local plain = arguments[3] local stringtype = "string or object convertible to a string" assert(type(pattern) == "string", s("assertion.internal.badargtype", { 1, "matches", "string", type(arguments[1]) }), level) assert(init == nil or tonumber(init), s("assertion.internal.badargtype", { 2, "matches", "number", type(arguments[2]) }), level) return function(value) local actualtype = type(value) local actual = nil if actualtype == "string" or actualtype == "number" or actualtype == "table" and (getmetatable(value) or {}).__tostring then actual = tostring(value) end if not actual then return false end return (actual:find(pattern, init, plain) ~= nil) end end local function equals(state, arguments, level) local level = (level or 1) + 1 local argcnt = arguments.n assert(argcnt > 0, s("assertion.internal.argtolittle", { "equals", 1, tostring(argcnt) }), level) return function(value) return value == arguments[1] end end local function same(state, arguments, level) local level = (level or 1) + 1 local argcnt = arguments.n assert(argcnt > 0, s("assertion.internal.argtolittle", { "same", 1, tostring(argcnt) }), level) return function(value) if type(value) == 'table' and type(arguments[1]) == 'table' then local result = util.deepcompare(value, arguments[1], true) return result end return value == arguments[1] end end local function ref(state, arguments, level) local level = (level or 1) + 1 local argcnt = arguments.n local argtype = type(arguments[1]) local isobject = (argtype == "table" or argtype == "function" or argtype == "thread" or argtype == "userdata") assert(argcnt > 0, s("assertion.internal.argtolittle", { "ref", 1, tostring(argcnt) }), level) assert(isobject, s("assertion.internal.badargtype", { 1, "ref", "object", argtype }), level) return function(value) return value == arguments[1] end end local function is_true(state, arguments, level) return function(value) return value == true end end local function is_false(state, arguments, level) return function(value) return value == false end end local function truthy(state, arguments, level) return function(value) return value ~= false and value ~= nil end end local function falsy(state, arguments, level) local is_truthy = truthy(state, arguments, level) return function(value) return not is_truthy(value) end end local function is_type(state, arguments, level, etype) return function(value) return type(value) == etype end end local function is_nil(state, arguments, level) return is_type(state, arguments, level, "nil") end local function is_boolean(state, arguments, level) return is_type(state, arguments, level, "boolean") end local function is_number(state, arguments, level) return is_type(state, arguments, level, "number") end local function is_string(state, arguments, level) return is_type(state, arguments, level, "string") end local function is_table(state, arguments, level) return is_type(state, arguments, level, "table") end local function is_function(state, arguments, level) return is_type(state, arguments, level, "function") end local function is_userdata(state, arguments, level) return is_type(state, arguments, level, "userdata") end local function is_thread(state, arguments, level) return is_type(state, arguments, level, "thread") end assert:register("matcher", "true", is_true) assert:register("matcher", "false", is_false) assert:register("matcher", "nil", is_nil) assert:register("matcher", "boolean", is_boolean) assert:register("matcher", "number", is_number) assert:register("matcher", "string", is_string) assert:register("matcher", "table", is_table) assert:register("matcher", "function", is_function) assert:register("matcher", "userdata", is_userdata) assert:register("matcher", "thread", is_thread) assert:register("matcher", "ref", ref) assert:register("matcher", "same", same) assert:register("matcher", "matches", matches) assert:register("matcher", "match", matches) assert:register("matcher", "near", near) assert:register("matcher", "equals", equals) assert:register("matcher", "equal", equals) assert:register("matcher", "unique", unique) assert:register("matcher", "truthy", truthy) assert:register("matcher", "falsy", falsy) luassert-1.8.0/src/matchers/init.lua000066400000000000000000000001371350545761100174350ustar00rootroot00000000000000-- load basic machers require('luassert.matchers.core') require('luassert.matchers.composite') luassert-1.8.0/src/mock.lua000066400000000000000000000031131350545761100156120ustar00rootroot00000000000000-- module will return a mock module table, and will not register any assertions local spy = require 'luassert.spy' local stub = require 'luassert.stub' local function mock_apply(object, action) if type(object) ~= "table" then return end if spy.is_spy(object) then return object[action](object) end for k,v in pairs(object) do mock_apply(v, action) end return object end local mock mock = { new = function(object, dostub, func, self, key) local visited = {} local function do_mock(object, self, key) local mock_handlers = { ["table"] = function() if spy.is_spy(object) or visited[object] then return end visited[object] = true for k,v in pairs(object) do object[k] = do_mock(v, object, k) end return object end, ["function"] = function() if dostub then return stub(self, key, func) elseif self==nil then return spy.new(object) else return spy.on(self, key) end end } local handler = mock_handlers[type(object)] return handler and handler() or object end return do_mock(object, self, key) end, clear = function(object) return mock_apply(object, "clear") end, revert = function(object) return mock_apply(object, "revert") end } return setmetatable(mock, { __call = function(self, ...) -- mock originally was a function only. Now that it is a module table -- the __call method is required for backward compatibility return mock.new(...) end }) luassert-1.8.0/src/modifiers.lua000066400000000000000000000010401350545761100166370ustar00rootroot00000000000000-- module will not return anything, only register assertions/modifiers with the main assert engine local assert = require('luassert.assert') local function is(state) return state end local function is_not(state) state.mod = not state.mod return state end assert:register("modifier", "is", is) assert:register("modifier", "are", is) assert:register("modifier", "was", is) assert:register("modifier", "has", is) assert:register("modifier", "does", is) assert:register("modifier", "not", is_not) assert:register("modifier", "no", is_not) luassert-1.8.0/src/namespaces.lua000066400000000000000000000000531350545761100170000ustar00rootroot00000000000000-- stores the list of namespaces return {} luassert-1.8.0/src/spy.lua000066400000000000000000000136431350545761100155050ustar00rootroot00000000000000-- module will return spy table, and register its assertions with the main assert engine local assert = require('luassert.assert') local util = require('luassert.util') -- Spy metatable local spy_mt = { __call = function(self, ...) local arguments = {...} arguments.n = select('#',...) -- add argument count for trailing nils table.insert(self.calls, util.copyargs(arguments)) local function get_returns(...) local returnvals = {...} returnvals.n = select('#',...) -- add argument count for trailing nils table.insert(self.returnvals, util.copyargs(returnvals)) return ... end return get_returns(self.callback(...)) end } local spy -- must make local before defining table, because table contents refers to the table (recursion) spy = { new = function(callback) callback = callback or function() end if not util.callable(callback) then error("Cannot spy on type '" .. type(callback) .. "', only on functions or callable elements", util.errorlevel()) end local s = setmetatable({ calls = {}, returnvals = {}, callback = callback, target_table = nil, -- these will be set when using 'spy.on' target_key = nil, revert = function(self) if not self.reverted then if self.target_table and self.target_key then self.target_table[self.target_key] = self.callback end self.reverted = true end return self.callback end, clear = function(self) self.calls = {} self.returnvals = {} return self end, called = function(self, times, compare) if times or compare then local compare = compare or function(count, expected) return count == expected end return compare(#self.calls, times), #self.calls end return (#self.calls > 0), #self.calls end, called_with = function(self, args) return util.matchargs(self.calls, args) ~= nil end, returned_with = function(self, args) return util.matchargs(self.returnvals, args) ~= nil end }, spy_mt) assert:add_spy(s) -- register with the current state return s end, is_spy = function(object) return type(object) == "table" and getmetatable(object) == spy_mt end, on = function(target_table, target_key) local s = spy.new(target_table[target_key]) target_table[target_key] = s -- store original data s.target_table = target_table s.target_key = target_key return s end } local function set_spy(state, arguments, level) state.payload = arguments[1] if arguments[2] ~= nil then state.failure_message = arguments[2] end end local function returned_with(state, arguments, level) local level = (level or 1) + 1 local payload = rawget(state, "payload") if payload and payload.returned_with then return state.payload:returned_with(arguments) else error("'returned_with' must be chained after 'spy(aspy)'", level) end end local function called_with(state, arguments, level) local level = (level or 1) + 1 local payload = rawget(state, "payload") if payload and payload.called_with then return state.payload:called_with(arguments) else error("'called_with' must be chained after 'spy(aspy)'", level) end end local function called(state, arguments, level, compare) local level = (level or 1) + 1 local num_times = arguments[1] if not num_times and not state.mod then state.mod = true num_times = 0 end local payload = rawget(state, "payload") if payload and type(payload) == "table" and payload.called then local result, count = state.payload:called(num_times, compare) arguments[1] = tostring(num_times or ">0") util.tinsert(arguments, 2, tostring(count)) arguments.nofmt = arguments.nofmt or {} arguments.nofmt[1] = true arguments.nofmt[2] = true return result elseif payload and type(payload) == "function" then error("When calling 'spy(aspy)', 'aspy' must not be the original function, but the spy function replacing the original", level) else error("'called' must be chained after 'spy(aspy)'", level) end end local function called_at_least(state, arguments, level) local level = (level or 1) + 1 return called(state, arguments, level, function(count, expected) return count >= expected end) end local function called_at_most(state, arguments, level) local level = (level or 1) + 1 return called(state, arguments, level, function(count, expected) return count <= expected end) end local function called_more_than(state, arguments, level) local level = (level or 1) + 1 return called(state, arguments, level, function(count, expected) return count > expected end) end local function called_less_than(state, arguments, level) local level = (level or 1) + 1 return called(state, arguments, level, function(count, expected) return count < expected end) end assert:register("modifier", "spy", set_spy) assert:register("assertion", "returned_with", returned_with, "assertion.returned_with.positive", "assertion.returned_with.negative") assert:register("assertion", "called_with", called_with, "assertion.called_with.positive", "assertion.called_with.negative") assert:register("assertion", "called", called, "assertion.called.positive", "assertion.called.negative") assert:register("assertion", "called_at_least", called_at_least, "assertion.called_at_least.positive", "assertion.called_less_than.positive") assert:register("assertion", "called_at_most", called_at_most, "assertion.called_at_most.positive", "assertion.called_more_than.positive") assert:register("assertion", "called_more_than", called_more_than, "assertion.called_more_than.positive", "assertion.called_at_most.positive") assert:register("assertion", "called_less_than", called_less_than, "assertion.called_less_than.positive", "assertion.called_at_least.positive") return setmetatable(spy, { __call = function(self, ...) return spy.new(...) end }) luassert-1.8.0/src/state.lua000066400000000000000000000057771350545761100160230ustar00rootroot00000000000000-- maintains a state of the assert engine in a linked-list fashion -- records; formatters, parameters, spies and stubs local state_mt = { __call = function(self) self:revert() end } local spies_mt = { __mode = "kv" } local nilvalue = {} -- unique ID to refer to nil values for parameters -- will hold the current state local current -- exported module table local state = {} ------------------------------------------------------ -- Reverts to a (specific) snapshot. -- @param self (optional) the snapshot to revert to. If not provided, it will revert to the last snapshot. state.revert = function(self) if not self then -- no snapshot given, so move 1 up self = current if not self.previous then -- top of list, no previous one, nothing to do return end end if getmetatable(self) ~= state_mt then error("Value provided is not a valid snapshot", 2) end if self.next then self.next:revert() end -- revert formatters in 'last' self.formatters = {} -- revert parameters in 'last' self.parameters = {} -- revert spies/stubs in 'last' for s,_ in pairs(self.spies) do self.spies[s] = nil s:revert() end setmetatable(self, nil) -- invalidate as a snapshot current = self.previous current.next = nil end ------------------------------------------------------ -- Creates a new snapshot. -- @return snapshot table state.snapshot = function() local s = current local new = setmetatable ({ formatters = {}, parameters = {}, spies = setmetatable({}, spies_mt), previous = current, revert = state.revert, }, state_mt) if current then current.next = new end current = new return current end -- FORMATTERS state.add_formatter = function(callback) table.insert(current.formatters, 1, callback) end state.remove_formatter = function(callback, s) s = s or current for i, v in ipairs(s.formatters) do if v == callback then table.remove(s.formatters, i) break end end -- wasn't found, so traverse up 1 state if s.previous then state.remove_formatter(callback, s.previous) end end state.format_argument = function(val, s, fmtargs) s = s or current for _, fmt in ipairs(s.formatters) do local valfmt = fmt(val, fmtargs) if valfmt ~= nil then return valfmt end end -- nothing found, check snapshot 1 up in list if s.previous then return state.format_argument(val, s.previous, fmtargs) end return nil -- end of list, couldn't format end -- PARAMETERS state.set_parameter = function(name, value) if value == nil then value = nilvalue end current.parameters[name] = value end state.get_parameter = function(name, s) s = s or current local val = s.parameters[name] if val == nil and s.previous then -- not found, so check 1 up in list return state.get_parameter(name, s.previous) end if val ~= nilvalue then return val end return nil end -- SPIES / STUBS state.add_spy = function(spy) current.spies[spy] = true end state.snapshot() -- create initial state return state luassert-1.8.0/src/stub.lua000066400000000000000000000061431350545761100156440ustar00rootroot00000000000000-- module will return a stub module table local assert = require 'luassert.assert' local spy = require 'luassert.spy' local util = require 'luassert.util' local unpack = require 'luassert.compatibility'.unpack local stub = {} function stub.new(object, key, ...) if object == nil and key == nil then -- called without arguments, create a 'blank' stub object = {} key = "" end local return_values_count = select("#", ...) local return_values = {...} assert(type(object) == "table" and key ~= nil, "stub.new(): Can only create stub on a table key, call with 2 params; table, key", util.errorlevel()) assert(object[key] == nil or util.callable(object[key]), "stub.new(): The element for which to create a stub must either be callable, or be nil", util.errorlevel()) local old_elem = object[key] -- keep existing element (might be nil!) local fn = (return_values_count == 1 and util.callable(return_values[1]) and return_values[1]) local defaultfunc = fn or function() return unpack(return_values, 1, return_values_count) end local oncalls = {} local callbacks = {} local stubfunc = function(...) local args = {...} args.n = select('#', ...) local match = util.matchargs(oncalls, args) if match then return callbacks[match](...) end return defaultfunc(...) end object[key] = stubfunc -- set the stubfunction local s = spy.on(object, key) -- create a spy on top of the stub function local spy_revert = s.revert -- keep created revert function s.revert = function(self) -- wrap revert function to restore original element if not self.reverted then spy_revert(self) object[key] = old_elem self.reverted = true end return old_elem end s.returns = function(...) local return_args = {...} local n = select('#', ...) defaultfunc = function() return unpack(return_args, 1, n) end return s end s.invokes = function(func) defaultfunc = function(...) return func(...) end return s end s.by_default = { returns = s.returns, invokes = s.invokes, } s.on_call_with = function(...) local match_args = {...} match_args.n = select('#', ...) match_args = util.copyargs(match_args) return { returns = function(...) local return_args = {...} local n = select('#', ...) table.insert(oncalls, match_args) callbacks[match_args] = function() return unpack(return_args, 1, n) end return s end, invokes = function(func) table.insert(oncalls, match_args) callbacks[match_args] = function(...) return func(...) end return s end } end return s end local function set_stub(state, arguments) state.payload = arguments[1] state.failure_message = arguments[2] end assert:register("modifier", "stub", set_stub) return setmetatable(stub, { __call = function(self, ...) -- stub originally was a function only. Now that it is a module table -- the __call method is required for backward compatibility return stub.new(...) end }) luassert-1.8.0/src/util.lua000066400000000000000000000210251350545761100156400ustar00rootroot00000000000000local util = {} function util.deepcompare(t1,t2,ignore_mt,cycles,thresh1,thresh2) local ty1 = type(t1) local ty2 = type(t2) -- non-table types can be directly compared if ty1 ~= 'table' or ty2 ~= 'table' then return t1 == t2 end local mt1 = debug.getmetatable(t1) local mt2 = debug.getmetatable(t2) -- would equality be determined by metatable __eq? if mt1 and mt1 == mt2 and mt1.__eq then -- then use that unless asked not to if not ignore_mt then return t1 == t2 end else -- we can skip the deep comparison below if t1 and t2 share identity if rawequal(t1, t2) then return true end end -- handle recursive tables cycles = cycles or {{},{}} thresh1, thresh2 = (thresh1 or 1), (thresh2 or 1) cycles[1][t1] = (cycles[1][t1] or 0) cycles[2][t2] = (cycles[2][t2] or 0) if cycles[1][t1] == 1 or cycles[2][t2] == 1 then thresh1 = cycles[1][t1] + 1 thresh2 = cycles[2][t2] + 1 end if cycles[1][t1] > thresh1 and cycles[2][t2] > thresh2 then return true end cycles[1][t1] = cycles[1][t1] + 1 cycles[2][t2] = cycles[2][t2] + 1 for k1,v1 in next, t1 do local v2 = t2[k1] if v2 == nil then return false, {k1} end local same, crumbs = util.deepcompare(v1,v2,nil,cycles,thresh1,thresh2) if not same then crumbs = crumbs or {} table.insert(crumbs, k1) return false, crumbs end end for k2,_ in next, t2 do -- only check whether each element has a t1 counterpart, actual comparison -- has been done in first loop above if t1[k2] == nil then return false, {k2} end end cycles[1][t1] = cycles[1][t1] - 1 cycles[2][t2] = cycles[2][t2] - 1 return true end function util.shallowcopy(t) if type(t) ~= "table" then return t end local copy = {} for k,v in next, t do copy[k] = v end return copy end function util.deepcopy(t, deepmt, cache) local spy = require 'luassert.spy' if type(t) ~= "table" then return t end local copy = {} -- handle recursive tables local cache = cache or {} if cache[t] then return cache[t] end cache[t] = copy for k,v in next, t do copy[k] = (spy.is_spy(v) and v or util.deepcopy(v, deepmt, cache)) end if deepmt then debug.setmetatable(copy, util.deepcopy(debug.getmetatable(t, nil, cache))) else debug.setmetatable(copy, debug.getmetatable(t)) end return copy end ----------------------------------------------- -- Copies arguments as a list of arguments -- @param args the arguments of which to copy -- @return the copy of the arguments function util.copyargs(args) local copy = {} local match = require 'luassert.match' local spy = require 'luassert.spy' for k,v in pairs(args) do copy[k] = ((match.is_matcher(v) or spy.is_spy(v)) and v or util.deepcopy(v)) end return { vals = copy, refs = util.shallowcopy(args) } end ----------------------------------------------- -- Finds matching arguments in a saved list of arguments -- @param argslist list of arguments from which to search -- @param args the arguments of which to find a match -- @return the matching arguments if a match is found, otherwise nil function util.matchargs(argslist, args) local function matches(t1, t2, t1refs) local match = require 'luassert.match' for k1,v1 in pairs(t1) do local v2 = t2[k1] if match.is_matcher(v1) then if not v1(v2) then return false end elseif match.is_matcher(v2) then if match.is_ref_matcher(v2) then v1 = t1refs[k1] end if not v2(v1) then return false end elseif (v2 == nil or not util.deepcompare(v1,v2)) then return false end end for k2,v2 in pairs(t2) do -- only check wether each element has a t1 counterpart, actual comparison -- has been done in first loop above local v1 = t1[k2] if v1 == nil then -- no t1 counterpart, so try to compare using matcher if match.is_matcher(v2) then if not v2(v1) then return false end else return false end end end return true end for k,v in ipairs(argslist) do if matches(v.vals, args, v.refs) then return v end end return nil end ----------------------------------------------- -- table.insert() replacement that respects nil values. -- The function will use table field 'n' as indicator of the -- table length, if not set, it will be added. -- @param t table into which to insert -- @param pos (optional) position in table where to insert. NOTE: not optional if you want to insert a nil-value! -- @param val value to insert -- @return No return values function util.tinsert(...) -- check optional POS value local args = {...} local c = select('#',...) local t = args[1] local pos = args[2] local val = args[3] if c < 3 then val = pos pos = nil end -- set length indicator n if not present (+1) t.n = (t.n or #t) + 1 if not pos then pos = t.n elseif pos > t.n then -- out of our range t[pos] = val t.n = pos end -- shift everything up 1 pos for i = t.n, pos + 1, -1 do t[i]=t[i-1] end -- add element to be inserted t[pos] = val end ----------------------------------------------- -- table.remove() replacement that respects nil values. -- The function will use table field 'n' as indicator of the -- table length, if not set, it will be added. -- @param t table from which to remove -- @param pos (optional) position in table to remove -- @return No return values function util.tremove(t, pos) -- set length indicator n if not present (+1) t.n = t.n or #t if not pos then pos = t.n elseif pos > t.n then local removed = t[pos] -- out of our range t[pos] = nil return removed end local removed = t[pos] -- shift everything up 1 pos for i = pos, t.n do t[i]=t[i+1] end -- set size, clean last t[t.n] = nil t.n = t.n - 1 return removed end ----------------------------------------------- -- Checks an element to be callable. -- The type must either be a function or have a metatable -- containing an '__call' function. -- @param object element to inspect on being callable or not -- @return boolean, true if the object is callable function util.callable(object) return type(object) == "function" or type((debug.getmetatable(object) or {}).__call) == "function" end ----------------------------------------------- -- Checks an element has tostring. -- The type must either be a string or have a metatable -- containing an '__tostring' function. -- @param object element to inspect on having tostring or not -- @return boolean, true if the object has tostring function util.hastostring(object) return type(object) == "string" or type((debug.getmetatable(object) or {}).__tostring) == "function" end ----------------------------------------------- -- Find the first level, not defined in the same file as the caller's -- code file to properly report an error. -- @param level the level to use as the caller's source file -- @return number, the level of which to report an error function util.errorlevel(level) local level = (level or 1) + 1 -- add one to get level of the caller local info = debug.getinfo(level) local source = (info or {}).source local file = source while file and (file == source or source == "=(tail call)") do level = level + 1 info = debug.getinfo(level) source = (info or {}).source end if level > 1 then level = level - 1 end -- deduct call to errorlevel() itself return level end ----------------------------------------------- -- Extract modifier and namespace keys from list of tokens. -- @param nspace the namespace from which to match tokens -- @param tokens list of tokens to search for keys -- @return table, list of keys that were extracted function util.extract_keys(nspace, tokens) local namespace = require 'luassert.namespaces' -- find valid keys by coalescing tokens as needed, starting from the end local keys = {} local key = nil local i = #tokens while i > 0 do local token = tokens[i] key = key and (token .. '_' .. key) or token -- find longest matching key in the given namespace local longkey = i > 1 and (tokens[i-1] .. '_' .. key) or nil while i > 1 and longkey and namespace[nspace][longkey] do key = longkey i = i - 1 token = tokens[i] longkey = (token .. '_' .. key) end if namespace.modifier[key] or namespace[nspace][key] then table.insert(keys, 1, key) key = nil end i = i - 1 end -- if there's anything left we didn't recognize it if key then error("luassert: unknown modifier/" .. nspace .. ": '" .. key .."'", util.errorlevel(2)) end return keys end return util