summaryrefslogtreecommitdiff
path: root/Tools/LuaMacro/macro/assert.lua
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2021-11-17 23:03:07 +0800
committerchai <chaifix@163.com>2021-11-17 23:03:07 +0800
commit27d6efb5f5a076f825fe2da1875e0cabaf02b4e7 (patch)
tree44f301110bc2ea742908ed92a78eba0803cd3b60 /Tools/LuaMacro/macro/assert.lua
parentb34310c631989551054d456eb47aaab5ded266a4 (diff)
+ LuaMacro
Diffstat (limited to 'Tools/LuaMacro/macro/assert.lua')
-rw-r--r--Tools/LuaMacro/macro/assert.lua74
1 files changed, 74 insertions, 0 deletions
diff --git a/Tools/LuaMacro/macro/assert.lua b/Tools/LuaMacro/macro/assert.lua
new file mode 100644
index 0000000..b25daaf
--- /dev/null
+++ b/Tools/LuaMacro/macro/assert.lua
@@ -0,0 +1,74 @@
+--- a simple testing framework.
+-- Defines a single statment macro assert_ which has the following syntax:
+--
+-- - assert_ val1 == val2
+-- - assert_ val1 > val2
+-- - assert_ val1 < val2
+-- - assert_ val1 matches val2 (using string matching)
+-- - assert_ val1 throws val2 (ditto, on exception string)
+--
+-- The `==` case has some special forms. If `val2` is `(v1,v2,..)` then
+-- it's assumed that the expression `val1` returns multiple values. `==` will
+-- also do value equality for plain tables. If `val2` is a number given in
+-- %f format (such as 3.14) then it will match `vall` up to that specified
+-- number of digits.
+--
+-- assert_ {one=1,two=2} == {two=2,one=1}
+-- assert_ 'hello' matches '^hell'
+-- assert_ 2 > 1
+-- assert_ ('hello'):find 'll' == (3,4)
+-- assert_ a.x throws 'attempt to index global'
+-- @module macro.assert
+
+local M = require 'macro'
+local relop = {
+ ['=='] = 'eq',
+ ['<'] = 'lt',
+ ['>'] = 'gt'
+}
+
+local function numfmt (x)
+ local int,frac = x:match('(%d+)%.(%d+)')
+ if not frac then return nil end
+ return '%'..#x..'.'..#frac..'f', x
+end
+
+--- assert that two values match the desired relation.
+-- @macro assert_
+M.define('assert_',function(get,put)
+ local testx,tok = get:upto(function(t,v)
+ return relop[t] or (t == 'iden' and (v == 'matches' or v == 'throws'))
+ end)
+ local testy,eos = get:line()
+ local otesty = testy
+ testx = tostring(testx)
+ testy = tostring(testy)
+ local t,v,op = tok[1],tok[2]
+ if relop[t] then
+ op = relop[t]
+ if t == '==' then
+ if testy:match '^%(.+%)$' then
+ testx = 'T_.tuple('..testx..')'
+ testy = 'T_.tuple'..testy
+ elseif #otesty == 1 and otesty[1][1] == 'number' then
+ local num = otesty[1][2]
+ local fmt,num = numfmt(num)
+ if fmt then -- explicit floating-point literal
+ testy = '"'..num..'"'
+ testx = '("'..fmt..'"):format('..testx..')'
+ op = 'match'
+ end
+ end
+ end
+ elseif v == 'matches' then
+ op = 'match'
+ elseif v == 'throws' then
+ op = 'match'
+ testx = 'T_.pcall_no(function() return '..testx..' end)'
+ end
+ return ('T_.assert_%s(%s,%s)%s'):format(op,testx,testy,tostring(eos))
+end)
+
+return function()
+ return "T_ = require 'macro.lib.test'"
+end