├── .gitignore ├── .travis.yml ├── COPYING.txt ├── Readme.md ├── documentation.adoc ├── documentation.html ├── perf ├── benchmark_ref.perf1.lua ├── lzw.perf1.lua ├── lzw.perf2.lua ├── peg.perf1.lua └── sha2.perf1.lua ├── src ├── appendfile.lua ├── argcheck.lua ├── bitpad.lua ├── clearfile.lua ├── cliparse.lua ├── clone.lua ├── combinetab.lua ├── copyfile.lua ├── countiter.lua ├── csvish.lua ├── csvishout.lua ├── datestd.lua ├── deepsame.lua ├── differencetab.lua ├── escapeshellarg.lua ├── factory.lua ├── filenamesplit.lua ├── flatarray.lua ├── get.lua ├── hexdecode.lua ├── hexencode.lua ├── intern.lua ├── intersecationtab.lua ├── iscallable.lua ├── isreadable.lua ├── jsonish.lua ├── jsonishout.lua ├── keysort.lua ├── lambda.lua ├── lineposition.lua ├── localbind.lua ├── locktable.lua ├── logline.lua ├── lzw.lua ├── measure.lua ├── memo.lua ├── new_module_scratch.lua ├── object.lua ├── pathpart.lua ├── peg.lua ├── rawhtml.lua ├── rawmark.lua ├── readfile.lua ├── searchluakeyword.lua ├── serialize.lua ├── sha2.lua ├── shellcommand.lua ├── simplepath.lua ├── stepdebug.lua ├── subbytebase.lua ├── tapfail.lua ├── taptest.lua ├── templua.lua ├── timeprof.lua ├── toposort.lua ├── trimstring.lua ├── tuple.lua ├── uniontab.lua └── valueprint.lua ├── test ├── appendfile.ex1.lua ├── argcheck.ex1.lua ├── bitpad.ex1.lua ├── clearfile.ex1.lua ├── cliparse.ex1.lua ├── clone.ex1.lua ├── combinetab.ex1.lua ├── copyfile.ex1.lua ├── countiter.ex1.lua ├── csvish.ex1.lua ├── csvishout.ex1.lua ├── datestd.ex1.lua ├── deepsame.ex1.lua ├── differencetab.ex1.lua ├── escapeshellarg.ex1.lua ├── factory.ex1.lua ├── filenamesplit.ex1.lua ├── flatarray.ex1.lua ├── get.ex1.lua ├── hexdecode.ex1.lua ├── hexencode.ex1.lua ├── intern.ex1.lua ├── intersecationtab.ex1.lua ├── iscallable.ex1.lua ├── isreadable.ex1.lua ├── jsonish.ex1.lua ├── jsonishout.ex1.lua ├── keysort.ex1.lua ├── lambda.ex1.lua ├── lineposition.ex1.lua ├── localbind.ex1.lua ├── locktable.ex1.lua ├── logline.ex1.lua ├── lzw.ex1.lua ├── measure.ex1.lua ├── memo.ex1.lua ├── new_module_scratch.ex1.lua ├── object.ex1.lua ├── pathpart.ex1.lua ├── peg.ex1.lua ├── rawhtml.ex1.lua ├── rawmark.ex1.lua ├── readfile.ex1.lua ├── searchluakeyword.ex1.lua ├── serialize.ex1.lua ├── sha2.ex1.lua ├── shellcommand.ex1.lua ├── simplepath.ex1.lua ├── stepdebug.ex1.lua ├── subbytebase.ex1.lua ├── tapfail.ex1.lua ├── taptest.ex1.lua ├── templua.ex1.lua ├── testhelper.lua ├── timeprof.ex1.lua ├── toposort.ex1.lua ├── trimstring.ex1.lua ├── tuple.ex1.lua ├── uniontab.ex1.lua └── valueprint.ex1.lua └── tool ├── asciidoctor.min.js ├── climint.lua ├── debugger_stdinout.lua ├── editor-ace.js ├── luasnip.lua └── luasniputil.lua /.gitignore: -------------------------------------------------------------------------------- 1 | out_* 2 | tmp_* 3 | bck/* 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | env: 4 | global: 5 | - LUA_PATH="./?.lua;./src/?.lua;./test/?.lua;./tool/?.lua" LUA_CPATH="./?.so;./src/?.so;./test/?.so;./tool/?.so;./lib?.so;./src/lib?.so;./test/lib?.so;./tool/lib?.so" 6 | 7 | branches: 8 | only: 9 | - master 10 | 11 | install: 12 | - wget http://www.lua.org/ftp/lua-5.3.5.tar.gz 13 | - tar -xzf lua-5.3.5.tar.gz 14 | - cd lua-5.3.5 15 | - make linux 16 | - sudo make install 17 | - cd .. 18 | 19 | script: 20 | - lua tool/luasniputil.lua 21 | 22 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | LuaSnip 3 | ------- 4 | 5 | LuaSnip is a collection of utility functions for lua. The main features are: 6 | 7 | - Simple and short modules 8 | - Each module is contained in a file without dependencies: you can just drop it 9 | in your project and start to use it. 10 | - Single file containing all the documentation and all the code: you can discover LuaSnip modules here, and copy-and-paste code directly. 11 | 12 | For a deeper introduction, implementation details and modules reference, you 13 | can continue [here](documentation.adoc). 14 | 15 | If you would like to try LuaSnip, there is the online, client-side 16 | [Playground](https://raw.githack.com/pocomane/clientsideutil/master/build/luasnip_playground.html) 17 | 18 | LuaSnip is strongly ispired by [Lua Zero Dependency 19 | Functions](https://github.com/aiq/luazdf). 20 | 21 | All the code is released under the [UNLICENSE](http://unlicense.org), as 22 | described in the [COPYING](COPYING.txt) file. It is provided without any 23 | warranty. 24 | 25 | -------------------------------------------------------------------------------- /documentation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LuaSnip Documentation 5 | 6 | 7 | 8 | 9 | 10 | 18 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /perf/benchmark_ref.perf1.lua: -------------------------------------------------------------------------------- 1 | return function(a) 2 | return a 3 | end 4 | -------------------------------------------------------------------------------- /perf/lzw.perf1.lua: -------------------------------------------------------------------------------- 1 | local lzw = require 'lzw' 2 | 3 | local s = {} 4 | for k = 1, 20000 do 5 | s[1+#s] = string.char(math.random(0, 255)) 6 | end 7 | for k = 1, 100000-#s do 8 | s[1+#s] = string.char(k%256) 9 | end 10 | s = table.concat(s) 11 | 12 | return function() 13 | local enc, dec = lzw() 14 | local x = enc(s)..enc() 15 | end 16 | -------------------------------------------------------------------------------- /perf/lzw.perf2.lua: -------------------------------------------------------------------------------- 1 | local lzw = require 'lzw' 2 | 3 | local s = {} 4 | for k = 1, 20000 do 5 | s[1+#s] = string.char(math.random(0, 255)) 6 | end 7 | for k = 1, 100000-#s do 8 | s[1+#s] = string.char(k%256) 9 | end 10 | s = table.concat(s) 11 | 12 | local e = lzw() 13 | local r = e(s)..e() 14 | 15 | return function() 16 | local enc, dec = lzw() 17 | local y = dec(r) 18 | -- assert(s==y) 19 | end 20 | -------------------------------------------------------------------------------- /perf/peg.perf1.lua: -------------------------------------------------------------------------------- 1 | 2 | local peg = require 'peg' 3 | 4 | local number = peg.PAT'%-?[0-9]+' 5 | 6 | local factor_operator = peg.PAT'%*' / peg.PAT'/' 7 | local term_operator = peg.PAT'%+' / peg.PAT'%-' 8 | 9 | local expression = peg.COM() 10 | 11 | local sub_expression = peg.PAT'%(' + expression + peg.PAT'%)' 12 | local factor = number / sub_expression 13 | local term = factor + (factor_operator + factor) ^0 14 | 15 | expression.EXT( term + (term_operator + term)^0) 16 | 17 | local toplevel = expression 18 | 19 | local base = "(1+2)*(-3-4)/50" 20 | base = base .. '*(' .. base .. '*(' .. base .. '))' 21 | base = base .. '+(' .. base .. '+(' .. base .. '))' 22 | local good = '0+(' .. (base .. '+' .. base .. '*'):rep(10) .. base .. ')' 23 | local bad = '(' .. good 24 | 25 | return function() 26 | local last = toplevel(good) 27 | if last ~= #good then error("text not parsed") end 28 | local last = toplevel(bad) 29 | if last ~= nil then error("error not catched") end 30 | end 31 | 32 | -------------------------------------------------------------------------------- /perf/sha2.perf1.lua: -------------------------------------------------------------------------------- 1 | local sha2 = require 'sha2' 2 | 3 | local data = ('x'):rep(1024) 4 | 5 | return function() 6 | return sha2( data ) 7 | end 8 | -------------------------------------------------------------------------------- /src/appendfile.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = appendfile 4 | 5 | [source,lua] 6 | ---- 7 | function appendfile( path, data [, prefix [, suffix]] ) --> res, err 8 | ---- 9 | 10 | This function will append the datas to a file. 11 | 12 | The file path is specified by the `path` string, while the `data` can be passed 13 | as a single string or an array of strings i.e. multiple chunks to be appended. 14 | 15 | Two strings can be optionally passed: `prefix` and `suffix`. They will be 16 | written before and after each chunk of data. 17 | 18 | This function will return `true` if it successed, otherwise it will return `nil` 19 | plus an error message. 20 | 21 | == Example 22 | 23 | [source,lua,example] 24 | ---- 25 | local appendfile = require "appendfile" 26 | 27 | os.remove( "appendfile.txt" ) 28 | 29 | appendfile( "appendfile.txt", "123" ) 30 | assert( "123" == io.open("appendfile.txt"):read("a") ) 31 | 32 | appendfile( "appendfile.txt", {"a","b"}, "<", ">" ) 33 | assert( "123" == io.open("appendfile.txt"):read("a") ) 34 | 35 | ---- 36 | 37 | ]===] 38 | 39 | local function appendfile( path, data, prefix, suffix ) --> res, err 40 | 41 | local function writeorclose( f, data ) 42 | local res, err = f:write( data ) 43 | if err then f:close() end 44 | return res, err 45 | end 46 | 47 | local d, derr = io.open( path, "a+b" ) 48 | if derr then 49 | return nil, "Can not create or open destination file. "..derr 50 | end 51 | 52 | local ok, err = d:seek( "end" ) 53 | if err then 54 | d:close() 55 | return nil, err 56 | end 57 | 58 | if "string" == type( data ) then 59 | data = { data } 60 | end 61 | 62 | -- Output loop 63 | for i = 1, #data do 64 | 65 | if prefix then 66 | ok, err = writeorclose( d, prefix ) 67 | if err then return ok, err end 68 | end 69 | 70 | ok, err = writeorclose( d, data[ i ] ) 71 | if err then return ok, err end 72 | 73 | if suffix then 74 | ok, err = writeorclose( d, suffix ) 75 | if err then return ok, err end 76 | end 77 | end 78 | 79 | return d:close() 80 | end 81 | 82 | return appendfile 83 | -------------------------------------------------------------------------------- /src/argcheck.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = argcheck 4 | 5 | [source,lua] 6 | ---- 7 | function argcheck( specTab , ... ) --> wrapFunc 8 | ---- 9 | 10 | This function return error if the argument specification in the table `specTab` 11 | does not match with the rest of the arguments. 12 | 13 | `specTab` must be an array of strings. Each one is the expected lua type of a 14 | following argument (as returned from the standard `type` function). The number 15 | of the following arguments must be equal to the length of the array. 16 | 17 | The main use case is as the first line of a user defined function. In that 18 | case an error corresponds to wrong arguments passed by the caller of the 19 | caller of `argcheck`. So its stack position is reported as the source of the 20 | error i.e. two stack level above `argcheck`. 21 | 22 | == Example 23 | 24 | [source,lua,example] 25 | ---- 26 | local argcheck = require 'argcheck' 27 | 28 | local _, err = pcall(function() 29 | argcheck({'number','string','boolean'}, 1, false, false) 30 | end) 31 | 32 | assert( err:match 'Invalid argument #2 type%. Must be string not boolean%.$' ) 33 | 34 | ---- 35 | 36 | ]===] 37 | 38 | local function argcheck( specTab, ... ) --> wrapFunc 39 | local arg = table.pack(...) 40 | local argn = arg.n 41 | if #specTab ~= argn then error('Invalid number of arguments. Must be '.. #specTab..' not '.. argn ..'.', 3) end 42 | for a = 1, argn do 43 | local argtype, exptype = type(arg[a]), specTab[a] 44 | if argtype ~= exptype then 45 | error('Invalid argument #'..a..' type. Must be '..exptype..' not '..argtype..'.', 2) 46 | end 47 | end 48 | end 49 | 50 | return argcheck 51 | -------------------------------------------------------------------------------- /src/bitpad.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = bitpad 4 | 5 | [source,lua] 6 | ---- 7 | function bitpad( padInt, bitInt, inStr [, outmapSeq] [, inmapSeq] [,offsetInt]) --> outStr, supbitInt 8 | ---- 9 | 10 | Add or remove padding from the byte sequence in the string `inStr`. `padInt` is the 11 | number of bit to add or remove, while `bitInt` it the number of bit after which 12 | the insertion/removal is repeated. If `inStr` is positive the bits are added, 13 | otherwise they are removed. 14 | 15 | For example, `bitpad( 1, 2, ...` will add 1 padding bit each 2 input bit, 16 | while `bitpad( -1, 2, ...` will remove one bit each 2 input bit. 17 | 18 | The `offsetInt` argument specify the first bit that must be added or 19 | removed. The very first bit is used by default. 20 | 21 | All the added bit will be set to `0`, while bit of any value can be removed. 22 | 23 | The tow optional parameter `outmapSeq` and `inmapSeq` are two maps that will be 24 | applied to each byte, before any processing (`inmapSeq`) or after all the 25 | processing (`outMapSeq`) 26 | 27 | The ouput will be returned in the `outStr` string. If the last bit do not fill 28 | a byte, the appropriate number of `0` will be added at end of the data. The 29 | number of added `0` is returned as the last returned value `supbitInt`. 30 | 31 | == Example 32 | 33 | [source,lua,example] 34 | ---- 35 | local bitpad = require 'bitpad' 36 | 37 | assert( bitpad(7, 1, '\x0F') == '\x00\x00\x00\x00\x01\x01\x01\x01' ) 38 | assert( bitpad(-7, 1, '\x01\x01\x01\x01\x01\x01\x01\x01') == '\xFF' ) 39 | 40 | ---- 41 | 42 | ]===] 43 | 44 | local function bitpad( pad, bit, str, map, imap, off ) 45 | if not bit then bit = 1 end 46 | if not pad then pad = 8 - (bit % 8) end 47 | local result = '' 48 | 49 | local removing = false 50 | if pad < 0 then 51 | pad = - pad 52 | removing = true 53 | end 54 | 55 | local out_count = 0 56 | local appending = false 57 | local procbit = pad 58 | if off then 59 | appending = true 60 | procbit = off 61 | end 62 | local store = 0 63 | local i = 0 64 | local inlast = 0 65 | local inbit = 0 66 | 67 | -- Bitloop 68 | while true do 69 | 70 | -- Get new input byte as needed 71 | if inbit <= 0 then 72 | i = i + 1 73 | inlast = str:byte(i) 74 | if not inlast then break end 75 | if imap then 76 | local x = imap[inlast+1] 77 | inlast = (x and x:byte()) or inlast 78 | end 79 | inbit = 8 80 | end 81 | 82 | -- Calculate number of appendable bits 83 | local appbit = procbit 84 | if appbit > inbit then appbit = inbit end 85 | if appbit + out_count > 8 then appbit = 8 - out_count end 86 | 87 | -- Make space into the output for the next bits 88 | if not removing or appending then 89 | store = (store << appbit) & 0xFF 90 | out_count = out_count + appbit 91 | end 92 | 93 | -- Copy the next bits from the input 94 | if appending then 95 | local mask = ((~0) << (8-appbit)) & 0xFF 96 | store = store | ((mask & inlast ) >> (8- appbit)) 97 | end 98 | 99 | -- Discard from the input the bits that were already processed 100 | if removing or appending then 101 | inbit = inbit - appbit 102 | inlast = (inlast << appbit) & 0xFF 103 | end 104 | 105 | -- Select bit handle mode for the next iteration 106 | procbit = procbit - appbit 107 | if procbit <= 0 then 108 | if appending then 109 | appending = false 110 | procbit = pad 111 | else 112 | appending = true 113 | procbit = bit 114 | end 115 | end 116 | 117 | -- Generate output byte 118 | if out_count >= 8 then 119 | result = result .. (map and map[store+1] or string.char(store)) 120 | store = 0 121 | out_count = 0 122 | end 123 | end 124 | 125 | -- Generate odd-bit byte 126 | local bitadd = 0 127 | if out_count > 0 then 128 | bitadd = 8 - out_count 129 | store = (store << bitadd) & 0xFF 130 | result = result .. (map and map[store+1] or string.char(store)) 131 | end 132 | 133 | return result, bitadd 134 | end 135 | 136 | return bitpad 137 | -------------------------------------------------------------------------------- /src/clearfile.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = clearfile 4 | 5 | [source,lua] 6 | ---- 7 | function clearfile( pathStr ) --> statusBool, errorStr 8 | ---- 9 | 10 | Create a empty file at path specified by the `pathStr` string. If the file 11 | exists its content will be deleted. 12 | 13 | It will return `true` if the file is created/cleared correctly. Nil otherwise, 14 | with the additional error string `errorStr`. 15 | 16 | == Example 17 | 18 | [source,lua,example] 19 | ---- 20 | local clearfile = require 'clearfile' 21 | 22 | os.remove( 'tmp.txt' ) 23 | 24 | clearfile'tmp.txt' 25 | assert( "" == io.open("tmp.txt","r"):read("a") ) 26 | 27 | io.open("tmp.txt","w"):write("a") 28 | 29 | clearfile'tmp.txt' 30 | assert( "" == io.open("tmp.txt","r"):read("a") ) 31 | 32 | ---- 33 | ]===] 34 | 35 | local function clearfile( pathStr ) --> statusBool, errorStr 36 | local f, err = io.open( pathStr, 'wb' ) 37 | if not f or err then return nil, err end 38 | local s, err = f:write( '' ) 39 | f:close() 40 | if not s then return nil, err end 41 | return true 42 | end 43 | 44 | return clearfile 45 | -------------------------------------------------------------------------------- /src/cliparse.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = cliparse 4 | 5 | [source,lua] 6 | ---- 7 | function cliparse( argArr [, defaultStr] ) --> parsedTab 8 | ---- 9 | 10 | Simple function to parse command line arguments, that must be passed as the array 11 | of string `arrArg`. 12 | 13 | All the arguments are collected in the output `parsedTab`. Each flag or option 14 | became a key of the table, while some arguments may be collected as values. 15 | Three type of arguments are supported: 16 | 17 | - `-aBc` - Will generate a key for each character (e.g. 'a') with an 18 | empty-table value. 19 | - `--key` - a key will be generate with the whole identifier (e.g. 'key') and 20 | an empty table is used as value; if the next argument does not start with '-' 21 | it will be appended in the table. 22 | - `--key=value`, `--key:value`, `-key=value` or `-key:value` - will generate a 23 | key with the suffix (e.g. 'key'); a table 24 | will be generated as value, containing the found suffix (e.g. 'value'). 25 | 26 | For the last two forms, if the same key is found more time, each value is 27 | appended into the table. 28 | 29 | All the arguments not associated to any key, will be collected under the 30 | default empty string (i.e. ''). The additional argument string `defaultStr` can 31 | be used to override this default. 32 | 33 | == Example 34 | 35 | [source,lua,example] 36 | ---- 37 | local cliparse = require 'cliparse' 38 | 39 | local opt = cliparse{'a','b'} 40 | assert( opt[''] ~= 'a') 41 | assert( opt[''][1] == 'a') 42 | assert( opt[''][2] == 'b') 43 | 44 | local opt = cliparse{'-a','-b','c','-xy','d'} 45 | assert( opt[''] ~= nil ) 46 | assert( opt.a ~= nil ) 47 | assert( opt.b ~= nil ) 48 | assert( opt.x ~= nil ) 49 | assert( opt.y ~= nil ) 50 | assert( opt.a[1] == nil ) 51 | assert( opt.b[1] == nil ) 52 | assert( opt[''][1] == 'c' ) 53 | assert( opt[''][2] == 'd' ) 54 | assert( opt.x[1] == nil ) 55 | assert( opt.y[1] == nil ) 56 | 57 | local opt = cliparse{'--aa','--bb','c','--dd','e','f'} 58 | assert( opt[''] ~= nil ) 59 | assert( opt.aa ~= nil ) 60 | assert( opt.bb ~= nil ) 61 | assert( opt.dd ~= nil ) 62 | assert( opt.bb[1] == 'c' ) 63 | assert( opt.dd[1] == 'e' ) 64 | assert( opt[''][1] == 'f' ) 65 | 66 | local opt = cliparse{'--aa=x','--bb:y','--cc=p','--cc=q','u'} 67 | assert( opt[''] ~= nil ) 68 | assert( opt.aa ~= nil ) 69 | assert( opt.bb ~= nil ) 70 | assert( opt.aa[1] == 'x' ) 71 | assert( opt.bb[1] == 'y' ) 72 | assert( opt.cc[1] == 'p' ) 73 | assert( opt.cc[2] == 'q' ) 74 | assert( opt[''][1] == 'u' ) 75 | ---- 76 | 77 | ]===] 78 | 79 | local function addvalue( p, k, value ) 80 | local prev = p[k] 81 | if not prev then prev = {} end 82 | if 'table' ~= type(value) then 83 | prev[1+#prev] = value 84 | else 85 | for v = 1, #value do 86 | prev[1+#prev] = value[v] 87 | end 88 | end 89 | p[k] = prev 90 | end 91 | 92 | local function cliparse( args, default_option ) 93 | 94 | if not args then args = {} end 95 | if not default_option then default_option = '' end 96 | local result = {} 97 | 98 | local append = default_option 99 | for _, arg in ipairs(args) do 100 | if 'string' == type( arg ) then 101 | local done = false 102 | 103 | -- CLI: --key=value, --key:value, -key=value, -key:value 104 | if not done then 105 | local key, value = arg:match('^%-%-?([^-][^ \t\n\r=:]*)[=:]([^ \t\n\r]*)$') 106 | if key and value then 107 | done = true 108 | addvalue(result, key, value) 109 | end 110 | end 111 | 112 | -- CLI: --key 113 | if not done then 114 | local keyonly = arg:match('^%-%-([^-][^ \t\n\r=:]*)$') 115 | if keyonly then 116 | done = true 117 | if not result[keyonly] then 118 | addvalue(result, keyonly, {}) 119 | end 120 | append = keyonly 121 | end 122 | end 123 | 124 | -- CLI: -kKj 125 | if not done then 126 | local flags = arg:match('^%-([^-][^ \t\n\r=:]*)$') 127 | if flags then 128 | done = true 129 | for i = 1, #flags do 130 | local key = flags:sub(i,i) 131 | addvalue(result, key, {}) 132 | end 133 | end 134 | end 135 | 136 | -- CLI: value 137 | if not done then 138 | addvalue(result, append, arg) 139 | append = default_option 140 | end 141 | end 142 | end 143 | 144 | return result 145 | end 146 | 147 | return cliparse 148 | -------------------------------------------------------------------------------- /src/clone.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = clone 4 | 5 | [source,lua] 6 | ---- 7 | function clone( sourceTab, depthNum ) --> clonedTab 8 | ---- 9 | 10 | This function will return the `clonedTab` table, that is a duplicate of the 11 | `sourceTab` table. The duplicated table is a different one but it has the same 12 | content. Any contained table will be recursively duplicated, both if it is a 13 | key or a value. 14 | 15 | The optional `depthNum` number defines the depth level at which the sub-tables 16 | must be duplicated. Deeper tables are copied by reference. If it is 0, the 17 | original table will be returned. If it is 1, any sub-table are copied by 18 | reference. When nil all the sub-tables, at any levels, will be duplicated. 19 | 20 | == Example 21 | 22 | [source,lua,example] 23 | ---- 24 | 25 | local clone = require 'clone' 26 | 27 | local ref = {} 28 | ref.ref = ref 29 | local origin = {a="a", b={b="b"}, ref=ref, [ref]="ref"} 30 | 31 | local cloned = clone(origin) 32 | 33 | assert( cloned ~= origin ) 34 | 35 | assert( cloned.a == "a" ) 36 | 37 | -- assert( cloned.b ~= origin.b ) -- TODO : FIX ! Stocastic failures 38 | assert( cloned.b.b == "b" ) 39 | 40 | assert( cloned.ref ~= origin.ref ) 41 | assert( cloned.ref.ref == cloned.ref ) 42 | 43 | assert( cloned[cloned.ref] == "ref" ) 44 | 45 | local ref = {} 46 | ref.ref = ref 47 | local origin = {b={b="b"}} 48 | 49 | local cloned = clone(origin, 1) 50 | 51 | assert( cloned ~= origin ) 52 | assert( cloned.b == origin.b ) 53 | 54 | ---- 55 | 56 | ]===] 57 | 58 | local function shallow_copy( depth, cloned, toclone ) 59 | local source = toclone[#toclone] 60 | if not source then return end 61 | toclone[#toclone]=nil 62 | 63 | local root = cloned[ source ] 64 | if not root then 65 | root = {} 66 | cloned[ source ] = root 67 | 68 | for k, v in pairs( source ) do 69 | root[k] = v 70 | 71 | if not depth or depth > 1 then 72 | if type(k) == 'table' then 73 | toclone[1+#toclone] = k 74 | end 75 | 76 | if type(v) == 'table' then 77 | toclone[1+#toclone] = v 78 | end 79 | end 80 | end 81 | 82 | return shallow_copy( depth and depth-1, cloned, toclone ) 83 | end 84 | end 85 | 86 | local function link_clones( cloned ) 87 | for _, tolink in pairs(cloned) do 88 | 89 | local K, V = {}, {} 90 | for k, v in pairs( tolink ) do 91 | local newk = cloned[k] 92 | local newv = cloned[v] 93 | 94 | if newk then 95 | tolink[k] = nil 96 | 97 | -- Note: New key adding is postponed since it is forbidden 98 | -- during iteration 99 | K[#K+1] = newk or k 100 | V[#V+1] = newv or v 101 | 102 | elseif newv then 103 | tolink[k] = newv 104 | end 105 | end 106 | 107 | for i = 1, #K do 108 | tolink[K[i]] = V[i] 109 | end 110 | end 111 | end 112 | 113 | local function clone( sourceTab, depthNum ) 114 | if depthNum == 0 then return sourceTab end 115 | if depthNum and depthNum < 1 then return sourceTab end 116 | local toclone = {sourceTab} 117 | local cloned = {} 118 | shallow_copy( depthNum, cloned, toclone ) 119 | link_clones( cloned ) 120 | return cloned[sourceTab] 121 | end 122 | 123 | return clone 124 | -------------------------------------------------------------------------------- /src/combinetab.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = combinetab 4 | 5 | [source,lua] 6 | ---- 7 | function combinetab( firstTab, secondTab[, ...], combFunc ) 8 | ---- 9 | 10 | The `combFunc` function will be called for each combination of the input table 11 | list `firstTab, secondTab, ...`. 12 | 13 | A single combination is generated selecting for each key of any input table, 14 | the value from one of the tables. All the combinations will be considered 15 | exactly one time. An absent key will be considered as another possible 16 | value: 'nil'. 17 | 18 | 19 | == Example 20 | 21 | [source,lua,example] 22 | ---- 23 | 24 | local combinetab = require 'combinetab' 25 | 26 | local r, n = {}, 0 27 | local function tcol(x) 28 | local t = {} 29 | for k,v in pairs(x) do t[k] = v end 30 | n = n + 1 31 | r[n] = t 32 | end 33 | 34 | combinetab( {k='a',x='a'}, {k='b'}, tcol ) 35 | 36 | assert( #r == 4 ) 37 | assert( r[1].k == 'a' ) 38 | assert( r[1].x == 'a' ) 39 | assert( r[2].k == 'b' ) 40 | assert( r[2].x == 'a' ) 41 | assert( r[3].k == 'a' ) 42 | assert( r[3].x == nil ) 43 | assert( r[4].k == 'b' ) 44 | assert( r[4].x == nil ) 45 | 46 | ---- 47 | 48 | ]===] 49 | 50 | local function combinetab(...) 51 | local n = select('#',...) 52 | local f = select(n,...) 53 | n = n -1 54 | c = {} 55 | cc = 0 56 | for i=1,n do 57 | for k in pairs((select(i,...))) do 58 | if not c[k] then 59 | c[1+#c] = k 60 | cc = cc + 1 61 | c[k] = true 62 | end 63 | end 64 | end 65 | table.sort( c ) 66 | local s = {} 67 | for i = 1,cc do s[i] = 1 end 68 | while s[cc] <= n do 69 | local a = {} 70 | for i = 1,cc do 71 | local k = c[i] 72 | a[k] = select(s[i],...)[k] 73 | end 74 | f(a) 75 | s[1] = s[1] + 1 76 | for i = 2,cc do -- carry 77 | if s[i-1] <= n then 78 | break 79 | else 80 | s[i-1] = 1 81 | s[i] = s[i] + 1 82 | end 83 | end 84 | end 85 | end 86 | 87 | return combinetab 88 | -------------------------------------------------------------------------------- /src/copyfile.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = copyfile 4 | 5 | [source,lua] 6 | ---- 7 | function copyfile( src, dst ) --> res, err 8 | ---- 9 | 10 | This function copy the file at the path specified by the `src` string to to the 11 | file at the 12 | path specified by the `dst` string. 13 | 14 | It will return `true` if the copy successes, otherwise `nil` plus an error string. 15 | 16 | == Example 17 | 18 | [source,lua,example] 19 | ---- 20 | local copyfile = require "copyfile" 21 | 22 | local data = tostring(math.random()*os.time()) 23 | 24 | os.remove('s.txt') 25 | local s = io.open('s.txt','w') 26 | s:write(data) 27 | s:close() 28 | 29 | os.remove('d.txt') 30 | copyfile( 's.txt', 'd.txt') 31 | 32 | local d = io.open('d.txt','r') 33 | local copied = d:read('a') 34 | d:close() 35 | 36 | assert( data == copied ) 37 | 38 | ---- 39 | 40 | ]===] 41 | 42 | local function copyfile( src, dst ) --> ok, err 43 | 44 | local function checkerror( ... ) 45 | local msg = "" 46 | for m = 1, select( "#", ... ) do 47 | local p = select( m, ... ) 48 | if p ~= nil then 49 | msg = msg..p..". " 50 | end 51 | end 52 | if msg == "" then return true end 53 | return nil, msg 54 | end 55 | 56 | local s, serr = io.open( src, "rb" ) 57 | if serr then 58 | return checkerror( "Can not open source file", serr ) 59 | end 60 | 61 | local d, derr = io.open( dst, "wb" ) 62 | if not d then 63 | s, serr = s:close() 64 | return checkerror( "Can not create destination file" , derr, serr ) 65 | end 66 | 67 | -- Copy loop 68 | while true do 69 | buf, serr = s:read( 1024 ) 70 | if serr or not buf then break end 71 | ok, derr = d:write( buf ) 72 | if derr then break end 73 | end 74 | if serr or derr then 75 | return checkerror( "Error while copying", serr, derr ) 76 | end 77 | 78 | s, serr = s:close() 79 | d, derr = d:close() 80 | return checkerror( serr, derr ) 81 | end 82 | 83 | return copyfile 84 | -------------------------------------------------------------------------------- /src/countiter.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = countiter 4 | 5 | [source,lua] 6 | ---- 7 | local function countiter( ... ) --> countInt 8 | ---- 9 | 10 | Count the number of iteration generated by a iterator. The argument must be the 11 | same varargs a `for in` loop. It will return the number of iteration. 12 | 13 | E.g. `countiter(pairs(tab))` will count the number of key in the table `tab`. 14 | 15 | == Example 16 | 17 | [source,lua,example] 18 | ---- 19 | 20 | local countiter = require 'countiter' 21 | 22 | assert( 3 == countiter( pairs{ 1, 2, c='2' }) ) 23 | 24 | ---- 25 | 26 | ]===] 27 | 28 | local function countiter( ... ) --> countInt 29 | local countInt = 0 30 | if select('#', ...) ~= 0 then 31 | for _ in ... do 32 | countInt = countInt + 1 33 | end 34 | end 35 | return countInt 36 | end 37 | 38 | return countiter 39 | -------------------------------------------------------------------------------- /src/csvish.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = csvish 4 | 5 | [source,lua] 6 | ---- 7 | function csvish( csvStr ) --> datTab 8 | ---- 9 | 10 | This is a very simple parser for a Comma Separed Value (CSV) file format. The 11 | record separator is the newline, while the field separator is the semicolon. A 12 | field containing a separators can be quoted with the double quote. The double 13 | quote itself can be escaped with `""`. 14 | 15 | It takes the `csvStr` string containing the CSV data, and it return the table 16 | `datTab` containing the same data as an array. Each item represents a CSV 17 | record. The item is an array by itself containing the fields as a string. 18 | 19 | 20 | == Example 21 | 22 | [source,lua,example] 23 | ---- 24 | local csvish = require 'csvish' 25 | 26 | local data = csvish [[ 27 | a;b;c 28 | d;;e;f; 29 | "g;\"" 30 | ]] 31 | 32 | assert( data[1][1] == 'a' ) 33 | assert( data[1][2] == 'b' ) 34 | assert( data[1][3] == 'c' ) 35 | assert( data[1][4] == nil ) 36 | assert( data[2][1] == 'd' ) 37 | assert( data[2][2] == '' ) 38 | assert( data[2][3] == 'e' ) 39 | assert( data[2][4] == 'f' ) 40 | assert( data[3][1] == 'g;\\"' ) 41 | assert( data[3][2] == nil ) 42 | 43 | ---- 44 | 45 | ]===] 46 | 47 | local function string_char_to_decimal( c ) 48 | return string.format( '\\%d', c:byte( 1,1 )) 49 | end 50 | 51 | local function string_decimal_to_char( d ) 52 | return string.char( tonumber( d )) 53 | end 54 | 55 | local function csvish( csv ) 56 | 57 | -- Protect quoted text 58 | local csv = csv:gsub('"(.-)"', function( quote ) 59 | if quote == '' then return string_char_to_decimal( '"' ) end 60 | return quote:gsub('[\\\n\r;"]', string_char_to_decimal ) 61 | end) 62 | 63 | local result = {} 64 | 65 | -- Loop over records and fields 66 | for line in csv:gmatch('([^\n\r]*)') do 67 | local record 68 | for field in line:gmatch('([^;]*)') do 69 | 70 | -- New record as needed 71 | if not record then 72 | record = {} 73 | result[1+#result] = record 74 | end 75 | 76 | -- Expand quoted/protected text 77 | field = field:gsub('\\(%d%d?%d?)', string_decimal_to_char) 78 | 79 | -- Append the new field 80 | record[1+#record] = field 81 | end 82 | end 83 | 84 | return result 85 | end 86 | 87 | return csvish 88 | -------------------------------------------------------------------------------- /src/csvishout.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = csvishout 4 | 5 | [source,lua] 6 | ---- 7 | function csvishout( datTab[, outFunc] ) --> csvStr 8 | ---- 9 | 10 | Generate the Comma Separed Value (CSV) rapresentation `csvStr` of the input array 11 | `datTab`. The ouput will be CSV string containing a list record. Each record is 12 | itself a list of fields. The record separator is the newline while the field 13 | separator is the semicolon. 14 | 15 | If a field contains a newlines ora a semicolons, it will be quoted with double 16 | quote (`"`). The double quote itself will be escaped with the sequence 17 | `""`. 18 | 19 | If an `outFunc` is passed, it is called on each output row. It this case the 20 | returned value will be always nil. 21 | 22 | == Example 23 | 24 | [source,lua,example] 25 | ---- 26 | local csvishout = require 'csvishout' 27 | 28 | assert( csvishout{{'a','b','c'},{'"\n;','ok'}} == 'a;b;c\n"""\n;";ok\n' ) 29 | 30 | ---- 31 | 32 | ]===] 33 | 34 | local function csvishout( tab, outFunc ) 35 | local result = '' 36 | for _, record in ipairs(tab) do 37 | if 'table' == type(record) then 38 | local first = true 39 | for _, field in ipairs(record) do 40 | if not first then result = result .. ';' end 41 | first = false 42 | field = tostring(field) 43 | if field:match('[;\n"]') then 44 | field = field:gsub('"','""') 45 | field = '"' .. field .. '"' 46 | end 47 | result = result .. field 48 | end 49 | result = result .. '\n' 50 | if outFunc then 51 | outFunc(result) 52 | result = '' 53 | end 54 | end 55 | end 56 | if outFunc then return nil end 57 | return result 58 | end 59 | 60 | return csvishout 61 | -------------------------------------------------------------------------------- /src/deepsame.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = deepsame 4 | 5 | [source,lua] 6 | ---- 7 | function deepsame( firstTab, secondTab ) --> sameBool 8 | ---- 9 | 10 | Deep comparison of the two tables `firstTab` and `secondTab`. It will return 11 | `true` if they contain recursively the same data, otherwise `false`. 12 | 13 | == Example 14 | 15 | [source,lua,example] 16 | ---- 17 | local deepsame = require 'deepsame' 18 | 19 | local t = {1,2,3} 20 | 21 | assert( true == deepsame({ 22 | [t] = t, 23 | }, { 24 | [{1,2,3}] = {1,2,3}, 25 | })) 26 | 27 | assert( false == deepsame({ 28 | [t] = t, 29 | }, { 30 | [{1,2}] = {1,2,3}, 31 | })) 32 | 33 | ---- 34 | 35 | ]===] 36 | 37 | local deepsame 38 | 39 | local function keycheck( k, t, s ) 40 | local r = t[k] 41 | if r ~= nil then return r end 42 | if 'table' ~= type(k) then return nil end 43 | for tk, tv in pairs( t ) do 44 | if deepsame( k, tk, s ) then 45 | r = tv 46 | break 47 | end 48 | end 49 | return r 50 | end 51 | 52 | function deepsame( a, b, s ) 53 | if not s then s = {} end 54 | if a == b then return true end 55 | if 'table' ~= type( a ) then return false end 56 | if 'table' ~= type( b ) then return false end 57 | 58 | if s[ a ] == b or s[ b ] == a then return true end 59 | s[ a ] = b 60 | s[ b ] = a 61 | 62 | local ca = 0 63 | for ak, av in pairs( a ) do 64 | ca = ca + 1 65 | local o = keycheck( ak, b, s ) 66 | if o == nil then return false end 67 | end 68 | 69 | local cb = 0 70 | for bk, bv in pairs( b ) do 71 | cb = cb + 1 72 | local o = keycheck( bk, a, s ) 73 | if o == nil then return false end 74 | 75 | if not deepsame( bv, o, s ) then return false end 76 | end 77 | 78 | if cb ~= ca then return false end 79 | 80 | s[ a ] = nil 81 | s[ b ] = nil 82 | return true 83 | end 84 | 85 | return deepsame 86 | -------------------------------------------------------------------------------- /src/differencetab.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = differencetable 4 | 5 | [source,lua] 6 | ---- 7 | function differencetab( firstTab, secondTab ) --> differenceTab 8 | ---- 9 | 10 | It returns a table that contain the keys present in the `firstTab` table but 11 | not in the `secondTab` table. 12 | 13 | No checks are performed on the associated values. 14 | 15 | == Example 16 | 17 | [source,lua,example] 18 | ---- 19 | local differencetab = require 'differencetab' 20 | 21 | local diff = differencetab({a='a',b='b',c='c'},{a='A',d='d'}) 22 | 23 | assert( diff.b == 'b' ) 24 | assert( diff.c == 'c' ) 25 | 26 | local c = 0 27 | for _ in pairs(diff) do c = c + 1 end 28 | assert( c == 2 ) 29 | 30 | ---- 31 | 32 | ]===] 33 | 34 | local function differencetab( firstTab, secondTab ) --> differenceTab 35 | local differenceTab = {} 36 | if not firstTab then return differenceTab end 37 | if not secondTab then 38 | for k, v in pairs(firstTab) do differenceTab[k] = v end 39 | return differenceTab 40 | end 41 | for k, v in pairs(firstTab) do 42 | if not secondTab[k] then 43 | differenceTab[k] = v 44 | end 45 | end 46 | return differenceTab 47 | end 48 | 49 | return differencetab 50 | -------------------------------------------------------------------------------- /src/escapeshellarg.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = escapeshellarg 4 | 5 | [source,lua] 6 | ---- 7 | function escapeshellarg( str ) --> esc 8 | ---- 9 | 10 | Adds double quotes around the `str` string and quotes/escapes any existing 11 | double quotes allowing you to pass the result `esc` string directly to a shell 12 | function and having it be treated as a single safe argument. 13 | 14 | This function should be used to escape individual arguments to shell functions 15 | coming from user input. 16 | 17 | == Example 18 | 19 | [source,lua,example] 20 | ---- 21 | local escapeshellarg = require "escapeshellarg" 22 | 23 | local esced = escapeshellarg(" '") 24 | 25 | local lua = 'lua' 26 | for a = 0, -99, -1 do 27 | if not arg[a] then break end 28 | lua = arg[a] 29 | end 30 | 31 | os.remove('tmp.tmp') 32 | os.execute(lua..' -e "io.open([[tmp.tmp]],[[w]]):write(arg[0]);os.exit()" '..esced) 33 | 34 | assert( " '" == io.open('tmp.tmp','r'):read('a') ) 35 | 36 | ---- 37 | 38 | ]===] 39 | 40 | local quote_function 41 | 42 | local function escapeshellarg( str ) --> esc 43 | 44 | local function posix_quote_argument(str) 45 | if not str:match('[^%a%d%.%-%+=/,:]') then 46 | return str 47 | else 48 | str = str:gsub( "[$`\"\\]", "\\%1" ) 49 | return '"' .. str .. '"' 50 | end 51 | end 52 | 53 | local function windows_quote_argument(str) 54 | str = str:gsub('[%%&\\^<>|]', '^%1') 55 | str = str:gsub('"', "\\%1") 56 | str = str:gsub('[ \t][ \t]*', '"%1"') 57 | return str 58 | end 59 | 60 | if not quote_function then 61 | quote_function = windows_quote_argument 62 | local shell = os.getenv('SHELL') 63 | if shell then 64 | if '/' == shell:sub(1,1) and 'sh' == shell:sub(-2, -1) then 65 | quote_function = posix_quote_argument 66 | end 67 | end 68 | end 69 | 70 | return quote_function(str) 71 | end 72 | 73 | return escapeshellarg 74 | -------------------------------------------------------------------------------- /src/factory.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = factory 4 | 5 | [source,lua] 6 | ---- 7 | function factory( initFunc ) --> buildFunc, checkFunc 8 | ---- 9 | 10 | This module create the `buildFunc` construction function, and the `checkFunc` 11 | checker function. These functions can be used in a class/mixin pattern: calling 12 | `buildFunc` just means to construct an object of a given class/mixin. 13 | 14 | The `buildFunc`: 15 | 16 | [source,lua] 17 | ---- 18 | function buildFunc( initTab ) --> objectTab[, error] 19 | ---- 20 | 21 | calls the `initFunc` on the `initTab` (or a new one if `nil` is passed). 22 | `buildFunc` return the first two results of `initFunc`, if one of them is not 23 | nil. If both are nil, `buildFunc` returns `initTab` as `objectTab` and nil as 24 | `error`. 25 | 26 | The `checkFunc` can be used in two ways: 27 | 28 | [source,lua] 29 | ---- 30 | function checkFunc( aTab ) --> truthnessBool 31 | function checkFunc( 'all' ) --> iterator 32 | ---- 33 | 34 | In the first form, it takes any `aTab` table as input and checks if it was 35 | constructed with the associated `buildFunc`. In the second form, i.e. when the 36 | string `'all'` is passed as argument, it returns an iterator to be used in a 37 | for/in loop. The iteration will span all the tables constructed with the 38 | associated `buildFunc` that are not already collected by the GC. 39 | 40 | To "Inherit" a method you can simply call the `buildFunc` of the base object 41 | from the initializer of the derived one. 42 | 43 | Please note that a method/field can be removed from the object after its 44 | creation. To avoid this, the constructor have to deal with the __index 45 | metamethod of the returned table. In the same way a more conventional 46 | inheritance behaviour can be implemented. 47 | 48 | == Example 49 | 50 | [source,lua,example] 51 | ---- 52 | local factory = require 'factory' 53 | 54 | local make2DPoint, is2DPoint = factory(function(ins) 55 | local x, y = ins[1], ins[2] 56 | ins.scale = ins.scale or 1 57 | 58 | function ins:getX() return self.scale * x end 59 | function ins:getY() return self.scale * y end 60 | 61 | function ins:getR2() return self.scale * ( x*x + y+y ) end 62 | end) 63 | 64 | local make3DPoint, is3DPoint = factory(function(ins) 65 | make2DPoint(ins) 66 | ins.get2DR2 = ins.getR2 67 | local z = ins[3] 68 | 69 | function ins:getZ() return self.scale * z end 70 | 71 | function ins:getR2() return ins:get2DR2() + self.scale * z*z end 72 | end) 73 | 74 | local p2d = make2DPoint { 1, 2 } 75 | 76 | assert( is2DPoint( p2d ) == true ) 77 | assert( is3DPoint( p2d ) == false ) 78 | assert( p2d:getR2() == 5 ) 79 | 80 | p2d.scale = 2 81 | 82 | assert( p2d:getR2() == 10 ) 83 | 84 | local p3d = make3DPoint { 1, 2, 3 } 85 | 86 | assert( is2DPoint( p3d ) == true ) 87 | assert( is3DPoint( p3d ) == true ) 88 | 89 | assert( p3d:getR2() == 14 ) 90 | 91 | p3d.scale = 2 92 | 93 | assert( p3d:getR2() == 28 ) 94 | ---- 95 | 96 | ]===] 97 | 98 | --[[ 99 | 100 | -- TODO : super accessor IDEA : 101 | local function method_accessor( obj ) 102 | local result = {} 103 | for k, v in pairs( obj ) do 104 | if 'function' == type( v ) then 105 | result[ k ] = v 106 | end 107 | end 108 | return setmetatable( result, { __index = obj, __newindex = obj, }) 109 | end 110 | 111 | -- TODO : super accessor IDEA USAGE : 112 | local make3DPoint, is3DPoint = factory(function(ins) 113 | make2DPoint(ins) 114 | local super = method_accessor(ins) 115 | local z = ins[3] 116 | function ins:getZ() return self.scale * z end 117 | function ins:getR2() return super:getR2() + self.scale * z*z end 118 | end) 119 | 120 | --]] 121 | 122 | local type, select, setmetatable = type, select, setmetatable 123 | 124 | local function factory( initializer ) 125 | 126 | local made_here = setmetatable({},{__mode='kv'}) 127 | 128 | local function checker(i) 129 | if i == 'all' then 130 | return pairs( made_here ) 131 | else 132 | return made_here[i] or false 133 | end 134 | end 135 | 136 | local function constructor( instance ) 137 | instance = instance or {} 138 | made_here[instance] = true 139 | 140 | local err = nil 141 | if initializer then 142 | local protect = instance 143 | instance, err = initializer( instance ) 144 | if nil == instance then instance = protect end 145 | end 146 | 147 | made_here[instance] = true 148 | 149 | return instance, err 150 | end 151 | return constructor, checker 152 | end 153 | 154 | return factory 155 | -------------------------------------------------------------------------------- /src/filenamesplit.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = filenamesplit 4 | 5 | [source,lua] 6 | ---- 7 | function filenamesplit( filepathStr ) --> pathStr, nameStr, extStr 8 | ---- 9 | 10 | Split a file path string `filepathStr` into the following strings: the folder 11 | path `pathStr`, filename `nameStr` and extension `extStr`. 12 | 13 | Note that `pathStr` contains the trailing separator, and the `extStr` contains 14 | the dot prefix. In this way you can get the original string cocatenating the 15 | three results. 16 | 17 | The valid path separators in the string are '/' and '\'. 18 | 19 | == Example 20 | 21 | [source,lua,example] 22 | ---- 23 | local filenamesplit = require 'filenamesplit' 24 | 25 | local a, b, c = filenamesplit'/path/path/name.ext' 26 | 27 | assert( a == '/path/path/' ) 28 | assert( b == 'name' ) 29 | assert( c == '.ext' ) 30 | 31 | ---- 32 | 33 | 34 | ]===] 35 | 36 | local function filenamesplit( str ) --> pathStr, nameStr, extStr 37 | if not str then str = '' end 38 | 39 | local pathStr, rest = str:match('^(.*[/\\])(.-)$') 40 | if not pathStr then 41 | pathStr = '' 42 | rest = str 43 | end 44 | 45 | if not rest then return pathStr, '', '' end 46 | 47 | local nameStr, extStr = rest:match('^(.*)(%..-)$') 48 | if not nameStr then 49 | nameStr = rest 50 | extStr = '' 51 | end 52 | 53 | return pathStr, nameStr, extStr 54 | end 55 | 56 | return filenamesplit 57 | -------------------------------------------------------------------------------- /src/flatarray.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = flatarray 4 | 5 | [source,lua] 6 | ---- 7 | function flatarray( inTab[, depthInt] ) --> outTab 8 | ---- 9 | 10 | Recursively expands the nested array in the input array `inTab` array and 11 | return the result in the `outTab` array. The max depth level `depthInt` can be 12 | passed. 13 | 14 | == Example 15 | 16 | [source,lua,example] 17 | ---- 18 | local flatarray = require 'flatarray' 19 | 20 | local flat = flatarray({1,{2,{3}},{{{4,5}}}}, 2) 21 | 22 | assert( flat[1] == 1 ) 23 | assert( flat[2] == 2 ) 24 | assert( flat[3] == 3 ) 25 | assert( flat[4][1] == 4 ) 26 | assert( flat[4][2] == 5 ) 27 | 28 | ---- 29 | 30 | ]===] 31 | 32 | local function flatarray( inTab, depthInt ) --> outTab 33 | local outTab = {} 34 | local n = 0 35 | local redo = false 36 | for _, v in ipairs( inTab ) do 37 | if 'table' == type(v) then 38 | for _, w in ipairs( v ) do 39 | n = n + 1 40 | outTab[n] = w 41 | if 'table' == type(w) then redo = true end 42 | end 43 | else 44 | n = n + 1 45 | outTab[n] = v 46 | end 47 | end 48 | if not redo then return outTab end 49 | if depthInt and depthInt <= 1 then return outTab end 50 | return flatarray( outTab, depthInt and depthInt-1 ) 51 | end 52 | 53 | return flatarray 54 | -------------------------------------------------------------------------------- /src/get.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = get 4 | 5 | [source,lua] 6 | ---- 7 | function get( parent [, ...] ) --> content 8 | ---- 9 | 10 | Get content trashing any access error. In case of access error, nil plus 11 | an error messate are returned. The `parent` lua value is recursively 12 | searched for the field passed as subsequent arguments. 13 | 14 | Note: the __index metamethod is used when found. 15 | 16 | == Example 17 | 18 | [source,lua,example] 19 | ---- 20 | local get = require 'get' 21 | 22 | local data = {a={b={c='d'}}} 23 | assert( 'd' == get(data,'a','b','c')) 24 | assert( nil == get(data,'a','x','c')) 25 | 26 | ---- 27 | 28 | ]===] 29 | 30 | local select = select 31 | local pcall = pcall 32 | 33 | local function get_rec(count, parent, child, ...) 34 | return count < 2 and parent or get_rec(count-1, parent[child], ...) 35 | end 36 | 37 | return function(...) -- get 38 | local ok, data = pcall(function(...) 39 | return get_rec(select('#', ...), ...) 40 | end, ...) 41 | local result = ok and data or nil 42 | return result, not ok and data or nil 43 | end 44 | -------------------------------------------------------------------------------- /src/hexdecode.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = hexdecode 4 | 5 | [source,lua] 6 | ---- 7 | function hexdecode( inputStr ) --> hexStr 8 | ---- 9 | 10 | This function will encode an ASCII Hexadecimal string `inputStr` into a binary 11 | sequence. 12 | 13 | The input string must be composed of a sequence of digit or upper case letters 14 | from 'A' to 'F'. 15 | 16 | For each two bytes in the input, a byte of the output `hexStr` string is 17 | generated. 18 | 19 | == Example 20 | 21 | [source,lua,example] 22 | ---- 23 | local hexdecode = require 'hexdecode' 24 | 25 | assert( hexdecode '10BA' == '\x10\xBA' ) 26 | 27 | ---- 28 | 29 | ]===] 30 | 31 | local function hexdecode( hexStr ) --> dataStr 32 | return hexStr:gsub( "..?", function( h ) 33 | return string.char(tonumber(h, 16)) 34 | end) 35 | end 36 | 37 | return hexdecode 38 | -------------------------------------------------------------------------------- /src/hexencode.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = hexencode 4 | 5 | [source,lua] 6 | ---- 7 | function hexencode( inputStr ) --> binStr 8 | ---- 9 | 10 | This function will return the hexadecimal rapresentation `binStr` of the data 11 | passed as the input string `inputStr`. The input is interpreted as binary data, 12 | whyle the output will be a string composed by an even sequence of digit or 13 | upper case 14 | letters from 'A' to 'F'. Each pair represent a subsequent byte in the input 15 | string. 16 | 17 | == Example 18 | 19 | [source,lua,example] 20 | ---- 21 | local hexencode = require 'hexencode' 22 | 23 | assert( hexencode '\x10\xBA' == '10BA' ) 24 | 25 | ---- 26 | 27 | ]===] 28 | 29 | local function hexencode( dataStr ) --> hexStr 30 | return dataStr:gsub( ".", function( c ) 31 | return string.format( "%02X", string.byte( c )) 32 | end) 33 | end 34 | 35 | return hexencode 36 | -------------------------------------------------------------------------------- /src/intern.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = intern 4 | 5 | [source,lua] 6 | ---- 7 | function intern( ... ) --> `refTab` 8 | ---- 9 | 10 | This function interns the list of arguments, i.e. it generates a reference 11 | table `refTab` for each possible list. When it is called multiple times with 12 | the same list, it will return the same reference. All the reference are 13 | automatically garbage collected when no more used. 14 | 15 | == Inspired by 16 | 17 | * http://lua-users.org/wiki/SimpleTuples 18 | 19 | == Example 20 | 21 | [source,lua,example] 22 | ---- 23 | local intern = require 'intern' 24 | 25 | local int = intern() 26 | 27 | local a = int( 1, nil, 0/0, 3 ) 28 | local b = int( 1, nil, 0/0, 2 ) 29 | local c = int( 1, nil, 0/0, 2 ) 30 | 31 | assert( a ~= b ) 32 | assert( b == c ) 33 | 34 | ---- 35 | 36 | ]===] 37 | 38 | local function intern() --> reference 39 | 40 | local rawget, rawset, select, setmetatable = 41 | rawget, rawset, select, setmetatable, select 42 | local NIL, NAN = {}, {} 43 | 44 | local internmeta = { 45 | __index = function() error('Can not access interned content directly.', 2) end, 46 | __newindex = function() error('Can not cahnge or add contents to a intern.', 2) end, 47 | } 48 | 49 | local internstore = setmetatable( {}, { __mode = "kv" } ) 50 | 51 | -- A map from child to parent is used to protect the internstore table's contents. 52 | -- In this way, they will he collected only when all the cildren are collected 53 | -- in turn. 54 | local parent = setmetatable( {}, { __mode = 'k' }) 55 | 56 | return function( ... ) 57 | local currentintern = internstore 58 | for a = 1, select( '#', ... ) do 59 | 60 | -- Get next intern field. Replace un-storable contents. 61 | local tonext = select( a, ... ) 62 | if tonext ~= tonext then tonext = NAN end 63 | if tonext == nil then tonext = NIL end 64 | 65 | -- Get or create the correspondent sub-intern 66 | local subintern = rawget( currentintern, tonext ) 67 | if subintern == nil then 68 | 69 | subintern = setmetatable( {}, internmeta ) 70 | parent[subintern] = currentintern 71 | rawset( currentintern, tonext, subintern ) 72 | end 73 | 74 | currentintern = subintern 75 | end 76 | return currentintern 77 | end 78 | end 79 | 80 | return intern 81 | -------------------------------------------------------------------------------- /src/intersecationtab.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = intersecationtab 4 | 5 | [source,lua] 6 | ---- 7 | function intersecationtab( firstTab, secondTab, selectFunc ) --> intersecationTab 8 | ---- 9 | 10 | Creates the `intersecationTab` table that contain the keys shared by the 11 | `firstTab` and `secondTab` tables. By default, the value of the first table 12 | will be used as value in the result. 13 | 14 | The `selectFunc` function may be optionally passed to select which value to 15 | associate to the key. It will be called with the two value associated to the 16 | same key in the two argument table. Its result will be used in the 17 | intersecation table. 18 | 19 | == Example 20 | 21 | [source,lua,example] 22 | ---- 23 | local intersecationtab = require 'intersecationtab' 24 | 25 | local int = intersecationtab({a='a',b='b',c='c',x='x1'},{a='A',d='d',x='x2'}) 26 | 27 | assert( int.a == 'a' ) 28 | assert( int.x == 'x1' ) 29 | 30 | local count = 0 31 | for _ in pairs(int) do count = count + 1 end 32 | assert( count == 2 ) 33 | 34 | local int = intersecationtab({a='a1'},{a='a2'},function(x,y) return y end) 35 | 36 | assert( int.a == 'a2' ) 37 | 38 | ---- 39 | 40 | 41 | ]===] 42 | 43 | local function intersecationtab( firstTab, secondTab, selectFunc ) --> intersecationTab 44 | local intersecationTab = {} 45 | if not firstTab or not secondTab then return intersecationTab end 46 | for k, v in pairs(firstTab) do 47 | local o = secondTab[k] 48 | if o then 49 | if not selectFunc then 50 | intersecationTab[k] = v 51 | else 52 | intersecationTab[k] = selectFunc(v, o) 53 | end 54 | end 55 | end 56 | return intersecationTab 57 | end 58 | 59 | return intersecationtab 60 | -------------------------------------------------------------------------------- /src/iscallable.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = iscallable 4 | 5 | [source,lua] 6 | ---- 7 | function iscallable( var ) --> res 8 | ---- 9 | 10 | This function will return `true` if `var` is callable through the standard function call 11 | syntax. Otherwise it will return `false`. 12 | 13 | == Example 14 | 15 | [source,lua,example] 16 | ---- 17 | local iscallable = require "iscallable" 18 | 19 | assert( false == iscallable( 'hi' ) ) 20 | assert( false == iscallable( {} ) ) 21 | assert( true == iscallable( function()end )) 22 | assert( true == iscallable( setmetatable({},{__call=function()end }) )) 23 | 24 | ---- 25 | 26 | ]===] 27 | 28 | local function iscallable_rec( mask, i ) 29 | 30 | if "function" == type( i ) then return true end 31 | 32 | local mt = getmetatable( i ) 33 | if not mt then return false end 34 | local callee = mt.__call 35 | if not callee then return false end 36 | 37 | if mask[ i ] then return false end 38 | mask[ i ] = true 39 | 40 | return iscallable_rec( mask, callee ) 41 | end 42 | 43 | local function iscallable( var ) --> res 44 | return iscallable_rec( {}, var ) 45 | end 46 | 47 | return iscallable 48 | -------------------------------------------------------------------------------- /src/isreadable.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = isreadable 4 | 5 | [source,lua] 6 | ---- 7 | function isreadable( path ) --> res 8 | ---- 9 | 10 | Return `true` if the input `path` string points to a readable file. `false` 11 | otherwise. 12 | 13 | == Example 14 | 15 | [source,lua,example] 16 | ---- 17 | local isreadable = require "isreadable" 18 | 19 | io.open( "isreadable.txt", "wb" ):close() 20 | assert( isreadable( "isreadable.txt" ) == true ) 21 | 22 | os.remove( "isreadable.txt" ) 23 | assert( isreadable( "isreadable.txt" ) == false ) 24 | ---- 25 | 26 | ]===] 27 | 28 | local function isreadable( path ) --> res 29 | local f = io.open(path, "r" ) 30 | if not f then return false end 31 | f:close() 32 | return true 33 | end 34 | 35 | return isreadable 36 | -------------------------------------------------------------------------------- /src/jsonish.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = jsonish 4 | 5 | [source,lua] 6 | ---- 7 | function jsonish( jsonStr ) --> dataTab 8 | ---- 9 | 10 | This function parses the json-like string `jsonStr` to the lua table `dataTab`. 11 | It does not perform any validation. The parser is not fully JSON compliant, 12 | however it is very simple and it should work in most the cases. 13 | 14 | This function internally works by trasforming the string into a valid lua table 15 | literal. For this reasons it accept also some syntax that is not actually valid 16 | JSON, e.g. mixed array/hash syntax: `{1, "a":"b"}. 17 | 18 | == Example 19 | 20 | [source,lua,example] 21 | ---- 22 | local jsonish = require 'jsonish' 23 | 24 | local data = jsonish '{ "a":{"hello":"world"}, "b":[99,100,101]}' 25 | 26 | assert( data.a.hello == "world" ) 27 | assert( data.b[1] == 99 ) 28 | assert( data.b[2] == 100 ) 29 | assert( data.b[3] == 101 ) 30 | ---- 31 | 32 | ]===] 33 | 34 | local function json_to_table_literal(s) 35 | 36 | s = s:gsub('([^\\])""',"%1''") 37 | 38 | s = s:gsub([[\\]],[[\u{5C}]]) 39 | s = (' '..s):gsub('([^\\])(".-[^\\]")', function( prefix, quoted ) 40 | -- Matched string: quoted, non empty 41 | 42 | quoted = quoted:gsub('\\"','\\u{22}') 43 | quoted = quoted:gsub('\\[uU](%x%x%x%x)', '\\u{%1}') 44 | quoted = quoted:gsub('%[','\\u{5B}') 45 | quoted = quoted:gsub('%]','\\u{5D}') 46 | return prefix .. quoted 47 | end) 48 | 49 | s = s:gsub('%[','{') 50 | s = s:gsub('%]','}') 51 | s = s:gsub('("[^"]-")%s*:','[%1]=') 52 | 53 | return s 54 | end 55 | 56 | local function json_to_table(s) 57 | local loader, e = 58 | load('return '..json_to_table_literal(s), 'jsondata', 't', {}) 59 | if not loader or e then return nil, e end 60 | return loader() 61 | end 62 | 63 | return json_to_table 64 | -------------------------------------------------------------------------------- /src/jsonishout.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = jsonishout 4 | 5 | [source,lua] 6 | ---- 7 | function jsonishout( inputValue ) --> jsonStr 8 | ---- 9 | 10 | Generate the JSON-like string `jsonStr` from the lua value `inputValue`. Only 11 | number or string keys are allowed in a table value. The value can be a table 12 | itself; any other value will be converted to string. 13 | 14 | If a table value contains only number key, a JSON array will be generated. If 15 | it contains only string key a JSON object will be generated istead. Empty table 16 | or mix table will produce an array. 17 | 18 | Any table that has a metatable will always generate a JSON object, so you can 19 | use an empty table with an empty metatable to generate an empty JSON obkec. 20 | This access the tables with common lua `[]` operator, so metatable can be used 21 | to hook into the generator behaviour. 22 | 23 | == Example 24 | 25 | [source,lua,example] 26 | ---- 27 | local jsonishout = require 'jsonishout' 28 | 29 | assert( jsonishout{{a=1},{1,"b"}} == '[{"a":1},[1,"b"]]' ) 30 | ---- 31 | 32 | ]===] 33 | 34 | local function quote_json_string(str) 35 | return '"' 36 | .. str:gsub('(["\\%c])', 37 | function(c) 38 | return string.format('\\x%02X', c:byte()) 39 | end) 40 | .. '"' 41 | end 42 | 43 | local table_to_json 44 | 45 | local function table_to_json_rec(result, t) 46 | 47 | if 'number' == type(t) then 48 | result[1+#result] = tostring(t) 49 | return 50 | end 51 | 52 | if 'table' ~= type(t) then 53 | result[1+#result] = quote_json_string(tostring(t)) 54 | return 55 | end 56 | 57 | local isarray = false 58 | if not getmetatable(t) then 59 | local hasindex, haskey = false, false 60 | for _ in ipairs(t) do hasindex = true break end 61 | for _ in pairs(t) do haskey = true break end 62 | isarray = hasindex or not haskey 63 | end 64 | 65 | if isarray then 66 | result[1+#result] = '[' 67 | local first = true 68 | for _,v in ipairs(t) do 69 | if not first then result[1+#result] = ',' end 70 | first = false 71 | table_to_json_rec(result, v) 72 | end 73 | result[1+#result] = ']' 74 | 75 | else 76 | result[1+#result] = '{' 77 | local first = true 78 | for k,v in pairs(t) do 79 | 80 | if 'number' ~= type(k) or 0 ~= math.fmod(k) then -- skip integer keys 81 | k = tostring(k) 82 | if not first then result[1+#result] = ',' end 83 | first = false 84 | 85 | -- Key 86 | result[1+#result] = quote_json_string(k) 87 | result[1+#result] = ':' 88 | 89 | -- Value 90 | table_to_json_rec(result, v) 91 | end 92 | end 93 | 94 | result[1+#result] = '}' 95 | end 96 | end 97 | 98 | table_to_json = function(t) 99 | local result = {} 100 | table_to_json_rec(result, t) 101 | return table.concat(result) 102 | end 103 | 104 | return table_to_json 105 | -------------------------------------------------------------------------------- /src/keysort.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = keysort 4 | 5 | [source,lua] 6 | ---- 7 | function keysort( inTab ) --> outArr 8 | ---- 9 | 10 | This function return the list of all the keys of the input `inTab` 11 | table. The keys are alphabetically sorted. String keys came before any 12 | other key. Other key are sorted with respect to their string 13 | representation, i.e. `tostring` is internally used. 14 | 15 | == Example 16 | 17 | [source,lua,example] 18 | ---- 19 | local keysort = require 'keysort' 20 | 21 | local sorted = keysort{[1]=400,[2]=300,['1']=200,['2']=100} 22 | assert( sorted[1] == '1' ) 23 | assert( sorted[2] == '2' ) 24 | assert( sorted[3] == 1 ) 25 | assert( sorted[4] == 2 ) 26 | assert( #sorted == 4 ) 27 | 28 | ---- 29 | 30 | ]===] 31 | 32 | local sort, tostring, type, ipairs, pairs = 33 | table.sort, tostring, type, ipairs, pairs 34 | 35 | local function keysort( inTab ) --> outArr 36 | local outArr = {} 37 | local nonstring = {} 38 | for k in pairs(inTab) do 39 | if type(k) == 'string' then 40 | outArr[1+#outArr] = k 41 | else 42 | local auxkey = tostring(k) 43 | nonstring[1+#nonstring] = auxkey 44 | nonstring[auxkey] = k 45 | end 46 | end 47 | sort(outArr) 48 | sort(nonstring) 49 | for _,v in ipairs(nonstring) do 50 | outArr[#outArr+1] = nonstring[v] 51 | end 52 | return outArr 53 | end 54 | 55 | return keysort 56 | -------------------------------------------------------------------------------- /src/lambda.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = lambda 4 | 5 | [source,lua] 6 | ---- 7 | function lambda( def ) --> func, err 8 | ---- 9 | 10 | Allows to define functions using a compact lambda-like syntax. It parse the 11 | `def` string and returns the lua function `func` that execute the input code. 12 | In case of error it return `nil` plus the `err` error string. 13 | 14 | This function internally works by expanding the following patterns into a 15 | standard lua function definition. 16 | Then it is parsed by the common Lua _load_/_loadstring_ function. 17 | 18 | The fundamental expanded pattern is 'prologue|statement;expression'. 19 | 20 | It generate a function that has 'prologue' as nominal arguments. 21 | It can be a comma separated list, like in 'x,y,z|statement;expression'. 22 | 23 | Then the 'statement' will be injected as the function body. 24 | It must be a sequence of lua statements like in 25 | 'prologue|for k = 1,10 do print(k) end print("ok");expression'. 26 | 27 | At end of the function the 'expression' will be returned. 28 | So it must be a valid Lua expression like in 'prologue|statement;math.random(2)'. 29 | 30 | When the 'prologue' is missing, a default one will be used consisting of the 31 | first 6 alphabet letters. 32 | 'expression' must always be given but the 'statement' and the separation ';' can 33 | be missing. 34 | Indeed, in the main use case, prologue and statement will be missing and only 35 | the expression will be given. 36 | 37 | == Example 38 | 39 | [source,lua,example] 40 | ---- 41 | local lambda = require "lambda" 42 | 43 | local inc = lambda'a+1' 44 | local dup = lambda"x| x=x*2; x" 45 | local dup2 = lambda"x| x=x*2; x" 46 | 47 | assert( inc ~= dup2 ) 48 | assert( dup == dup2 ) 49 | 50 | assert( inc(7) == 8 ) 51 | assert( dup(3) == 6 ) 52 | ---- 53 | 54 | ]===] 55 | 56 | local load = load 57 | local memo = setmetatable( {}, { __mode = "kv" } ) 58 | 59 | local function lambda( def ) --> func, err 60 | 61 | -- Check cache 62 | local result = memo[def] 63 | if result then return result end 64 | 65 | -- Find the body and symbolic arguments 66 | local symb, body = def:match( "^(.-)|(.*)$" ) 67 | if not arg or not body then 68 | symb = "a,b,c,d,e,f,..." 69 | body = def 70 | end 71 | 72 | -- Split statements from the last expression 73 | local stat, expr = body:match( "^(.*;)([^;]*)$" ) 74 | 75 | -- Generate standard lua function definition 76 | local func = "return( function( "..symb..")" 77 | if not expr or expr == "" then 78 | func = func.."return "..body 79 | else 80 | func = func..stat.."return "..expr 81 | end 82 | func = func.." end )( ... )" 83 | 84 | -- Generate the function 85 | local result, err = load( func, "lambda", "t" ) 86 | if result and not err then 87 | memo[def] = result 88 | end 89 | return result, err 90 | end 91 | 92 | return lambda 93 | -------------------------------------------------------------------------------- /src/lineposition.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = lineposition 4 | 5 | [source,lua] 6 | ---- 7 | function lineposition( str, byteNum ) --> columnNum, lineNum 8 | function lineposition( str, columnNum, lineNum ) --> byteNum 9 | ---- 10 | 11 | This function translate to/from the following representation of a position in a 12 | string: 13 | 14 | - Byte count from the beginning 15 | - Column and line count 16 | 17 | It behaves differently based on the number of arguments. 18 | 19 | When the `str` string and a single `byteNum` integer are passed, it will 20 | interpret the number as a byte offset in the string. The column and line are 21 | returned. 22 | 23 | When `str` is passed with both `columnNum` and `lineNum`, the opposite 24 | transformation is perfomed. 25 | 26 | == Example 27 | 28 | [source,lua,example] 29 | ---- 30 | local lineposition = require "lineposition" 31 | 32 | local x, y = lineposition( "a\na", 3 ) 33 | assert( x == 1 ) 34 | assert( y == 2 ) 35 | 36 | local c = lineposition( "a\na", 1, 2 ) 37 | assert( c == 3 ) 38 | 39 | ---- 40 | 41 | ]===] 42 | 43 | local select = select 44 | 45 | local function lineposition( str, byteNum, ... ) --> columnNum | byteNum[, lineNum] 46 | 47 | local lineNum = select('#', ...) > 0 and select(1, ...) 48 | 49 | if lineNum then 50 | local columnNum = byteNum 51 | local pat = ( "[^\n]*\n" ):rep( lineNum -1 ) .. '()' 52 | local lineoff = str:match( pat ) 53 | if lineoff then 54 | return lineoff -1 + columnNum 55 | end 56 | return nil 57 | 58 | else 59 | local columnNum = byteNum 60 | lineNum = 1 61 | 62 | for c in str:gmatch('\n()') do 63 | if c > byteNum then break end 64 | columnNum = 1 + byteNum - c 65 | lineNum = lineNum + 1 66 | end 67 | 68 | return columnNum, lineNum 69 | end 70 | end 71 | 72 | return lineposition 73 | -------------------------------------------------------------------------------- /src/locktable.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = locktable 4 | 5 | [source,lua] 6 | ---- 7 | function locktable( inTab [, modeStr ...] ) --> protectTab 8 | ---- 9 | 10 | Return the `protectTab` proxy table: each operation on it will be actually 11 | performed on the `inTab` input table. A list of string can be optionally passed 12 | to forbid some kind of operation. If an operation is forbidden, when trying to 13 | perform it on `protectTab`, an error will be thrown. 14 | 15 | The avaiable limitation are: 16 | 17 | - 'readnil': error if try to read a empty key 18 | - 'writenil': error if try to write an empty key 19 | - 'read': error if try to read any key 20 | - 'write': error if try to write any key 21 | - 'iterate': error if try to iterate with `pairs` or `ipairs` 22 | - 'full': all the previous 23 | 24 | Any of this limitation specifier can be as optiontional alrgument. More 25 | limitation can be passed as variadic argument list. 26 | 27 | A typical usage is the protection of the environment to check the access to a 28 | undefined global: 29 | 30 | ``` 31 | _ENV = require 'locktable' ( _ENV, 'readnil' ) 32 | local x = True --> this rises an error, while normally just nil was placed in x 33 | ``` 34 | 35 | == Example 36 | 37 | [source,lua,example] 38 | ---- 39 | local locktable = require 'locktable' 40 | 41 | local o = { a = 1 } 42 | l = locktable( o, 'readnil', 'writenil' ) 43 | 44 | assert( o ~= l ) 45 | assert( l.a == 1 ) 46 | l.a = true 47 | assert( l.a == true ) 48 | assert( o.a == true ) 49 | 50 | local ok, err 51 | 52 | ok, err = pcall(function() return l.b end) 53 | assert( ok == false ) 54 | assert( err:match( 'Read of nil field was forbidden$' )) 55 | 56 | ok, err = pcall(function() l.b = true end) 57 | assert( ok == false ) 58 | assert( err:match( 'Write of nil field was forbidden$' )) 59 | ---- 60 | 61 | ]===] 62 | 63 | local error, setmetatable = error, setmetatable 64 | local pairs, ipairs = pairs, ipairs 65 | local rawget, rawset = rawget, rawset 66 | 67 | local function iterate( ) 68 | error('Iteration on fielad was forbidden', 2) 69 | end 70 | 71 | local function readall( ) 72 | error('Access of any field was forbidden', 2) 73 | end 74 | 75 | local function writeall( ) 76 | error('Change of any field was forbidden', 2) 77 | end 78 | 79 | local function lockingmeta( inTab, ... ) --> proxyMet 80 | 81 | local function readnil( s, k ) 82 | local v = rawget( inTab, k ) 83 | if nil == v then 84 | error('Read of nil field was forbidden', 2) end 85 | return v 86 | end 87 | 88 | local function writenil( s, k, v ) 89 | if nil == rawget( inTab, k ) then 90 | error('Write of nil field was forbidden', 2) 91 | end 92 | rawset( inTab, k, v ) 93 | end 94 | 95 | local metatable = { 96 | __newindex = function(s, k, v) rawset( inTab, k, v ) end, 97 | __index = function(s,k) return rawget( inTab, k ) end, 98 | __pairs = function(...) return pairs(inTab, ...) end, 99 | __ipairs = function(...) return ipairs(inTab, ...) end, 100 | } 101 | 102 | for _, locktype in ipairs({...}) do 103 | 104 | if locktype == 'readnil' or locktype == 'full' then 105 | metatable.__index = readnil 106 | end 107 | 108 | if locktype == 'writenil' or locktype == 'full' then 109 | metatable.__newindex = writenil 110 | end 111 | 112 | if locktype == 'iterate' or locktype == 'full' then 113 | metatable.__pairs = iterate 114 | metatable.__ipairs = iterate 115 | end 116 | 117 | if locktype == 'read' or locktype == 'full' then 118 | metatable.__index = readall 119 | end 120 | 121 | if locktype == 'write' or locktype == 'full' then 122 | metatable.__newindex = writeall 123 | end 124 | end 125 | 126 | return metatable 127 | end 128 | 129 | local function locktable( inTab, ... ) --> lockedTab 130 | return setmetatable( {}, lockingmeta( inTab, ... )) 131 | end 132 | 133 | return locktable 134 | -------------------------------------------------------------------------------- /src/logline.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = logline 4 | 5 | [source,lua] 6 | ---- 7 | function logline( level [, ...] ) --> line, err 8 | ---- 9 | 10 | This function adds common useful information to the data that you want to 11 | output. 12 | 13 | When called with the single 'level' argument, it will set the global verbosity 14 | level. When called with additional arguments it will generate the log string 15 | `line`. However the string will be generated only if the first argument, the 16 | line log level, is smaller than the global verbosity level. In this way you 17 | can dinamically enable or disable log messages in critical part of the code. 18 | 19 | The verbosity level can be given in two way: as an integer or as a string 20 | representing the verbosity class. 21 | 22 | The allowed verbosity classes are: 23 | 24 | - *ERROR* <==> 25 25 | - *DEBUG* <==> 50 26 | - *INFO* <==> 75 27 | - *VERBOSE* <==> 99 28 | 29 | Each class will be considered to cantain any integer level just below it, e.g. 30 | 26, 30 and 50 all belongs to the *DEBUG* class. 31 | When specifying the verbosity level as a class name, the higher belonging 32 | integer will be used. 33 | 34 | All the other vararg are appended to the generated log line. 35 | 36 | The data included in the log are: 37 | 38 | - Date/time in a format such as the string order is the same of time order 39 | - _os.clock()_ result 40 | - Verbosity level of the log line (both number and class name) 41 | - Source position of function call 42 | - Additional info in the arguments 43 | 44 | Note 1: if the caller is a tail call or a function with a name that starts or 45 | ends with _log_, the position used will be the one of the caller of the caller 46 | (and so on). 47 | 48 | Note 2: in case of error `nil` will be returned, plus the `err` error string 49 | 50 | == Example 51 | 52 | [source,lua,example] 53 | ---- 54 | local logline = require "logline" 55 | 56 | logline( 30 ) 57 | assert( logline( 29, "test" ) ~= nil) 58 | assert( logline( 30, "test" ) ~= nil) 59 | assert( logline( 31, "test" ) == nil) 60 | assert( logline( "error", "test" ) ~= nil) 61 | assert( logline( "debug", "test" ) == nil) 62 | assert( logline( "info", "test" ) == nil) 63 | assert( logline( "verbose", "test" ) == nil) 64 | 65 | logline( 50 ) 66 | assert( logline( 26, "test" ) ~= nil) 67 | assert( logline( 50, "test" ) ~= nil) 68 | assert( logline( 51, "test" ) == nil) 69 | assert( logline( "error", "test" ) ~= nil) 70 | assert( logline( "debug", "test" ) ~= nil) 71 | assert( logline( "info", "test" ) == nil) 72 | assert( logline( "verbose", "test" ) == nil) 73 | ---- 74 | 75 | ]===] 76 | 77 | local skip_lower_level = 25 78 | 79 | local level_list = { 80 | { 25, "ERROR" }, 81 | { 50, "DEBUG" }, 82 | { 75, "INFO"} , 83 | { 99, "VERBOSE" } 84 | } 85 | 86 | local level_map 87 | local function update_level_map() 88 | level_map = {} 89 | for k,v in ipairs( level_list ) do 90 | level_map[ v[ 2 ] ] = v 91 | end 92 | end 93 | 94 | update_level_map() 95 | 96 | local function logline( level, ... ) --> line 97 | -- Classify log level 98 | local level_class 99 | if "string" == type( level ) then 100 | level_class = level_map[ level:upper() ] 101 | if level_class then level = level_class[ 1 ] end 102 | elseif "number" == type( level ) then 103 | local level_num = #level_list 104 | for k = 1, level_num do 105 | if k == level_num or level <= level_list[k][1] then 106 | level_class = level_list[k] 107 | break 108 | end 109 | end 110 | else 111 | return nil, "Invalid type for argument #1" 112 | end 113 | 114 | if not level_class then 115 | return nil, "Invalid symbolic log level" 116 | end 117 | 118 | local n = select( "#", ... ) 119 | -- Single argument mode: set log level 120 | if n == 0 then 121 | skip_lower_level = level 122 | return 123 | end 124 | 125 | -- Multiple argument mode: generate log line 126 | 127 | -- Skip if the current log level is too small 128 | if skip_lower_level < level then 129 | return 130 | end 131 | 132 | -- Get info about the function in the correct stack position 133 | local d = debug.getinfo( 2 ) 134 | local td = d 135 | local stackup = 2 136 | while true do 137 | local n = td.name 138 | if not n then break end 139 | n = n:lower() 140 | if not n:match( "log$" ) 141 | and not n:match( "^log" ) 142 | and n ~= "" then 143 | break 144 | end 145 | stackup = stackup + 1 146 | td = debug.getinfo(stackup) 147 | end 148 | if td then d = td end 149 | 150 | -- Log line common part 151 | local line = os.date( "%Y/%m/%d %H:%M:%S" ).." "..os.clock().." " 152 | ..level_class[ 1 ].."."..level_class[ 2 ].." " 153 | ..d.short_src:match( "([^/\\]*)$" )..":"..d.currentline.." | " 154 | 155 | -- Append additional log info from arguments 156 | for m = 1,n do 157 | line = line..tostring( select( m, ... ) ).." | " 158 | end 159 | 160 | return line 161 | end 162 | 163 | return logline 164 | -------------------------------------------------------------------------------- /src/measure.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = measure 4 | 5 | [source,lua] 6 | ---- 7 | function measure( partMea ) --> sampleFunc 8 | ---- 9 | 10 | This function generate a sample handling function `sampleFunc`. It can be used 11 | to add repeted measurement of a quantity, and get the following sample statisitcs: 12 | 13 | - Mean 14 | - Standard deviation 15 | - Skewness (i.e. sqrt(sample-number) * 3rd-momentum / 2nd-momentum^(3/2) ) 16 | - Kurtosis 17 | - Sample size 18 | - Minimum 19 | - Maximum 20 | 21 | If the `partMea` table is passed, it will be interpreted as a seqeunce of different 22 | `sampleFunc`. The returned `sampleFunc` will be intialized as the union of all 23 | the partial sets of measurements. A partition formula is used to merge the 24 | measurements [1]. 25 | 26 | The `sampleFunc` can be used in two forms: 27 | 28 | [source,lua] 29 | ---- 30 | function sampleFunc( valueNum ) --> nil 31 | function sampleFunc( nil ) --> meanNum, deviationNum, SkewnessNum, kurtosisNum, sizeNum, minValue, maxValue 32 | ---- 33 | 34 | In the first form, the `valueNum` number will be added to the measurements. This 35 | causes the recalculation of the stored sample momentums. 36 | 37 | In the second form, the statistics are calculated and returned. 38 | 39 | == References 40 | 41 | [1] Philippe Pébay. SANDIA REPORT SAND2008-6212 (2008) - https://prod.sandia.gov/techlib-noauth/access-control.cgi/2008/086212.pdf 42 | 43 | == Example 44 | 45 | [source,lua,example] 46 | ---- 47 | local measure = require 'measure' 48 | local m 49 | 50 | local a = measure() 51 | a(2) 52 | a(2) 53 | m = a() 54 | assert( m > 2 -1e-4 and m < 2 +1e04 ) 55 | 56 | local b = measure() 57 | b(4) 58 | b(8) 59 | m = b() 60 | assert( m > 6 -1e-4 and m < 6 +1e04 ) 61 | 62 | local c = measure{a, b} 63 | m = {c()} 64 | 65 | assert( m[1] > 4.0 -1e-4 and m[1] < 4.0 +1e04 ) 66 | assert( m[2] > 2.828 -1e-4 and m[2] < 2.828 +1e04 ) 67 | assert( m[3] > 0.816 -1e-4 and m[3] < 0.816 +1e04 ) 68 | assert( m[4] > 2.0 -1e-4 and m[4] < 2.0 +1e04 ) 69 | assert( m[5] > 4 -1e-4 and m[5] < 4 +1e04 ) 70 | assert( m[6] > 2 -1e-4 and m[6] < 2 +1e04 ) 71 | assert( m[7] > 8 -1e-4 and m[7] < 8 +1e04 ) 72 | ---- 73 | 74 | ]===] 75 | 76 | local sqrt = math.sqrt 77 | 78 | local aux_get_state = {} 79 | 80 | local function measure( partMea ) --> 81 | 82 | -- init 83 | local M1 = 0 84 | local M2 = 0 85 | local M3 = 0 86 | local M4 = 0 87 | local n = 0 88 | local min = nil 89 | local max = nil 90 | 91 | local function import_set(M1F2, M2F2, M3F2, M4F2, n2, min2, max2) 92 | if n == 0 then 93 | M1, M2, M3, M4, n = M1F2, M2F2, M3F2, M4F2, n2 94 | min = min2 95 | max = max2 96 | else 97 | -- Formula: Philippe Pébay. SANDIA REPORT SAND2008-6212 (2008) - https://prod.sandia.gov/techlib-noauth/access-control.cgi/2008/086212.pdf 98 | local M1F1, M2F1, M3F1, M4F1, n1 = M1, M2, M3, M4, n 99 | local n1p2 = n1 + n2 100 | local nn = n1 * n2 101 | local n1sq = n1 * n1 102 | local n2sq = n2 * n2 103 | local D = (M1F2 - M1F1) / n1p2 104 | local DSQ = D * D 105 | M1 = M1F1 + n2 * D 106 | M2 = M2F1 + M2F2 107 | + nn * DSQ * n1p2 108 | M3 = M3F1 + M3F2 109 | + nn * (n1 - n2) * n1p2 * D * DSQ 110 | + 3 * (n1 * M2F2 - n2 * M2F1) * D 111 | M4 = M4F1 + M4F2 112 | + nn * (n1sq + n2sq - nn) * n1p2 * DSQ * DSQ 113 | + 6 * (n1sq * M2F2 + n2sq * M2F1) * DSQ 114 | + 4 * (n1 * M3F2 - n2 * M3F1) * D 115 | n = n1p2 116 | if min2 and min2max then 120 | max = max2 121 | end 122 | end 123 | end 124 | 125 | local function import_all( ml ) 126 | for _, m in pairs( ml ) do 127 | import_set( m( aux_get_state )) 128 | end 129 | end 130 | 131 | local function get_measure( value ) 132 | if value == aux_get_state then 133 | return M1, M2, M3, M4, n, min, max 134 | elseif value ~= nil then 135 | import_set(value, 0, 0, 0, 1, value, value) 136 | end 137 | local m, d, s, k = M1, 0, 0, 0 138 | if n > 1 then 139 | d = sqrt( M2 /( n - 1 )) 140 | end 141 | if n > 1 and d > 0 then 142 | -- s = M3 /( n * d * d * d ) -- wikipedia 143 | s = M3 * sqrt(n) /sqrt( M2 * M2 * M2 ) -- wolfram 144 | end 145 | if M2 > 0 then 146 | k = M4 * n /( M2 * M2 ) 147 | end 148 | return m,d,s,k,n,min,max 149 | end 150 | 151 | if partMea then import_all(partMea) end 152 | return get_measure 153 | end 154 | 155 | return measure 156 | -------------------------------------------------------------------------------- /src/memo.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = memo 4 | 5 | [source,lua] 6 | ---- 7 | function memo( coreFunc ) --> wrapFunc 8 | ---- 9 | 10 | This function take any function `coreFunc` as input and it return the memoized 11 | version `wrapFunc`. The momoized wrapper will call the core function only the 12 | first time that a new combination of input values is passed. If `wrapFunc` is 13 | re-called with the same parameters, it does not call `coreFunc` but it just 14 | returns a cashed copy of the results. 15 | 16 | == Example 17 | 18 | [source,lua,example] 19 | ---- 20 | local memo = require 'memo' 21 | 22 | local f = memo(function(a) return {} end) 23 | 24 | assert ( f'' == f'' ) 25 | assert ( f'' ~= f'x' ) 26 | ---- 27 | 28 | ]===] 29 | 30 | local intern = (function() 31 | -- [SNIP:intern.lua[ 32 | local function intern() --> reference 33 | 34 | local rawget, rawset, select, setmetatable = 35 | rawget, rawset, select, setmetatable, select 36 | local NIL, NAN = {}, {} 37 | 38 | local internmeta = { 39 | __index = function() error('Can not access interned content directly.', 2) end, 40 | __newindex = function() error('Can not cahnge or add contents to a intern.', 2) end, 41 | } 42 | 43 | local internstore = setmetatable( {}, { __mode = "kv" } ) 44 | 45 | -- A map from child to parent is used to protect the internstore table's contents. 46 | -- In this way, they will he collected only when all the cildren are collected 47 | -- in turn. 48 | local parent = setmetatable( {}, { __mode = 'k' }) 49 | 50 | return function( ... ) 51 | local currentintern = internstore 52 | for a = 1, select( '#', ... ) do 53 | 54 | -- Get next intern field. Replace un-storable contents. 55 | local tonext = select( a, ... ) 56 | if tonext ~= tonext then tonext = NAN end 57 | if tonext == nil then tonext = NIL end 58 | 59 | -- Get or create the correspondent sub-intern 60 | local subintern = rawget( currentintern, tonext ) 61 | if subintern == nil then 62 | 63 | subintern = setmetatable( {}, internmeta ) 64 | parent[subintern] = currentintern 65 | rawset( currentintern, tonext, subintern ) 66 | end 67 | 68 | currentintern = subintern 69 | end 70 | return currentintern 71 | end 72 | end 73 | 74 | return intern 75 | -- ]SNIP:intern.lua] 76 | end)() 77 | 78 | local setmetatable, pack, unpack = setmetatable, table.pack, table.unpack 79 | 80 | local function memo(func) 81 | 82 | local memo_input = intern() 83 | local memo_output = setmetatable({},{__mode='k'}) 84 | 85 | return function( ... ) 86 | local i = memo_input( ... ) 87 | local v = memo_output[i] 88 | if not v then 89 | v = pack(func(...)) 90 | memo_output[i] = v 91 | end 92 | return unpack(v) 93 | end 94 | end 95 | 96 | return memo 97 | -------------------------------------------------------------------------------- /src/object.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = object 4 | 5 | [source,lua] 6 | ---- 7 | function inherit( base1Tab[, base2Tab[, ...]] ) --> derivedTab 8 | function isderived( derivedTab, baseTab ) --> truthnessBool 9 | ---- 10 | 11 | The `inherit` function retrun a new table that inherits from all the 12 | `base1Tab`, `base2Tab` tables. When a field is not found in the new table, it 13 | will be serched in the base ones, in the same orded as they were prvided (i.e. 14 | `base1Tab` first). The first one found is returned. 15 | 16 | The `isderived` function will check if `derivedTab` was generated ba an 17 | `inherit` function call with `baseTab` somewhere in its arguments. 18 | 19 | This module implements a prototype pattern, with multiple inheritace. It does 20 | not provide a constructor semantic. You can use the `factory` module for that 21 | purpose. 22 | 23 | ]===] 24 | 25 | local setmetatable, move = setmetatable, table.move 26 | 27 | local prototype_map = setmetatable({},{__mode="k"}) 28 | local function protoadd( instance, protochain ) 29 | 30 | local protos = prototype_map[instance] 31 | if not protos then 32 | protos = setmetatable( {meta={}}, {__mode="k"} ) 33 | prototype_map[instance] = protos 34 | end 35 | local meta = protos.meta 36 | 37 | local pn = #protochain 38 | if pn > 0 then 39 | move( protos, 1, #protos, pn+1) 40 | end 41 | move( protochain, 1, pn, 1, protos ) 42 | 43 | meta.__index = function( _, k ) 44 | local pn = #protos 45 | for p = 1, pn do 46 | local field = protos[p][k] 47 | if field ~= nil then 48 | return field 49 | end 50 | end 51 | end 52 | 53 | return setmetatable( instance, meta ) 54 | end 55 | 56 | local function inherit(b, o) 57 | o = o or {} 58 | return protoadd(o, b) 59 | end 60 | 61 | local function has_proto( derived, base ) 62 | local protos = prototype_map[derived] 63 | 64 | if protos then 65 | for _, b in pairs(protos) do 66 | if b == base then return true end 67 | if has_proto( b, base ) then return true end -- TODO : avoid recursion? memoize? 68 | end 69 | end 70 | return false 71 | end 72 | 73 | return { 74 | inherit = inherit, 75 | isderived = has_proto, 76 | } 77 | -------------------------------------------------------------------------------- /src/pathpart.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = pathpart 4 | 5 | [source,lua] 6 | ---- 7 | function pathpart( pathIn ) --> pathOut, errorStr 8 | ---- 9 | 10 | Convert between two path representation: the string one, and the array of 11 | strings one. `pathIn` may be any of them: the other will be generated as 12 | `pathOut`. In case of error, `nil` plus the `errorStr` string is returned 13 | instead. 14 | 15 | While converting from string, any of the following path separator is valid: 16 | '\', '.'. 17 | 18 | While converting from array of string, the path separator from `package.config` 19 | is used. 20 | 21 | The strings in the array representation do not contain any path separator: each 22 | array entry correspond to a single path step, and contains exactly the folder 23 | name. 24 | 25 | == Example 26 | 27 | [source,lua,example] 28 | ---- 29 | local pathpart = require 'pathpart' 30 | 31 | local s = package.config:sub(1,1) 32 | 33 | local p = pathpart('path'..s..'to'..s..'name.ext') 34 | assert( p[1] == 'path' ) 35 | assert( p[2] == 'to' ) 36 | assert( p[3] == 'name.ext' ) 37 | 38 | assert( pathpart{'path','to','name.ext'} == 'path'..s..'to'..s..'name.ext' ) 39 | 40 | ---- 41 | 42 | ]===] 43 | 44 | local path_separator = package.config:sub(1,1) 45 | 46 | local function path_merge( pathTab ) 47 | return table.concat( pathTab, path_separator ) 48 | end 49 | 50 | local function path_split( pathStr ) 51 | local result = {} 52 | for c in pathStr:gmatch( '[^/\\]+' ) do 53 | result[1+#result] = c 54 | end 55 | return result 56 | end 57 | 58 | local function pathpart( pathIn ) --> pathOut, errorStr 59 | local t = type(pathIn) 60 | if 'table' == t then return path_merge( pathIn ) 61 | elseif 'string' == t then return path_split( pathIn ) 62 | else return nil, 'Invalid input type' 63 | end 64 | end 65 | 66 | return pathpart 67 | -------------------------------------------------------------------------------- /src/rawhtml.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = rawhtml 4 | 5 | [source,lua] 6 | ---- 7 | function rawhtml( htmlStr ) --> rawmarkStr 8 | ---- 9 | 10 | This function, togheter with `rawmark`, allows the parsing of html-like data. 11 | 12 | Infact, you can use this function to trasfrom the `htmlStr` string, containing 13 | html data, into the `rawmarkStr` string containing an rawmark equivalent. This 14 | result can be oarsed with the <> module. 15 | 16 | No html validation is performed and actually the syntax is more permissive than 17 | the html one. 18 | 19 | The attribute of each tag is not parsed, but stored verbatim in the first 20 | sub-tag using the "=attribute=" type. 21 | 22 | == Example 23 | 24 | [source,lua,example] 25 | ---- 26 | local rawhtml = require 'rawhtml' 27 | 28 | assert( rawhtml'
x< b />y
bla
' 29 | == '{=comment=:{+}{=}{-}}{div:{=attribute=:my-attr="hi"}x{b:}y{div:bla}}' ) 30 | ---- 31 | 32 | ]===] 33 | 34 | local function rawhtml( inStr ) --> outStr 35 | if inStr == '' then return '' end 36 | local outStr = inStr 37 | outStr = outStr:gsub('([{:}])',{['{']='{+}',['}']='{-}',[':']='{=}' }) 38 | outStr = outStr:gsub('','}') 40 | outStr = outStr:gsub('<(/?)([^>]-)(/?)>',function(p,a,s) 41 | a = a:gsub('^[ \t]*(.-)[ \t]*$','%1') 42 | local a, b = a:match('^([^ \t]*)(.*)$') 43 | if p == '/' then return '}' end 44 | if s == '/' then s = '}' end 45 | if b and b ~= '' then 46 | b = b:gsub('^[ \t]*(.-)[ \t]*$','%1') 47 | b = '{=attribute=:'..b..'}' 48 | end 49 | return '{'..a..':'..b..s 50 | 51 | end) 52 | return outStr 53 | end 54 | 55 | return rawhtml 56 | -------------------------------------------------------------------------------- /src/rawmark.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = rawmark 4 | 5 | [source,lua] 6 | ---- 7 | function rawmark( dataStr ) --> parsedTab 8 | ---- 9 | 10 | This function implement a raw markup language. It take an input `dataStr` 11 | string and generate the `parsedTab` table representation of it. The format of the 12 | input strigs is based on the following core expansion: 13 | 14 | `{type:data}`:: 15 | Where `type` is the only metadata that can be added and `data` is the content. 16 | If `type` is not present, the empty string will be used as default. The type 17 | can contain any character except `:`, `{` and `}`. The data can be any string, 18 | also the empty one. In the data the `{}` is recursively expanded. 19 | 20 | The `:` can be omitted: the sequences like `{abc}` are equivalent to `{:abc}`. 21 | 22 | The following exact sequences are substituted: 23 | 24 | - `{=}` is expanded to `:` 25 | - `{+}` is expanded to `{` 26 | - `{-}` is expanded to `}` 27 | 28 | Note that the sequences like `{:=}` are expanded as usual, i.e. a sub-tag with 29 | the default type and containing only `=`. 30 | 31 | The function will return a table with the only string key `type` containing 32 | ``. All the other keys form a sequence of natural number from 1 to N. To each 33 | key is associated the string value for a verbatim content, or a sub-table in 34 | case of `{}` sub-expansion. This sub-table is contructed at same way with the 35 | `type` field set to the metatada in the tag, or `default` if not present. 36 | 37 | For example the string `aaa{bbb:ccc}` will be expanded to the lua table `{ 38 | type='', 'aaa', {type='bbb', 'ccc'} }`. 39 | 40 | == Example 41 | 42 | [source,lua,example] 43 | ---- 44 | local rawmark = require 'rawmark' 45 | 46 | local data = rawmark '{M:{a}} b {X: {c} }' 47 | 48 | assert( data.type == '' ) 49 | 50 | assert( data[1].type == 'M' ) 51 | assert( data[1][1].type == '' ) 52 | assert( data[1][1].type == '' ) 53 | assert( data[1][1][1] == 'a' ) 54 | 55 | assert( data[2] == ' b ' ) 56 | 57 | assert( data[3].type == 'X' ) 58 | 59 | assert( data[3][1] == ' ' ) 60 | assert( data[3][2].type == '' ) 61 | assert( data[3][2][1] == 'c' ) 62 | assert( data[3][3] == ' ' ) 63 | ---- 64 | 65 | ]===] 66 | 67 | local function rawmark( str, typ ) 68 | 69 | -- Special cases 70 | typ = typ or '' 71 | if str == '' then return { str, type = typ } end 72 | 73 | local result, merge = { type = typ }, false 74 | while str and str ~= '' do 75 | 76 | -- Split verbatim and container parts 77 | local ver, exp, rest = str:match('^(.-)(%b{})(.*)$') 78 | if ver == nil then ver = str end 79 | str = rest -- Prepare next iteration 80 | 81 | -- Append verbatim prefix 82 | if ver and ver ~= '' then result[1+#result] = ver end 83 | 84 | -- Handle escape sequences 85 | local sub = exp and ({ ['{+}']='{', ['{-}']='}', ['{=}']=':' })[exp] 86 | if sub then 87 | merge = true 88 | result[1+#result] = sub 89 | exp = nil 90 | end 91 | 92 | -- Parse tag 93 | if exp and exp ~= '' then 94 | local typ, col, exp = exp:match('^{([^:]*)(:?)(.*)}$') 95 | if col == '' then exp, typ = typ, '' end 96 | result[1+#result] = rawmark( exp, typ ) 97 | end 98 | end 99 | 100 | return result 101 | end 102 | 103 | return rawmark 104 | -------------------------------------------------------------------------------- /src/readfile.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = readfile 4 | 5 | [source,lua] 6 | ---- 7 | local function readfile( pathStr, optStr ) --> readTabStr 8 | local function readfile( pathStr, optStr ) --> nil, errorStr 9 | ---- 10 | 11 | Read the file specified by the path string `pathStr`. Several read option may 12 | be provided. If the read results in a single chunk, a string is returned. If 13 | multiple chunks are avaiable, an array of string is returned. 14 | 15 | The avaiable read option string `optStr` are the same of the lua standard 16 | `io.read` function: for example the `l` option can be used to read each line 17 | separately, and to store it as an item of the returned array. 18 | 19 | In case of error, `nil` plus an error message string `errorStr` is returned. 20 | 21 | == Example 22 | 23 | [source,lua,example] 24 | ---- 25 | local readfile = require 'readfile' 26 | 27 | local f = io.open('tmp.txt', 'wb') 28 | f:write("1 1.2 -1e3\naaa") 29 | f:close() 30 | 31 | assert( readfile('tmp.txt') == "1 1.2 -1e3\naaa" ) 32 | 33 | local data = readfile('tmp.txt', 'l') 34 | assert( data[1] == "1 1.2 -1e3" ) 35 | assert( data[2] == "aaa" ) 36 | 37 | local data = readfile('tmp.txt', 'n') 38 | assert( data[1] == 1 ) 39 | assert( data[2] == 1.2 ) 40 | assert( data[3] == -1e3 ) 41 | ---- 42 | 43 | ]===] 44 | 45 | local function readfile( pathStr, optStr ) --> readTabStr 46 | local f, err = io.open( pathStr, 'rb' ) 47 | if not f or err then return f, err end 48 | if not optStr then optStr = 'a' end 49 | local readTabStr = {} 50 | while true do 51 | local p = f:seek() 52 | local r, err = f:read( optStr ) 53 | if err then return nil, err end 54 | if p == f:seek() then break end 55 | if r and r ~= '' then 56 | readTabStr[1+#readTabStr] = r 57 | end 58 | end 59 | if #readTabStr == 0 then return '' end 60 | if #readTabStr == 1 then return readTabStr[1] end 61 | return readTabStr 62 | end 63 | 64 | return readfile 65 | -------------------------------------------------------------------------------- /src/serialize.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = serialize 4 | 5 | [source,lua] 6 | ---- 7 | function serialize( value, outfunc ) --> str 8 | ---- 9 | 10 | It serializes the lua value `value`. The resulting `str` string can be parsed 11 | by the common Lua _load_/_loadstring_ function to restore the original value. 12 | It have not the Lua literal limitation for tables, as the one found in the 13 | _lualiteral_ function. So it can handle tables with cycles or with a nest 14 | level higher than the max defined for the Lua literals (200). It still can not 15 | handle _userdata_ and _lightuserdata_. 16 | 17 | If `outfunc` is passed, then nothing is returned. Instead `outfunc` will be 18 | called multiple times with a single string parameter: a chunk of the serialized 19 | data. They can be, for example, saved in a file one afther the other; the 20 | resulting file can be read the common lua _load_/_loadstring_ function 21 | 22 | == Example 23 | 24 | [source,lua,example] 25 | ---- 26 | local serialize = require "serialize" 27 | 28 | local tab = {'a', b='b'} 29 | tab.ref = tab 30 | tab[tab] = 'key' 31 | 32 | local rec = serialize(tab) 33 | rec = load( 'return ' .. serialize( tab ))() 34 | 35 | assert( rec ~= tab ) 36 | 37 | assert( rec[1] == 'a' ) 38 | assert( rec.b == 'b' ) 39 | assert( rec.ref == rec ) 40 | assert( rec[rec] == 'key' ) 41 | ---- 42 | 43 | ]===] 44 | 45 | local type = type 46 | 47 | local function basic_representation( value, outfunc ) 48 | local tv = type(value) 49 | if "string" == tv then 50 | outfunc(string.format( "%q", value ):gsub('\n','n')) 51 | return true 52 | elseif "table" ~= tv then 53 | outfunc(tostring( value )) 54 | return true 55 | end 56 | return false 57 | end 58 | 59 | local function serialize( value, outfunc ) --> str 60 | 61 | -- Default ouput function 62 | local result 63 | if not outfunc then 64 | result = {} 65 | outfunc = function(dat) result[1+#result]=dat end 66 | end 67 | 68 | -- Basic/Flat type 69 | if basic_representation( value, outfunc ) then 70 | return result and table.concat(result) or nil 71 | end 72 | 73 | outfunc('((function() local T=\n{') 74 | 75 | -- Table memo 76 | local reference = { value } 77 | local alias = { [value] = 'r' } 78 | local function add_reference( tab ) 79 | if not alias[tab] then 80 | reference[1+#reference]=tab 81 | alias[tab] = 'T[' .. #reference .. ']' 82 | end 83 | end 84 | 85 | -- Loop over all the tables 86 | local t = 0 87 | while true do 88 | t = t + 1 89 | local tab = reference[t] 90 | if tab == nil then break end 91 | if type(tab)=='table'then 92 | 93 | outfunc('{') 94 | 95 | -- Expand basic type or placeholder for the Array part 96 | local already_seen = {} 97 | for k, v in ipairs( tab ) do 98 | if type(v) == 'table' then 99 | add_reference( v ) 100 | outfunc('0,') -- Placeholder, it will be replaced 101 | else 102 | basic_representation( v, outfunc ) 103 | outfunc(',') 104 | end 105 | already_seen[k] = true 106 | end 107 | 108 | for k, v in pairs( tab ) do 109 | if not already_seen[k] then 110 | 111 | -- Mark for placeholder/nested expansion 112 | local skip_expansion = false 113 | if type(k) == 'table' then 114 | add_reference( k ) 115 | skip_expansion = true 116 | end 117 | if type(v) == 'table' then 118 | add_reference( v ) 119 | skip_expansion = true 120 | end 121 | 122 | -- Expand basic type for the Hash part 123 | if not skip_expansion then 124 | outfunc('[') 125 | basic_representation( k, outfunc ) 126 | outfunc(']=') 127 | basic_representation( v, outfunc ) 128 | outfunc(',') 129 | end 130 | end 131 | end 132 | 133 | outfunc('},') 134 | end 135 | end 136 | 137 | outfunc('}') 138 | outfunc('\nlocal r=T[1]') 139 | 140 | -- Override placeholders and nested table references 141 | for _, tab in ipairs(reference) do 142 | for k, v in pairs(tab) do 143 | local table_key = (type(k) == 'table') 144 | local table_value = (type(v) == 'table') 145 | if table_key or table_value then 146 | outfunc('\n') 147 | outfunc(alias[tab]) 148 | outfunc('[') 149 | if table_key then 150 | outfunc(alias[k]) 151 | else 152 | basic_representation( k, outfunc ) 153 | end 154 | outfunc(']=') 155 | if table_value then 156 | outfunc(alias[v]) 157 | else 158 | basic_representation( v, outfunc ) 159 | end 160 | end 161 | end 162 | end 163 | 164 | outfunc('\nreturn r end)())') 165 | 166 | return result and table.concat(result) or nil 167 | end 168 | 169 | return serialize 170 | -------------------------------------------------------------------------------- /src/shellcommand.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = shellcommand 4 | 5 | [source,lua] 6 | ---- 7 | function shellcommand( commandTab ) --> commandStr 8 | ---- 9 | 10 | Construct the shell command string `commandStr`, suitable to be executed by 11 | `os.execute`. The input is the array of strings `commandTab`, the first being 12 | the external command path, the other being all the arguments. 13 | 14 | Command path and argument strings can contain characters that have special 15 | meaning for the shell: they will be quoted. 16 | 17 | The `commandTab` argument can contain also the following key, that have a 18 | special meaning: 19 | 20 | - `input`: the generated command will instruct the shell to get the standard 21 | console input of the command from a file; the path to this file is the one 22 | containied in this table field 23 | - `output`: the generated command will instruct the shell to put the standard 24 | console ouput and error of the command into a file; the path to this file is 25 | the one containied in this table field 26 | - `append`: if true and the `output` field is also set, the ouput will be 27 | appended to the file instead of overwrite previous data 28 | 29 | == Example 30 | 31 | [source,lua,example] 32 | ---- 33 | local shellcommand = require 'shellcommand' 34 | 35 | local lua = 'lua' 36 | for a = 0, -99, -1 do 37 | if not arg[a] then break end 38 | lua = arg[a] 39 | end 40 | 41 | local cmd = shellcommand{lua, '-e', 'io.open([[tmp.tmp]],[[w]]):write(arg[0]);os.exit()', " '"} 42 | 43 | os.remove('tmp.tmp') 44 | os.execute(cmd) 45 | 46 | assert( " '" == io.open('tmp.tmp','r'):read('a') ) 47 | ---- 48 | 49 | ]===] 50 | 51 | local escapeshellarg = (function() 52 | -- [SNIP:escapeshellarg.lua[ 53 | local quote_function 54 | 55 | local function escapeshellarg( str ) --> esc 56 | 57 | local function posix_quote_argument(str) 58 | if not str:match('[^%a%d%.%-%+=/,:]') then 59 | return str 60 | else 61 | str = str:gsub( "[$`\"\\]", "\\%1" ) 62 | return '"' .. str .. '"' 63 | end 64 | end 65 | 66 | local function windows_quote_argument(str) 67 | str = str:gsub('[%%&\\^<>|]', '^%1') 68 | str = str:gsub('"', "\\%1") 69 | str = str:gsub('[ \t][ \t]*', '"%1"') 70 | return str 71 | end 72 | 73 | if not quote_function then 74 | quote_function = windows_quote_argument 75 | local shell = os.getenv('SHELL') 76 | if shell then 77 | if '/' == shell:sub(1,1) and 'sh' == shell:sub(-2, -1) then 78 | quote_function = posix_quote_argument 79 | end 80 | end 81 | end 82 | 83 | return quote_function(str) 84 | end 85 | 86 | return escapeshellarg 87 | -- ]SNIP:escapeshellarg.lua] 88 | end)() 89 | 90 | local function shellcommand( commandTab ) --> commandStr 91 | if not commandTab then return '' end 92 | local commandStr = '' 93 | for _, v in ipairs(commandTab) do 94 | commandStr = commandStr .. ' ' .. escapeshellarg(v) 95 | end 96 | local ri = ' < ' 97 | local ro = ' > ' 98 | local re = ' 2> ' 99 | local moe = '' 100 | if commandTab.append then 101 | ro = ' >> ' 102 | re = ' 2>> ' 103 | end 104 | if commandTab.output == commandTab.error then 105 | commandTab.error = nil 106 | moe = ' 2>&1' 107 | end 108 | if commandTab.input then 109 | commandStr = commandStr .. ri .. escapeshellarg(commandTab.input) .. moe 110 | end 111 | if commandTab.output then 112 | commandStr = commandStr .. ro .. escapeshellarg(commandTab.output) .. moe 113 | end 114 | if commandTab.error then 115 | commandStr = commandStr .. re .. escapeshellarg(commandTab.error) .. moe 116 | end 117 | return commandStr 118 | end 119 | 120 | return shellcommand 121 | -------------------------------------------------------------------------------- /src/simplepath.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = simplepath 4 | 5 | [source,lua] 6 | ---- 7 | function simplepath( pathIn ) --> pathOut 8 | ---- 9 | 10 | Simplify the path contained in the string 'pathIn'. It return a 11 | simpler string 'pathOut' with the following expansion 12 | 13 | - . means 'last directory', so it is just removed 14 | - .. means 'parent directory', so it will remove the previous directory (unless 15 | it is at beginning of the path) 16 | 17 | == Example 18 | 19 | [source,lua,example] 20 | ---- 21 | local simplepath = require 'simplepath' 22 | 23 | local sps = function(x) return x:gsub("/", package.config:sub(1,1)) end 24 | 25 | assert( simplepath(sps'A/B/./C/../D') == sps'A/B/D' ) 26 | 27 | ---- 28 | 29 | ]===] 30 | 31 | local dirsep = package.config:sub(1,1) 32 | local splitpat = '[^'..dirsep..']+' 33 | 34 | local function simplepath( pathIn ) --> pathOut, errorStr 35 | local result = {} 36 | for part in pathIn:gmatch( splitpat ) do 37 | if part ~= '.' then 38 | if part ~= '..' then 39 | table.insert( result, part ) 40 | else 41 | local nres = #result 42 | if nres > 0 and result[nres] ~= '..' then 43 | result[nres] = nil 44 | else 45 | table.insert( result, '..' ) 46 | end 47 | end 48 | end 49 | end 50 | local pathOut = table.concat( result, dirsep ) 51 | if pathIn:sub(1,1) == dirsep then pathOut = dirsep..pathOut end 52 | if pathOut == '' then 53 | pathOut = '.' 54 | end 55 | return pathOut 56 | end 57 | 58 | return simplepath 59 | -------------------------------------------------------------------------------- /src/tapfail.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = tapfail 4 | 5 | [source,lua] 6 | ---- 7 | local function tapfail( ) --> streamFunc( lineStr ) --> errorStr 8 | ---- 9 | 10 | With this function, a stream in the TAP format can be searched for errors (Test 11 | Anything Protocol). Itself returns the `streamFunc` function that performs the 12 | real analisys. 13 | 14 | `streamFunc` must be called on each line of the TAP stream and it will return 15 | `nil` if no error was found. Otherwise it will return the `errorStr` string 16 | describint the error. 17 | 18 | At the end of the stream, `streamFunc` should be called the last time, without 19 | any argument, to perform the last checks (e.g. a proper summary line was 20 | found). 21 | 22 | When called without argument, `streamFunc` will always return the last found 23 | error (in the current as in the previous calls). 24 | 25 | == Example 26 | 27 | [source,lua,example] 28 | ---- 29 | local tapfail = require 'tapfail' 30 | 31 | ts = tapfail() 32 | 33 | assert( ts'ok 1' == nil ) 34 | assert( ts'#not ok masked by diagnostic' == nil ) 35 | assert( ts'1..1' == nil ) 36 | assert( ts'ok 2' == 'line after summary' ) 37 | ---- 38 | 39 | ]===] 40 | 41 | local function ton( x ) 42 | local _, x = pcall(function() return tonumber(x) end) 43 | if x < 0 then return nil end 44 | if x ~= math.modf(x) then return nil end 45 | return x 46 | end 47 | 48 | local function tapfail( ) --> streamFunc( lineStr ) --> errorStr 49 | local summary 50 | local summary_line 51 | local testcount = 0 52 | local l = 0 53 | 54 | local function check_line( line ) 55 | if line == '' then 56 | return nil 57 | elseif line:match('^#') then 58 | return nil 59 | else 60 | 61 | local ok = line:match('^ok (%d*)') 62 | if ok then 63 | if summary_line and l > summary_line and summary_line ~= 1 then 64 | return 'line after summary' 65 | end 66 | ok = ton( ok ) 67 | if not ok then ok = -9 end 68 | local deltacount = ok - testcount 69 | testcount = ok 70 | if deltacount ~= 1 then 71 | return 'invalid count sequence' 72 | end 73 | end 74 | 75 | local sum = line:match('^1%.%.(.*)') 76 | if sum == 'N' then 77 | sum = true 78 | elseif sum then 79 | sum = ton( sum ) 80 | end 81 | if sum then 82 | summary = sum 83 | if not summary_line then 84 | summary_line = l 85 | else 86 | return 'summary already found at line '..summary_line 87 | end 88 | end 89 | 90 | if not ok and not diag and not summary then 91 | return 'no diagnostic or ok line' 92 | end 93 | 94 | if not result and summary and summary ~= true then 95 | if summary_line==l and l > 1 and summary ~= testcount then 96 | return 'invalid test count' 97 | elseif summary testcount then 113 | last_error = 'missing test' 114 | end 115 | return last_error 116 | end 117 | 118 | l = l + 1 119 | local result = check_line( line ) 120 | 121 | if result then last_error = result end 122 | return result 123 | end 124 | 125 | return tapchunk 126 | end 127 | 128 | return tapfail 129 | -------------------------------------------------------------------------------- /src/templua.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = templua 4 | 5 | [source,lua] 6 | ---- 7 | function templua( template ) --> ( sandbox ) --> expstr, err 8 | ---- 9 | 10 | Expand the Lua code contained in the `template` string and generates a 11 | function. The returned function, when called, will execute the lua code in the 12 | `template` and it will return the template `expstr` result string. 13 | 14 | The code in the `template` can be specified with the following patterns: 15 | 16 | `@{luaexp}`:: 17 | Will be substituted with the result of the Lua expression. 18 | 19 | `@{{luastm}}`:: 20 | Embeds the Lua statement. This allow to mix Lua code and verbatim text. 21 | 22 | From the code in the statement pattern, an utility function can be used to 23 | produce the `template` output. The function is in the local variable `out`. If 24 | you need to access a field of the passed environment that have the same name, 25 | you can use '_ENV.out'. 26 | 27 | The `sandbox` table is used as the environment of the Lua code (both 28 | expressions and statements). This allows you to pass parameters to the 29 | template. 30 | 31 | To escape the template sequencies, `@` can be substituded with `@{"@"}`, e.g. 32 | `@{"@"}{error()}` can be used to insert `@{error()}` in the document without 33 | expanding it. 34 | 35 | == Example 36 | 37 | [source,lua,example] 38 | ---- 39 | local templua = require( "templua" ) 40 | 41 | assert( templua( "Hello @{W}!" )({ W = "world" }) == "Hello world!") 42 | 43 | local exp = templua( "Hello @{upper(W)}!" ) 44 | assert( exp{ W = "Anne", upper = string.upper } == "Hello ANNE!") 45 | assert( exp{ W = "Bob", upper = string.upper } == "Hello BOB!") 46 | 47 | assert( templua( "@{{for i=1,3 do}}Hello All! @{{end}}" )({}) 48 | == 'Hello All! Hello All! Hello All! ' ) 49 | ---- 50 | 51 | ]===] 52 | 53 | local setmetatable, load = setmetatable, load 54 | local fmt, tostring = string.format, tostring 55 | local error = error 56 | 57 | local function templua( template ) --> ( sandbox ) --> expstr, err 58 | local function expr(e) return ' out('..e..')' end 59 | 60 | -- Generate a script that expands the template 61 | local script, position, max = '', 1, #template 62 | while position <= max do -- TODO : why '(.-)@(%b{})([^@]*)' is so much slower? The loop is needed to avoid a simpler gsub on that pattern! 63 | local start, finish = template:find('@%b{}', position) 64 | if not start then 65 | script = script .. expr( fmt( '%q', template:sub(position, max) ) ) 66 | position = max + 1 67 | else 68 | if start > position then 69 | script = script .. expr( fmt( '%q', template:sub(position, start-1) ) ) 70 | end 71 | if template:match( '^@{{.*}}', start ) then 72 | script = script .. template:sub( start+3, finish-2 ) 73 | else 74 | script = script .. expr( template:sub( start+2, finish-1 ) ) 75 | end 76 | position = finish + 1 77 | end 78 | end 79 | 80 | -- Utility to append the script to the error string 81 | local function report_error( err ) 82 | return nil, err..'\nTemplate script: [[\n'..script..'\n]]' 83 | end 84 | 85 | -- Special case when no template tag is found 86 | if script == template then 87 | return function() return script end 88 | end 89 | 90 | -- Compile the template expander in a empty environment 91 | local env = {} 92 | script = 'local out = _ENV.out; local _ENV = _ENV.env; ' .. script 93 | local generate, err = load( script, 'templua_script', 't', env ) 94 | if err ~= nil then return report_error( err ) end 95 | 96 | -- Return a function that runs the expander with a custom environment 97 | return function( sandbox ) 98 | 99 | -- Template environment and utility function 100 | local expstr = '' 101 | env.env = sandbox 102 | env.out = function( out ) expstr = expstr..tostring(out) end 103 | 104 | -- Run the template 105 | local ok, err = pcall(generate) 106 | if not ok then return report_error( err ) end 107 | return expstr 108 | end 109 | end 110 | 111 | return templua 112 | -------------------------------------------------------------------------------- /src/timeprof.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = timeprof 4 | 5 | [source,lua] 6 | ---- 7 | function timeprof( argTyp [, optTyp] ) --> timerObj 8 | function timerObj.start( self ) -> nil 9 | function timerObj.stop( self ) -> nil 10 | function timerObj.reset( self ) -> nil 11 | function timerObj.summary( self ) -> fulltimeNum, meantimeNum, errortimeNum 12 | ---- 13 | 14 | `timeprof` return an `timeObj` object that can be used to measure code execution time.If no argument is passed, a new timer is returned. Otherwise, on multiple invocation, same timers are returned when same arguments are passed. 15 | 16 | The `timerObj` interface contains four function that must be called with the lua object-method syntax: 17 | 18 | - `timerObj:start()` will start to measure the elapsed time 19 | - `timerObj:stop()` will stop to measure the elapsed time 20 | - `timerObj:reset()` will reset all the collected time measurements 21 | - `timerObj:summary()` will return the time statistics 22 | 23 | The returned statistic are the following three number: 24 | 25 | - `fulltimeNum` is the sum of all the elapsed time between all the `start` and the consecutive `stop` 26 | - `meantimeNum` is the mean of all the measurements 27 | - `errortimeNum` is the statistical error of the mean 28 | 29 | ]===] 30 | 31 | local clock, sqrt = os.clock, math.sqrt 32 | 33 | local checkpoint = setmetatable({}, {mode="kv"}) 34 | 35 | local function timeprof_start(self) 36 | self.time_last = clock() 37 | end 38 | 39 | local function timeprof_stop(self) 40 | if self.time_last > 0 then 41 | local time_delta = clock() - self.time_last 42 | self.time_last = -1 43 | self.time_step = self.time_step + 1 44 | self.time_sum = self.time_sum + time_delta 45 | self.time_square_sum = self.time_square_sum + (time_delta * time_delta) 46 | end 47 | end 48 | 49 | local function timeprof_summary(self) 50 | local ts = self.time_sum 51 | local n = self.time_step 52 | if self.time_step < 2 then return ts, ts, 0 end 53 | return ts, ts/n, sqrt((self.time_square_sum - ts*ts/n)/(n-1)) 54 | end 55 | 56 | local function timeprof_reset(self) 57 | self.time_sum = 0 58 | self.time_square_sum = 0 59 | self.time_step = 0 60 | end 61 | 62 | local function timeprof( checkpointVal ) --> resTyp 63 | local resTyp 64 | if checkpointVal then resTyp = checkpoint[ checkpointVal ] end 65 | if not checkpointVal or not resTyp then 66 | resTyp = { 67 | start = timeprof_start, 68 | stop = timeprof_stop, 69 | reset = timeprof_reset, 70 | summary = timeprof_summary, 71 | } 72 | resTyp:reset() 73 | if checkpointVal then 74 | checkpoint[ checkpointVal ] = resTyp 75 | else 76 | checkpoint[ resTyp ] = resTyp 77 | end 78 | end 79 | return resTyp 80 | end 81 | 82 | return timeprof 83 | -------------------------------------------------------------------------------- /src/toposort.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = toposort 4 | 5 | [source,lua] 6 | ---- 7 | function toposort( dependenceTab ) --> orderArr 8 | ---- 9 | 10 | Topological sort the `dependenceTab` table. It returns the `orderArr` array 11 | containing the all the items sorted with respect to the input dependencies. 12 | 13 | Each key of `dependeceTab` is an item to sort. The value associated to each of 14 | them must be an array containing the dependency of the item. 15 | 16 | == Example 17 | 18 | [source,lua,example] 19 | ---- 20 | local toposort = require 'toposort' 21 | 22 | local order = toposort{x={'e'},a={'x'},} 23 | assert( order[1] == 'e' ) 24 | assert( order[2] == 'x' ) 25 | assert( order[3] == 'a' ) 26 | assert( #order == 3 ) 27 | 28 | local order, err = toposort{a={'b'},b={'a'}} 29 | assert( err == 'cycle detected' ) 30 | assert( order == nil ) 31 | 32 | ---- 33 | 34 | ]===] 35 | 36 | local pairs, ipairs = pairs, ipairs 37 | 38 | local function toposort( depTab ) --> orderArr 39 | depTab = depTab or {} 40 | local status, orderArr, tovisit, o, n = {}, {}, {}, 0, 0 41 | for node in pairs( depTab ) do 42 | local stat = status[node] 43 | if not stat then 44 | n = n + 1 45 | tovisit[n] = node 46 | repeat 47 | local dlist = not stat and depTab[node] 48 | if dlist then 49 | for _, depend in ipairs(dlist) do 50 | local dstat = status[depend] 51 | if not dstat then -- just an optimization 52 | n = n + 1 53 | tovisit[n] = depend 54 | elseif dstat == 'seen' then -- seen but not pushed -> cycle detected 55 | return nil, 'cycle detected', orderArr 56 | end 57 | end 58 | else 59 | if stat ~= 'pushed' then 60 | o = o + 1 61 | orderArr[o] = node 62 | end 63 | tovisit[n] = nil 64 | n = n - 1 65 | status[node] = 'pushed' 66 | end 67 | status[node] = status[node] or 'seen' 68 | node = tovisit[n] 69 | stat = status[node] 70 | until n <= 0 71 | end end 72 | return orderArr 73 | end 74 | 75 | return toposort 76 | -------------------------------------------------------------------------------- /src/trimstring.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = trimstring 4 | 5 | [source,lua] 6 | ---- 7 | function trimstring( inStr ) --> trimStr 8 | ---- 9 | 10 | Remove starting or tailing white character from the `inStr` input string. 11 | 12 | == Example 13 | 14 | [source,lua,example] 15 | ---- 16 | local trimstring = require 'trimstring' 17 | 18 | assert( trimstring(' \nstr\r\t ') == 'str' ) 19 | ---- 20 | 21 | ]===] 22 | 23 | local function trimstring( inStr ) --> trimStr 24 | return inStr:match('^[ %c]*(.-)[ %c]*$') 25 | end 26 | 27 | return trimstring 28 | -------------------------------------------------------------------------------- /src/tuple.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = tuple 4 | 5 | [source,lua] 6 | ---- 7 | function tuple( ... ) --> tupleTable 8 | ---- 9 | 10 | Constructs a tuple type, i.e. an object representing an unmodifiable list of 11 | fields. 12 | 13 | It returns the `tupleTable` table that allows to read the tuple fields, but it 14 | forbit the modification of the fields. 15 | 16 | When called with same arguments, the same table reference will be returned. The 17 | unused reference will be automatically garbage collected. 18 | 19 | == Inspired by 20 | 21 | * http://lua-users.org/wiki/SimpleTuples 22 | 23 | == Example 24 | 25 | [source,lua,example] 26 | ---- 27 | local tuple = require 'tuple' 28 | 29 | local field = tuple(1,nil,0/0,3) 30 | assert( field.n == 4 ) 31 | assert( field[1] == 1 ) 32 | assert( field[2] == nil ) 33 | assert( field[3] ~= field[3] ) 34 | assert( field[4] == 3 ) 35 | 36 | local again = tuple(1,nil,0/0,3) 37 | assert( field == again ) 38 | ---- 39 | 40 | ]===] 41 | 42 | local intern = (function() 43 | -- [SNIP:intern.lua[ 44 | local function intern() --> reference 45 | 46 | local rawget, rawset, select, setmetatable = 47 | rawget, rawset, select, setmetatable, select 48 | local NIL, NAN = {}, {} 49 | 50 | local internmeta = { 51 | __index = function() error('Can not access interned content directly.', 2) end, 52 | __newindex = function() error('Can not cahnge or add contents to a intern.', 2) end, 53 | } 54 | 55 | local internstore = setmetatable( {}, { __mode = "kv" } ) 56 | 57 | -- A map from child to parent is used to protect the internstore table's contents. 58 | -- In this way, they will he collected only when all the cildren are collected 59 | -- in turn. 60 | local parent = setmetatable( {}, { __mode = 'k' }) 61 | 62 | return function( ... ) 63 | local currentintern = internstore 64 | for a = 1, select( '#', ... ) do 65 | 66 | -- Get next intern field. Replace un-storable contents. 67 | local tonext = select( a, ... ) 68 | if tonext ~= tonext then tonext = NAN end 69 | if tonext == nil then tonext = NIL end 70 | 71 | -- Get or create the correspondent sub-intern 72 | local subintern = rawget( currentintern, tonext ) 73 | if subintern == nil then 74 | 75 | subintern = setmetatable( {}, internmeta ) 76 | parent[subintern] = currentintern 77 | rawset( currentintern, tonext, subintern ) 78 | end 79 | 80 | currentintern = subintern 81 | end 82 | return currentintern 83 | end 84 | end 85 | 86 | return intern 87 | -- ]SNIP:intern.lua] 88 | end)() 89 | 90 | local select, getmetatable, setmetatable = select, getmetatable, setmetatable 91 | 92 | local tuplefact = intern() 93 | 94 | local function tuple( ... ) --> tupleTable 95 | 96 | local tupleTable = tuplefact( ... ) 97 | if not getmetatable( tupleTable ).__type then -- First time initialization 98 | 99 | -- Store fields 100 | -- local n = select( '#', ... ) 101 | -- local fields = { n=n, ... } 102 | -- for i = 1, fields.n do fields[i] = select( i, ... ) end 103 | local fields = { ... } 104 | fields.n = select( '#', ... ) 105 | 106 | -- Dispatch to the stored fields, and forbid modification 107 | setmetatable( tupleTable, { 108 | type = 'tuple', 109 | __index = function( t, k ) return fields[k] end, 110 | __newindex = function( t, k ) return error( 'can not change tuple field', 2 ) end, 111 | }) 112 | 113 | end 114 | return tupleTable 115 | end 116 | 117 | return tuple 118 | -------------------------------------------------------------------------------- /src/uniontab.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = uniontab 4 | 5 | [source,lua] 6 | ---- 7 | function uniontab( firstTab, secondTab[, selectFunc] ) --> unionTab 8 | ---- 9 | 10 | Creates the `unionTabl` table that contain all the keys of the `firstTab` and 11 | `secondTab` tables. 12 | 13 | When both the table have the same key the value of the first table will be 14 | used. This can be changed passing the optional `selectFunc` function. It will 15 | be called with both the values as arguments, and its result will be used in the 16 | union table. 17 | 18 | == Example 19 | 20 | [source,lua,example] 21 | ---- 22 | local uniontab = require 'uniontab' 23 | 24 | local union = uniontab({a='a',c='c'},{b='b',c='C'}) 25 | assert( union.a == 'a') 26 | assert( union.b == 'b') 27 | assert( union.c == 'c') 28 | 29 | local union = uniontab({a='a',c='c'},{b='b',c='C'}, function(x,y)return y end) 30 | assert( union.a == 'a') 31 | assert( union.b == 'b') 32 | assert( union.c == 'C') 33 | ---- 34 | 35 | ]===] 36 | 37 | local function uniontab( firstTab, secondTab, selectFunc ) --> unionTab 38 | local unionTab = {} 39 | if secondTab then 40 | for k, v in pairs(secondTab) do unionTab[k] = v end 41 | end 42 | if not firstTab then return unionTab end 43 | for k, v in pairs(firstTab) do 44 | local o = unionTab[k] 45 | if not o then 46 | unionTab[k] = v 47 | else 48 | if not selectFunc then 49 | unionTab[k] = v 50 | else 51 | unionTab[k] = selectFunc(v, o) 52 | end 53 | end 54 | end 55 | return unionTab 56 | end 57 | 58 | return uniontab 59 | -------------------------------------------------------------------------------- /src/valueprint.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = valueprint 4 | 5 | [source,lua] 6 | ---- 7 | function valueprint( value [, formatFunc] ) --> str 8 | ---- 9 | 10 | It return `str` an human readable representation of the input value `value`. 11 | If the value is a function or user data it return a reference. If it is a 12 | non-aggregated lua type, the returned string contains just a lua literal 13 | representing the value. 14 | 15 | If the value is a table, it is expanded as a list of key/value pairs. If a 16 | table is found as key, the reference only is printed. If the value contained in 17 | the key is an already printed table, the reference only is printed. If the 18 | value contains a new table, the key/value pairs are recursively printed. 19 | 20 | These limitations are needed in order to avoid issues with loops or with hard 21 | to read results. This function is ment only for human inspection: for an 22 | accurate table dump, see the `serialize` module. 23 | 24 | The optional `formatFunc` value can be used to change the default table output 25 | style. If the string "lua" is passed, a lua-parsable literal will be emitted. 26 | If It is a function, it will called for each key/value pair. It will be also 27 | called when a entering or quitting a sub-table. The result of the function must 28 | be a string that will be appended to the final result. 29 | 30 | When called on key/value pair the `formatFunc` will get the following 31 | arguments: 32 | 33 | - A string representing the key 34 | - A string representing the content 35 | - A depth index 36 | - An info string i.e. the type of the content 37 | 38 | When called on the entering/quitting of a sub-table, the key will be nil and 39 | the info string will be the string 'in' or 'out'. 40 | 41 | == Example 42 | 43 | [source,lua,example] 44 | ---- 45 | local valueprint = require "valueprint" 46 | 47 | assert( valueprint"1\n2" == '"1\\n2"' ) 48 | 49 | assert( valueprint({a={b="c"}}):match[[ 50 | ^table 0?x?%x* 51 | | "a": table 0?x?%x* 52 | | | "b": "c"$]]) 53 | ---- 54 | 55 | ]===] 56 | 57 | local function print_basic( cur ) 58 | if "string" == type( cur ) then 59 | return string.format( "%q", cur ):gsub( '\n', 'n' ) 60 | else 61 | return tostring( cur ):gsub( ':', '' ) 62 | end 63 | end 64 | 65 | local function print_with_annotation( cur, memo ) 66 | local s = print_basic( cur ) 67 | if type(cur) == 'table' then 68 | if memo == true or memo[cur] then 69 | s = s .. ' content is not shown here' 70 | end 71 | end 72 | return s 73 | end 74 | 75 | local function print_record( key, value, depth, info ) 76 | return (key and '\n'..('| '):rep(depth)..key..': '..value) 77 | or (depth == 1 and info == 'in' and value) or '' 78 | end 79 | 80 | local function print_record_lua( k, v, d, i ) 81 | local y = '' 82 | if not k then 83 | if i == 'in' then 84 | y = '{ --[[' .. v .. ']]\n' 85 | elseif i == 'out' then 86 | y = ((' '):rep(d)) .. '},\n' 87 | end 88 | else 89 | if k ~= 'true' and k ~= 'false' and not tonumber(k) and k:sub(1,1) ~= '"' then 90 | k = '"'..k..'"' 91 | end 92 | y = y .. ((' '):rep(d+1)) .. '[' .. k .. '] = ' 93 | if i ~= 'table' then 94 | y = y .. v .. ',\n' 95 | end 96 | end 97 | return y 98 | end 99 | 100 | local function valueprint( value, format ) --> str 101 | 102 | local memo = {} 103 | if format == 'default' then format = print_record end 104 | if format == 'lua' then format = print_record_lua end 105 | if 'function' ~= type(format) then format = print_record end 106 | 107 | local function valueprint_rec( cur, depth ) 108 | 109 | -- Flat type pr already processed table 110 | if "table" ~= type(cur)then 111 | return print_with_annotation( cur ) 112 | end 113 | 114 | local subtab = {} 115 | 116 | -- Start table iteration 117 | local is_hidden = ' content not shown here' 118 | local ref = print_with_annotation( cur, memo ) 119 | table.insert( subtab, format( nil, ref, depth, 'in')) 120 | 121 | -- Recurse over each key and each value 122 | if not memo[cur] then 123 | memo[cur] = true 124 | for k, v in pairs( cur ) do 125 | k = print_with_annotation( k, true ) 126 | local vs = print_with_annotation( v, memo ) 127 | table.insert( subtab, format( k, vs, depth, type( v )) or '' ) 128 | if 'table' == type(v) then 129 | table.insert( subtab, valueprint_rec( v, depth+1 ) or '') 130 | end 131 | end 132 | end 133 | 134 | -- -- End table iteration 135 | table.insert( subtab, format( nil, ref, depth, 'out')) 136 | 137 | return table.concat( subtab ) 138 | end 139 | return valueprint_rec( value, 1 ) 140 | end 141 | 142 | return valueprint 143 | -------------------------------------------------------------------------------- /test/appendfile.ex1.lua: -------------------------------------------------------------------------------- 1 | local appendfile = require "appendfile" 2 | local t = require "testhelper" 3 | 4 | os.remove( "appendfile.txt" ) 5 | 6 | t( appendfile( "appendfile.txt", "123" ), true ) 7 | t( t.readfile( "appendfile.txt" ), "123" ) 8 | 9 | t( appendfile( "appendfile.txt", "456" ), true ) 10 | t( t.readfile( "appendfile.txt" ), "123456" ) 11 | 12 | t( appendfile( "appendfile.txt", { "7","8" } ), true ) 13 | t( t.readfile( "appendfile.txt" ), "12345678" ) 14 | 15 | t( appendfile( "appendfile.txt", {"9","10"}, "<", ">" ), true ) 16 | t( t.readfile( "appendfile.txt" ), "12345678<9><10>" ) 17 | 18 | t.test_embedded_example() 19 | 20 | os.remove( "appendfile.txt" ) 21 | 22 | t() 23 | -------------------------------------------------------------------------------- /test/argcheck.ex1.lua: -------------------------------------------------------------------------------- 1 | local a = require 'argcheck' 2 | local t = require 'testhelper' 3 | 4 | local function argcheck(...) return t.filterr(a, ...) end 5 | 6 | t( argcheck({}), nil ) 7 | t( argcheck({}, 1), 'Invalid number of arguments. Must be 0 not 1.' ) 8 | 9 | t( argcheck({'number'}, 1), nil ) 10 | t( argcheck({'number'}, 'a'), 'Invalid argument #1 type. Must be number not string.' ) 11 | t( argcheck({'boolean'}, 'a'), 'Invalid argument #1 type. Must be boolean not string.' ) 12 | t( argcheck({'string'}, false), 'Invalid argument #1 type. Must be string not boolean.' ) 13 | t( argcheck({'table'}, false), 'Invalid argument #1 type. Must be table not boolean.' ) 14 | 15 | t( argcheck({'number','string','boolean'}, 1, 'a', false), nil ) 16 | t( argcheck({'number','string','boolean'}, 1, false, false), 'Invalid argument #2 type. Must be string not boolean.' ) 17 | 18 | t.test_embedded_example() 19 | 20 | t() 21 | -------------------------------------------------------------------------------- /test/bitpad.ex1.lua: -------------------------------------------------------------------------------- 1 | 2 | local bitpad = require 'bitpad' 3 | local t = require 'testhelper' 4 | 5 | t( bitpad(0, 0, ''), '', t.bytesame ) 6 | 7 | t( bitpad(8, 8, '\x0F\x0F\x0F'), '\0\x0F\0\x0F\0\x0F', t.bytesame ) 8 | 9 | t( bitpad(7, 1, '\x0F'), '\x00\x00\x00\x00\x01\x01\x01\x01', t.bytesame ) 10 | t( bitpad(15, 1, '\x0F'), '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01\x00\x01\x00\x01', t.bytesame ) 11 | 12 | t( bitpad(6, 2, '\x0F'), '\x00\x00\x03\x03', t.bytesame ) 13 | t( bitpad(4, 4, '\x0F'), '\x00\x0F', t.bytesame ) 14 | 15 | t( bitpad(5, 3, '\x0F'), '\x00\x03\x06', t.bytesame ) 16 | t( bitpad(5, 3, '\x0F\x0F'), '\x00\x03\x06\x00\x07\x04', t.bytesame ) 17 | t( bitpad(5, 3, '\x0F\x81'), '\x00\x03\x07\x00\x00\x04', t.bytesame ) 18 | 19 | t( bitpad(12, 4, '\xFF'), '\x00\x0F\x00\x0F', t.bytesame ) 20 | 21 | t( bitpad(2, 2, '\xFF'), '\x33\x33', t.bytesame ) 22 | 23 | t( bitpad(3, 3, '\xFF'), '\x1C\x71\x80', t.bytesame ) 24 | t( bitpad(3, 3, '\xFF\xFF'), '\x1C\x71\xC7\x1C\x40', t.bytesame ) 25 | 26 | t( bitpad(-1, 1, '\xFF'), '\xF0', t.bytesame ) 27 | t( bitpad(-1, 1, '\xFF\xFF'), '\xFF', t.bytesame ) 28 | t( bitpad(-1, 1, '\xFF\xFF\xFF'), '\xFF\xF0', t.bytesame ) 29 | 30 | t( bitpad(-2, 1, '\xFF'), '\xC0', t.bytesame ) 31 | t( bitpad(-2, 1, '\xFF\xFF'), '\xF8', t.bytesame ) 32 | t( bitpad(-2, 1, '\xFF\xFF\xFF'), '\xFF', t.bytesame ) 33 | 34 | t( bitpad(-7, 1, '\x01\x01\x01\x01\x01\x01\x01\x01'), '\xFF', t.bytesame ) 35 | 36 | t( bitpad(-4, 4, '\xFF'), '\xF0', t.bytesame ) 37 | t( bitpad(-4, 4, '\xFF\xFF'), '\xFF', t.bytesame ) 38 | t( bitpad(-4, 4, '\xFF\xFF\xFF'), '\xFF\xF0', t.bytesame ) 39 | 40 | t( bitpad(-4, 4, (bitpad(4, 4, '\x13'))), '\x13', t.bytesame ) 41 | t( bitpad(-2, 3, (bitpad(2, 3, '\x13'))), '\x13\x00', t.bytesame ) -- additional padding 42 | 43 | t( bitpad(4, 4, '\x01\x00'), '\x00\x01\x00\x00', t.bytesame ) 44 | t( bitpad(4, 4, '\x01\x00', {'\xFF'}), '\xFF\x01\xFF\xFF', t.bytesame ) 45 | t( bitpad(4, 4, '\x01\x00', {'\xFF','\xF0'}), '\xFF\xF0\xFF\xFF', t.bytesame ) 46 | 47 | t( bitpad(-4, 4, '\x00\x01'), '\x01', t.bytesame ) 48 | t( bitpad(-4, 4, '\x00\x01', {'\x00','\xFF'}), '\xFF', t.bytesame ) 49 | 50 | t( bitpad(4, 4, '\x01\x00'), '\x00\x01\x00\x00', t.bytesame ) 51 | t( bitpad(4, 4, '\x01\x00', nil, {'\x02',}), '\x00\x01\x00\x02', t.bytesame ) 52 | t( bitpad(4, 4, '\x01\x00', nil, {'\x02','\xFF'}), '\x0F\x0F\x00\x02', t.bytesame ) 53 | 54 | t( bitpad(-4, 4, '\x01\x00'), '\x10', t.bytesame ) 55 | t( bitpad(-4, 4, '\x01\x00', nil, {'\x02','\x01'}), '\x12', t.bytesame ) 56 | 57 | t( bitpad(16, 8, '\x01\x01'), '\x00\x00\x01\x00\x00\x01', t.bytesame ) 58 | t( bitpad(-16, 8, '\xFF\xFF\x00\xFF\xFF\x00'), '\x00\x00', t.bytesame ) 59 | 60 | t( bitpad(4, 12, '\xFF\xFF\xFF'), '\x0F\xFF\x0F\xFF', t.bytesame ) 61 | t( bitpad(-4, 12, '\x0F\xFF\x0F'), '\xFF\xFF', t.bytesame ) 62 | 63 | local _,b 64 | 65 | _, b = bitpad(1, 8, '\x00') t( b, 7 ) 66 | _, b = bitpad(1, 8, '\x00\x00') t( b, 6 ) 67 | _, b = bitpad(1, 8, '\x00\x00\0\0\0\0\0') t( b, 1 ) 68 | _, b = bitpad(1, 8, '\x00\x00\0\0\0\0\0\0') t( b, 0 ) 69 | 70 | _, b = bitpad(-1, 8, '\x00') t( b, 1 ) 71 | _, b = bitpad(-1, 8, '\x00\x00') t( b, 2 ) 72 | _, b = bitpad(-1, 8, '\x00\x00\0\0\0\0\0') t( b, 7 ) 73 | _, b = bitpad(-1, 8, '\x00\x00\0\0\0\0\0\0') t( b, 0 ) 74 | 75 | t( bitpad(4, 4, '\xFF\xFF\xFF'), '\x0F\x0F\x0F\x0F\x0F\x0F', t.bytesame ) 76 | t( bitpad(4, 4, '\xFF\xFF\xFF',nil,nil,4), '\xF0\xF0\xF0\xF0\xF0\xF0', t.bytesame ) 77 | t( bitpad(4, 4, '\xFF\xFF\xFF',nil,nil,2), '\xC3\xC3\xC3\xC3\xC3\xC3', t.bytesame ) 78 | t( bitpad(4, 4, '\xFF\xFF\xFF',nil,nil,3), '\xE1\xE1\xE1\xE1\xE1\xE1', t.bytesame ) 79 | t( bitpad(-4, 4, '\x0F\x0F\x0F\x0F\x0F\x0F'), '\xFF\xFF\xFF', t.bytesame ) 80 | t( bitpad(-4, 4, '\xF0\xF0\xF0\xF0\xF0\xF0',nil,nil,4), '\xFF\xFF\xFF', t.bytesame ) 81 | t( bitpad(-4, 4, '\xC3\xC3\xC3\xC3\xC3\xC3',nil,nil,2), '\xFF\xFF\xFF', t.bytesame ) 82 | t( bitpad(-4, 4, '\xE1\xE1\xE1\xE1\xE1\xE1',nil,nil,3), '\xFF\xFF\xFF', t.bytesame ) 83 | 84 | t.test_embedded_example() 85 | 86 | t() 87 | 88 | -------------------------------------------------------------------------------- /test/clearfile.ex1.lua: -------------------------------------------------------------------------------- 1 | local clearfile = require 'clearfile' 2 | local t = require 'testhelper' 3 | 4 | t.removefile( 'tmp.txt' ) 5 | clearfile'tmp.txt' 6 | t( t.readfile'tmp.txt', '' ) 7 | 8 | t.writefile( 'tmp.txt', 'xxx' ) 9 | clearfile'tmp.txt' 10 | t( t.readfile'tmp.txt', '' ) 11 | 12 | t.test_embedded_example() 13 | 14 | t.removefile( 'tmp.txt' ) 15 | 16 | t() 17 | 18 | -------------------------------------------------------------------------------- /test/cliparse.ex1.lua: -------------------------------------------------------------------------------- 1 | local cliparse = require 'cliparse' 2 | local t = require 'testhelper' 3 | 4 | t( cliparse(), {}, t.deepsame ) 5 | t( cliparse({}), {}, t.deepsame ) 6 | t( cliparse({'a'}), {['']={'a'}}, t.deepsame ) 7 | t( cliparse({'a','b'}), {['']={'a','b'}}, t.deepsame ) 8 | 9 | t( cliparse({'-a'}), {['a']={}}, t.deepsame ) 10 | t( cliparse({'-a','b'}), {['a']={},['']={'b'}}, t.deepsame ) 11 | t( cliparse({'-a','-b','c'}), {['a']={},['b']={},['']={'c'}}, t.deepsame ) 12 | 13 | t( cliparse({'-ab','c'}), {['a']={},['b']={},['']={'c'}}, t.deepsame ) 14 | 15 | t( cliparse({'--aa'}), {['aa']={}}, t.deepsame ) 16 | t( cliparse({'--aa','c'}), {['aa']={'c'}}, t.deepsame ) 17 | t( cliparse({'--aa','c','d'}), {['aa']={'c'},['']={'d'}}, t.deepsame ) 18 | 19 | t( cliparse({'--aa','--bb'}), {['aa']={},['bb']={}}, t.deepsame ) 20 | 21 | t( cliparse({'--aa','b','c','--aa','d'}), {['aa']={'b','d'},['']={'c'}}, t.deepsame ) 22 | 23 | t( cliparse({'--aa=b','c'}), {['aa']={'b'},['']={'c'}}, t.deepsame ) 24 | t( cliparse({'--aa:b','c'}), {['aa']={'b'},['']={'c'}}, t.deepsame ) 25 | t( cliparse({'--aa=b=c','d'}), {['aa']={'b=c'},['']={'d'}}, t.deepsame ) 26 | 27 | t( cliparse({'-a=b','c'}), {['a']={'b'},['']={'c'}}, t.deepsame ) 28 | t( cliparse({'-a:b','c'}), {['a']={'b'},['']={'c'}}, t.deepsame ) 29 | t( cliparse({'-aa=b','c'}), {['aa']={'b'},['']={'c'}}, t.deepsame ) 30 | 31 | t.test_embedded_example() 32 | 33 | t() 34 | 35 | -------------------------------------------------------------------------------- /test/clone.ex1.lua: -------------------------------------------------------------------------------- 1 | local clone = require 'clone' 2 | local t = require 'testhelper' 3 | 4 | local s = {} 5 | t( clone(s), s, t.diff ) 6 | t( clone(s), s, t.deepsame ) 7 | 8 | local s = {1} 9 | t( clone(s), s, t.diff ) 10 | t( clone(s), s, t.deepsame ) 11 | 12 | local s = { a = 'a' } 13 | local d = clone(s) 14 | t( s, d, t.deepsame ) 15 | 16 | local s = { a = {} } 17 | local d = clone(s) 18 | t( s, d, t.deepsame ) 19 | t( s.a, d.a, t.diff ) 20 | 21 | local s = { a = {1} } 22 | local d = clone(s) 23 | t( s, d, t.deepsame ) 24 | t( s.a, d.a, t.diff ) 25 | 26 | local r = {} 27 | local s = { a = r, b = r } 28 | local d = clone(s) 29 | t( s, d, t.deepsame ) 30 | t( s.a, d.a, t.diff ) 31 | t( s.b, d.b, t.diff ) 32 | t( d.a, d.b ) 33 | 34 | local r = {} 35 | local s = { r, [r] = 1 } 36 | local d = clone(s) 37 | t( s, d, t.deepsame ) 38 | t( s[1], d[1], t.diff ) 39 | local kc 40 | for k in pairs(d) do kc = k end 41 | t( d[1], kc ) 42 | 43 | local s = { } 44 | s[1] = s 45 | local d = clone(s) 46 | t( s, d, t.deepsame ) 47 | t( s[1], d[1], t.diff ) 48 | t( d, d[1] ) 49 | 50 | local k = {} 51 | local s = { [k] = 2 } 52 | local d = clone(s) 53 | t( s, d, t.deepsame ) 54 | local kc 55 | for k in pairs(d) do kc = k end 56 | t( k, kc, t.deepsame ) 57 | t( k, kc, t.diff ) 58 | 59 | local s = {} 60 | s.a = {} 61 | s.a.a = {} 62 | local d = clone( s ,2 ) 63 | t( s, d, t.deepsame ) 64 | t( s.a, d.a, t.diff ) 65 | t( s.a.a, d.a.a ) 66 | 67 | local s = {} 68 | local r,q = {},{} 69 | s[r] = 'a' 70 | r[q] = 'a' 71 | local d = clone( s ,2 ) 72 | t( s, d, t.deepsame ) 73 | local kc 74 | for k in pairs(d) do kc = k end 75 | local kcc 76 | for k in pairs(kc) do kcc = k end 77 | t( r, kc, t.diff ) 78 | t( q, kcc ) 79 | 80 | t.test_embedded_example() 81 | 82 | t() 83 | 84 | -------------------------------------------------------------------------------- /test/combinetab.ex1.lua: -------------------------------------------------------------------------------- 1 | local combinetab = require 'combinetab' 2 | local t = require 'testhelper' 3 | 4 | local r, n 5 | local function tres() 6 | r = {} 7 | n = 0 8 | end 9 | local function tcol(x) 10 | local t = {} 11 | for k,v in pairs(x) do t[k] = v end 12 | n = n + 1 13 | r[n] = t 14 | end 15 | 16 | tres() 17 | combinetab({k='a'},{k='b'}, tcol) 18 | t( #r, 2 ) 19 | t( r[1], {k='a'}, t.deepsame ) 20 | t( r[2], {k='b'}, t.deepsame ) 21 | 22 | tres() 23 | combinetab({k='a',x='a'},{k='b'}, tcol) 24 | t( #r, 4 ) 25 | t( r[1], {k='a',x='a'}, t.deepsame ) 26 | t( r[2], {k='b',x='a'}, t.deepsame ) 27 | t( r[3], {k='a'}, t.deepsame ) 28 | t( r[4], {k='b'}, t.deepsame ) 29 | 30 | tres() 31 | combinetab({k='a'},{k='b',x='b'}, tcol) 32 | t( #r, 4 ) 33 | t( r[1], {k='a'}, t.deepsame ) 34 | t( r[2], {k='b'}, t.deepsame ) 35 | t( r[3], {k='a',x='b'}, t.deepsame ) 36 | t( r[4], {k='b',x='b'}, t.deepsame ) 37 | 38 | tres() 39 | combinetab({k='a'},{k='b'},{k='c'}, tcol) 40 | t( #r, 3 ) 41 | t( r[1], {k='a'}, t.deepsame ) 42 | t( r[2], {k='b'}, t.deepsame ) 43 | t( r[3], {k='c'}, t.deepsame ) 44 | 45 | t.test_embedded_example() 46 | 47 | t() 48 | -------------------------------------------------------------------------------- /test/copyfile.ex1.lua: -------------------------------------------------------------------------------- 1 | local copyfile = require "copyfile" 2 | local t = require "testhelper" 3 | 4 | local inpath = "intmp.txt" 5 | local outpath = "outtmp.txt" 6 | local data = ( "01f" ):rep( 512 ) 7 | 8 | t.writefile( inpath, data ) 9 | t( copyfile( inpath, outpath ), true ) 10 | t( t.readfile( outpath ), data ) 11 | 12 | os.remove( inpath ) 13 | os.remove( outpath ) 14 | 15 | t.test_embedded_example() 16 | os.remove('s.txt') 17 | os.remove('d.txt') 18 | 19 | t() 20 | -------------------------------------------------------------------------------- /test/countiter.ex1.lua: -------------------------------------------------------------------------------- 1 | local countiter = require 'countiter' 2 | local t = require 'testhelper' 3 | 4 | t( countiter(), 0 ) 5 | t( countiter( pairs{}), 0 ) 6 | t( countiter( pairs{ 1, 2, c='2' }), 3 ) 7 | t( countiter( ipairs{ 1, 2, c='2' }), 2 ) 8 | 9 | t.test_embedded_example() 10 | 11 | t() 12 | -------------------------------------------------------------------------------- /test/csvish.ex1.lua: -------------------------------------------------------------------------------- 1 | 2 | local csvish = require 'csvish' 3 | local t = require 'testhelper' 4 | 5 | t( csvish'', {{''}}, t.deepsame ) 6 | t( csvish'aa', {{'aa'}}, t.deepsame ) 7 | t( csvish'aa;bb', {{'aa','bb'}}, t.deepsame ) 8 | 9 | t( csvish'aa;bb;;cc', {{'aa','bb','','cc'}}, t.deepsame ) 10 | t( csvish'aa;bb;', {{'aa','bb',''}}, t.deepsame ) 11 | t( csvish';', {{'',''}}, t.deepsame ) 12 | t( csvish';;', {{'','',''}}, t.deepsame ) 13 | 14 | t( csvish'aa\nbb', {{'aa'},{'bb'}}, t.deepsame ) 15 | t( csvish'aa\nbb\ncc', {{'aa'},{'bb'},{'cc'}}, t.deepsame ) 16 | t( csvish'aa\nbb\n', {{'aa'},{'bb'},{''}}, t.deepsame ) 17 | t( csvish'aa\n', {{'aa'},{''}}, t.deepsame ) 18 | t( csvish'aa\n\nbb', {{'aa'},{''},{'bb'}}, t.deepsame ) 19 | t( csvish'\n', {{''},{''}}, t.deepsame ) 20 | 21 | t( csvish'aa\n;\nbb', {{'aa'},{'',''},{'bb'}}, t.deepsame ) 22 | 23 | t( csvish'"aa";bb', {{'aa','bb'}}, t.deepsame ) 24 | t( csvish'"aa;bb"', {{'aa;bb'}}, t.deepsame ) 25 | t( csvish'"aa;bb";cc', {{'aa;bb','cc'}}, t.deepsame ) 26 | t( csvish'"aa;bb";cc;"dd;ee"', {{'aa;bb','cc','dd;ee'}}, t.deepsame ) 27 | 28 | t( csvish'"aa"bb', {{'aabb'}}, t.deepsame ) 29 | t( csvish'aa"bb"', {{'aabb'}}, t.deepsame ) 30 | t( csvish'aa"bb"cc', {{'aabbcc'}}, t.deepsame ) 31 | t( csvish'aa"bb"cc;dd', {{'aabbcc','dd'}}, t.deepsame ) 32 | t( csvish'zz;aa"bb"cc', {{'zz','aabbcc'}}, t.deepsame ) 33 | 34 | t( csvish'aa""bb', {{'aa"bb'}}, t.deepsame ) 35 | t( csvish'aa""', {{'aa"'}}, t.deepsame ) 36 | t( csvish'""aa', {{'"aa'}}, t.deepsame ) 37 | t( csvish'aa;bb""', {{'aa','bb"'}}, t.deepsame ) 38 | t( csvish'""aa;bb', {{'"aa','bb'}}, t.deepsame ) 39 | 40 | t( csvish'aa"\n"bb', {{'aa\nbb'}}, t.deepsame ) 41 | t( csvish'aa"\r"bb', {{'aa\rbb'}}, t.deepsame ) 42 | t( csvish'aa"\n\r"bb', {{'aa\n\rbb'}}, t.deepsame ) 43 | t( csvish'aa";"bb', {{'aa;bb'}}, t.deepsame ) 44 | 45 | t.test_embedded_example() 46 | 47 | t() 48 | 49 | -------------------------------------------------------------------------------- /test/csvishout.ex1.lua: -------------------------------------------------------------------------------- 1 | local csvishout = require 'csvishout' 2 | local t = require 'testhelper' 3 | 4 | t( csvishout{}, '' ) 5 | t( csvishout{{}}, '\n' ) 6 | t( csvishout{{},{}}, '\n\n' ) 7 | 8 | t( csvishout{{1}}, '1\n' ) 9 | t( csvishout{{'a'}}, 'a\n' ) 10 | t( csvishout{{1,2}}, '1;2\n' ) 11 | t( csvishout{{'',2}}, ';2\n' ) 12 | 13 | t( csvishout{{1,2,3}}, '1;2;3\n' ) 14 | t( csvishout{{1,2,3},{1,2,3}}, '1;2;3\n1;2;3\n' ) 15 | t( csvishout{{1,2,3},{1,2}}, '1;2;3\n1;2\n' ) 16 | t( csvishout{{1,2,3},{1,2}}, '1;2;3\n1;2\n' ) 17 | 18 | t( csvishout{{1},{},{2}}, '1\n\n2\n' ) 19 | 20 | t( csvishout{{';'}}, '";"\n' ) 21 | t( csvishout{{'\n'}}, '"\n"\n' ) 22 | t( csvishout{{'a"b'}}, '"a""b"\n' ) 23 | 24 | t( csvishout{{';','ok'}}, '";";ok\n' ) 25 | t( csvishout{{'\n','ok'}}, '"\n";ok\n' ) 26 | t( csvishout{{'"','ok'}}, '"""";ok\n' ) 27 | t( csvishout{{'ok"ok','ok'}}, '"ok""ok";ok\n' ) 28 | 29 | t.test_embedded_example() 30 | 31 | t() 32 | 33 | -------------------------------------------------------------------------------- /test/datestd.ex1.lua: -------------------------------------------------------------------------------- 1 | 2 | local datestd = require 'datestd' 3 | local t = require 'testhelper' 4 | 5 | t( datestd{}, '' ) 6 | t( datestd{ year=2018, month=1, day=21, hour=14, min=32, sec=10.1, zone=0}, '2018-01-21 14:32:10.1Z' ) 7 | 8 | t( datestd{ year=2018, month=1, day=21, hour=14, min=32, sec=10.1, zone=1}, '2018-01-21 14:32:10.1+01:00' ) 9 | t( datestd{ year=2018, month=1, day=21, hour=14, min=32, sec=10.1, zone=-1}, '2018-01-21 14:32:10.1-01:00' ) 10 | 11 | t( datestd{ year=2018, month=1, day=21, hour=14, min=32, sec=10.1}, '2018-01-21 14:32:10.1' ) 12 | t( datestd{ year=2018, month=1, day=21}, '2018-01-21' ) 13 | t( datestd{ hour=14, min=32, sec=10.1}, '14:32:10.1' ) 14 | 15 | t( datestd{ year=2018, month=1, day=21, hour=14, min=32, sec=0}, '2018-01-21 14:32:00' ) 16 | 17 | -- 18 | 19 | t( datestd'2018-01-21 14:32:10.100Z', { year=2018, month=1, day=21, hour=14, min=32, sec=10.1, zone=0}, t.deepsame ) 20 | 21 | t( datestd'2018-01-21 14:32:10.100+01:00', { year=2018, month=1, day=21, hour=14, min=32, sec=10.1, zone=1}, t.deepsame ) 22 | t( datestd'2018-01-21 14:32:10.100-01:00', { year=2018, month=1, day=21, hour=14, min=32, sec=10.1, zone=-1}, t.deepsame ) 23 | 24 | t( datestd'2018-01-21 14:32:10.100', { year=2018, month=1, day=21, hour=14, min=32, sec=10.1}, t.deepsame ) 25 | t( datestd'14:32:10.100', { hour=14, min=32, sec=10.1}, t.deepsame ) 26 | t( datestd'2018-01-21', { year=2018, month=1, day=21}, t.deepsame ) 27 | 28 | -- TODO : test errors ! 29 | 30 | t.test_embedded_example() 31 | 32 | t() 33 | 34 | -------------------------------------------------------------------------------- /test/deepsame.ex1.lua: -------------------------------------------------------------------------------- 1 | local deepsame = require 'deepsame' 2 | local t = require 'testhelper' 3 | 4 | t( deepsame({}, {}), true ) 5 | t( deepsame({1}, {1}), true ) 6 | t( deepsame({1}, {2}), false ) 7 | 8 | t( deepsame({1,2}, {1}), false ) 9 | t( deepsame({1}, {1,2}), false ) 10 | 11 | t( deepsame({[{1}]=1}, {[{1}]=1}), true ) 12 | t( deepsame({[{1}]=1}, {[{2}]=1}), false ) 13 | t( deepsame({[{1}]=1}, {[{1}]=2}), false ) 14 | 15 | local a,b = {},{} 16 | t( deepsame({[a]='a',[b]='a'}, {[a]='a'}), false ) 17 | t( deepsame({[a]='a'}, {[a]='a',[b]='a'}), false ) 18 | 19 | t( deepsame({{}}, {{}}), true ) 20 | t( deepsame({{1}}, {{1}}), true ) 21 | t( deepsame({{1}}, {{2}}), false ) 22 | 23 | t( deepsame({{1},{2}}, {{1}}), false ) 24 | t( deepsame({{1}}, {{1},{2}}), false ) 25 | 26 | t( deepsame({[{{1}}]={1}}, {[{{1}}]={1}}), true ) 27 | t( deepsame({[{{1}}]={1}}, {[{{2}}]={1}}), false ) 28 | t( deepsame({[{{1}}]={1}}, {[{{1}}]={2}}), false ) 29 | 30 | local a = {y={}} 31 | local x = {} 32 | x.y = x 33 | local w = {} 34 | w.y = w 35 | local z = {y={}} 36 | z.y.y = z 37 | 38 | t( deepsame(a, x), false ) 39 | t( deepsame(x, a), false ) 40 | t( deepsame(x, w), true ) 41 | t( deepsame(w, x), true ) 42 | t( deepsame(x, z), true ) 43 | t( deepsame(z, x), true ) 44 | 45 | t( deepsame( { false }, { false } ), true ) 46 | 47 | -- Table with multiple cycle 48 | local atab = {} 49 | atab.kv = {} 50 | atab[atab.kv] = atab.kv 51 | atab[atab.kv][atab.kv] = atab[atab.kv] 52 | local btab = {} 53 | btab.kv = {} 54 | btab[btab.kv] = btab.kv 55 | btab[btab.kv][btab.kv] = btab[btab.kv] 56 | t( t.deepsame( atab, btab ), true ) 57 | 58 | t.test_embedded_example() 59 | 60 | t() 61 | -------------------------------------------------------------------------------- /test/differencetab.ex1.lua: -------------------------------------------------------------------------------- 1 | local differencetab = require 'differencetab' 2 | local t = require 'testhelper' 3 | 4 | t( differencetab(), {}, t.deepsame ) 5 | t( differencetab({}), {}, t.deepsame ) 6 | t( differencetab({},{}), {}, t.deepsame ) 7 | 8 | t( differencetab({a='a'}), {a='a'}, t.deepsame ) 9 | t( differencetab({},{a='a'}), {}, t.deepsame ) 10 | 11 | t( differencetab({a='a'},{b='b'}), {a='a'}, t.deepsame ) 12 | t( differencetab({a='a'},{a='b'}), {}, t.deepsame ) 13 | 14 | t( differencetab({a='a',b='b',c='c'},{a='A',d='d'}), {b='b',c='c'}, t.deepsame ) 15 | 16 | t.test_embedded_example() 17 | 18 | t() 19 | -------------------------------------------------------------------------------- /test/escapeshellarg.ex1.lua: -------------------------------------------------------------------------------- 1 | local escapeshellarg = require "escapeshellarg" 2 | local t = require "testhelper" 3 | 4 | local lua, argdumputil, outpath = t.argdumputil() 5 | local p = lua..' '..argdumputil..' ' 6 | local d 7 | 8 | d = [[Hello's world]] 9 | os.execute( p..escapeshellarg( d )) 10 | t( t.readfile(outpath), d ) 11 | 12 | d = [[use a " to mark]] 13 | os.execute( p..escapeshellarg( d )) 14 | t( t.readfile(outpath), d ) 15 | 16 | d = [[should escape \]] 17 | os.execute( p..escapeshellarg( d )) 18 | t( t.readfile(outpath), d ) 19 | 20 | d = [[special $PATH]] 21 | os.execute( p..escapeshellarg( d )) 22 | t( t.readfile(outpath), d ) 23 | 24 | d = [[special %PATH%]] 25 | os.execute( p..escapeshellarg( d )) 26 | t( t.readfile(outpath), d ) 27 | 28 | d = [[redirect>o.txt]] 29 | os.execute( p..escapeshellarg( d )) 30 | t( t.readfile(outpath), d ) 31 | 32 | d = [[redirect]] 45 | os.execute( p..escapeshellarg( d )) 46 | t( t.readfile(outpath), d ) 47 | 48 | t( escapeshellarg'-i', '-i' ) 49 | 50 | t.test_embedded_example() 51 | os.remove('tmp.tmp') 52 | 53 | t() 54 | -------------------------------------------------------------------------------- /test/factory.ex1.lua: -------------------------------------------------------------------------------- 1 | local factory = require 'factory' 2 | local t = require 'testhelper' 3 | 4 | local makeA, isA = factory(function(ins) 5 | if not ins.built then ins.built = '' end 6 | ins.built = ins.built .. 'A' 7 | end) 8 | 9 | local makeB, isB = factory(function(ins) 10 | if not ins.built then ins.built = '' end 11 | ins.built = ins.built .. 'B' 12 | end) 13 | 14 | local makeC, isC = factory(function(ins) 15 | makeA(ins) 16 | makeB(ins) 17 | if not ins.built then ins.built = '' end 18 | ins.built = ins.built .. 'C' 19 | end) 20 | 21 | local a = makeA() 22 | local b = makeB() 23 | local c = makeC { built = 'X' } 24 | 25 | t( a.built, 'A' ) 26 | t( b.built, 'B' ) 27 | t( c.built, 'XABC' ) 28 | 29 | t( isA(a), true ) 30 | t( isB(a), false ) 31 | t( isC(a), false ) 32 | 33 | t( isA(b), false ) 34 | t( isB(b), true ) 35 | t( isC(b), false ) 36 | 37 | t( isA(c), true ) 38 | t( isB(c), true ) 39 | t( isC(c), true ) 40 | 41 | makeA, isA = factory(function(ins) 42 | local private1, private2 = {'p1'}, {'p2'} 43 | function ins:getprivate() 44 | return private1, private2 45 | end 46 | end) 47 | 48 | local a = makeA() 49 | local d = makeA() 50 | 51 | local B, C = a:getprivate() 52 | local E, F = d:getprivate() 53 | 54 | t( true, B ~= E ) 55 | t( true, C ~= F ) 56 | t( 'p1', B[1] ) 57 | t( 'p1', E[1] ) 58 | t( 'p2', C[1] ) 59 | t( 'p2', F[1] ) 60 | 61 | -- Iteration 62 | 63 | makeA, isA = factory(function()end) 64 | local a, b 65 | a = makeA() 66 | b = makeA() 67 | 68 | local C = {} 69 | for i in isA('all') do 70 | C[1+#C] = i 71 | end 72 | 73 | t( a, C[1] ) 74 | t( b, C[2] ) 75 | 76 | -- Empty constructor 77 | 78 | makeA, isA = factory() 79 | local a = makeA() 80 | 81 | t( a ~= nil, true ) 82 | t( isA( a ), true ) 83 | 84 | -- Method protection example 85 | makeA, isA = factory(function(ins) 86 | ins.t = 'a' 87 | return setmetatable({}, { __index = ins }) 88 | end) 89 | a = {} 90 | b = makeA(a) 91 | 92 | t( a.t, 'a' ) 93 | t( b.t, 'a' ) 94 | a.t = 'c' 95 | t( a.t, 'c' ) 96 | t( b.t, 'c' ) 97 | b.t = 'b' 98 | t( a.t, 'c' ) 99 | t( b.t, 'b' ) 100 | 101 | t( isA(a), true ) -- TODO : change this ? 102 | t( isA(b), true ) 103 | 104 | t.test_embedded_example() 105 | 106 | t() 107 | 108 | -------------------------------------------------------------------------------- /test/filenamesplit.ex1.lua: -------------------------------------------------------------------------------- 1 | local filenamesplit = require 'filenamesplit' 2 | local t = require 'testhelper' 3 | 4 | t( {filenamesplit()}, {'','',''}, t.deepsame ) 5 | t( {filenamesplit''}, {'','',''}, t.deepsame ) 6 | 7 | t( {filenamesplit'path/name.ext'}, {'path/','name','.ext'}, t.deepsame ) 8 | 9 | t( {filenamesplit'/path/path/name.ext'}, {'/path/path/','name','.ext'}, t.deepsame ) 10 | t( {filenamesplit'path/name.name.ext'}, {'path/','name.name','.ext'}, t.deepsame ) 11 | 12 | t( {filenamesplit'name.ext'}, {'','name','.ext'}, t.deepsame ) 13 | t( {filenamesplit'path/.ext'}, {'path/','','.ext'}, t.deepsame ) 14 | t( {filenamesplit'path/name'}, {'path/','name',''}, t.deepsame ) 15 | 16 | t( {filenamesplit'path//name.ext'}, {'path//','name','.ext'}, t.deepsame ) 17 | t( {filenamesplit'path/name..ext'}, {'path/','name.','.ext'}, t.deepsame ) 18 | 19 | t.test_embedded_example() 20 | 21 | t() 22 | -------------------------------------------------------------------------------- /test/flatarray.ex1.lua: -------------------------------------------------------------------------------- 1 | local flatarray = require 'flatarray' 2 | local t = require 'testhelper' 3 | 4 | t( flatarray{}, {}, t.deepsame ) 5 | t( flatarray{1}, {1}, t.deepsame ) 6 | t( flatarray{1,2,3,4}, {1,2,3,4}, t.deepsame ) 7 | 8 | t( flatarray{1,{2,3},4}, {1,2,3,4}, t.deepsame ) 9 | 10 | t( flatarray{1,{{2,3}},4}, {1,2,3,4}, t.deepsame ) 11 | 12 | t( flatarray({1,{{2,3}},4}, 1), {1,{2,3},4}, t.deepsame ) 13 | 14 | t( flatarray{1,{2,{3}},{{4}}}, {1,2,3,4}, t.deepsame ) 15 | 16 | t.test_embedded_example() 17 | 18 | t() 19 | -------------------------------------------------------------------------------- /test/get.ex1.lua: -------------------------------------------------------------------------------- 1 | 2 | local get = require 'get' 3 | local t = require 'testhelper' 4 | 5 | t( nil, get({},'a')) 6 | t( 'b', get({a='b'},'a')) 7 | 8 | t( 'd', get({a={b={c='d'}}},'a','b','c')) 9 | t( nil, get({a={b={c='d'}}},'a','x','c'), nil ) 10 | 11 | t( nil, get({a={b={c='d'}}},'a',nil,'c'), nil ) 12 | 13 | t( nil, get(nil,'a','b','c'), nil ) 14 | t( nil, get({a={b=0}},'a','b','c'), nil ) 15 | 16 | t.test_embedded_example() 17 | 18 | t() 19 | -------------------------------------------------------------------------------- /test/hexdecode.ex1.lua: -------------------------------------------------------------------------------- 1 | local hexdecode = require 'hexdecode' 2 | local t = require 'testhelper' 3 | 4 | t( hexdecode '00', '\x00' ) 5 | t( hexdecode '0000', '\x00\x00' ) 6 | 7 | t( hexdecode 'FF', '\xFF' ) 8 | t( hexdecode 'FFFF', '\xFF\xFF' ) 9 | 10 | t( hexdecode '10BA', '\x10\xBA' ) 11 | 12 | t( hexdecode 'F', '\x0F' ) 13 | 14 | t.test_embedded_example() 15 | 16 | t() 17 | 18 | -------------------------------------------------------------------------------- /test/hexencode.ex1.lua: -------------------------------------------------------------------------------- 1 | local hexencode = require 'hexencode' 2 | local t = require 'testhelper' 3 | 4 | t( hexencode '\x00', '00' ) 5 | t( hexencode '\x00\x00', '0000' ) 6 | 7 | t( hexencode '\xFF', 'FF' ) 8 | t( hexencode '\xFF\xFF', 'FFFF' ) 9 | 10 | t( hexencode '\x10\xBA', '10BA' ) 11 | 12 | t.test_embedded_example() 13 | 14 | t() 15 | 16 | -------------------------------------------------------------------------------- /test/intern.ex1.lua: -------------------------------------------------------------------------------- 1 | local intern = require 'intern' 2 | local t = require 'testhelper' 3 | 4 | t( type( intern() ), 'function' ) 5 | 6 | local int = intern() 7 | 8 | t( type( int( 1 )), 'table' ) 9 | t( int( 1 ), int( 2 ), t.diff ) 10 | 11 | t( type( int( 1, nil, 0/0, 3 )), 'table' ) 12 | t( int( 1, nil, 0/0, 3 ), int( 1, nil, 0/0, 3 )) 13 | 14 | t( int( 1, nil, 0/0, 3 ), int( 1, nil, 0/0 ), t.diff ) 15 | t( int( 1, nil, 0/0, 3 ), int( 1, nil ), t.diff ) 16 | t( int( 1, nil, 0/0, 3 ), int( 1 ), t.diff ) 17 | 18 | t( int( 1, nil, 0/0, 3 ), int( 1, nil, 0/0, 2 ), t.diff) 19 | t( int( 1, nil, 0/0, 3 ), int( 1, nil, 0, 3 ), t.diff) 20 | t( int( 1, nil, 0/0, 3 ), int( 1, '', 0/0, 3 ), t.diff) 21 | t( int( 1, nil, 0/0, 3 ), int( 4, nil, 0/0, 3 ), t.diff) 22 | 23 | -- Multiple store 24 | local alt = intern() 25 | t( type( alt( 1, nil, 0/0, 3 )), 'table' ) 26 | t( alt( 1, nil, 0/0, 3 ), alt( 1, nil, 0/0, 3 )) 27 | t( alt( 1, nil, 0/0, 3 ), int( 1, nil, 0/0, 3 ), t.diff ) 28 | 29 | -- Garbage collection test 30 | 31 | local gccount = 0 32 | local x = int( true, false ) 33 | x = setmetatable( x, {__gc=function(t) gccount = gccount + 1 end} ) 34 | 35 | -- No collection if some reference is still around 36 | collectgarbage('collect') 37 | t( gccount, 0 ) 38 | 39 | -- Automatic collection 40 | x = nil 41 | collectgarbage('collect') 42 | t( gccount, 1 ) 43 | 44 | t.test_embedded_example() 45 | 46 | t() 47 | 48 | -------------------------------------------------------------------------------- /test/intersecationtab.ex1.lua: -------------------------------------------------------------------------------- 1 | local intersecationtab = require 'intersecationtab' 2 | local t = require 'testhelper' 3 | 4 | t( intersecationtab(), {}, t.deepsame ) 5 | t( intersecationtab({}), {}, t.deepsame ) 6 | t( intersecationtab({},{}), {}, t.deepsame ) 7 | 8 | t( intersecationtab({a='a'}), {}, t.deepsame ) 9 | t( intersecationtab({},{a='a'}), {}, t.deepsame ) 10 | 11 | t( intersecationtab({a='a'},{b='b'}), {}, t.deepsame ) 12 | t( intersecationtab({a='a'},{a='b'}), {a='a'}, t.deepsame ) 13 | 14 | t( intersecationtab({a='a'},{a='b'},function(a,b) return a..b end), {a='ab'}, t.deepsame ) 15 | 16 | t( intersecationtab({a='a',b='b',c='c'},{a='A',d='d'}), {a='a'}, t.deepsame ) 17 | 18 | t.test_embedded_example() 19 | 20 | t() 21 | -------------------------------------------------------------------------------- /test/iscallable.ex1.lua: -------------------------------------------------------------------------------- 1 | local iscallable = require "iscallable" 2 | local t = require "testhelper" 3 | 4 | t( iscallable( 0 ), false ) 5 | t( iscallable( "" ), false ) 6 | t( iscallable( true ), false ) 7 | t( iscallable( {} ), false ) 8 | t( iscallable( function() end ), true ) 9 | 10 | local calltab_a = {} 11 | setmetatable( calltab_a, { __call = function() end } ) 12 | 13 | t( iscallable( calltab_a ), true ) 14 | 15 | local calltab_b = {} 16 | setmetatable( calltab_b, { __call = calltab_a } ) 17 | 18 | t( iscallable( calltab_b ), true ) 19 | 20 | local rectab_a = {} 21 | local rectab_b = {} 22 | setmetatable( rectab_a, { __call = rectab_b } ) 23 | setmetatable( rectab_b, { __call = rectab_a } ) 24 | 25 | t( iscallable( rectab_b ), false ) 26 | 27 | t.test_embedded_example() 28 | 29 | t() 30 | 31 | -------------------------------------------------------------------------------- /test/isreadable.ex1.lua: -------------------------------------------------------------------------------- 1 | local isreadable = require "isreadable" 2 | local t = require "testhelper" 3 | 4 | io.open( "isreadable.txt", "wb" ):close() 5 | t( isreadable( "isreadable.txt" ), true ) 6 | 7 | os.remove( "isreadable.txt" ) 8 | t( isreadable( "isreadable.txt" ), false ) 9 | 10 | t.test_embedded_example() 11 | 12 | t() 13 | -------------------------------------------------------------------------------- /test/jsonish.ex1.lua: -------------------------------------------------------------------------------- 1 | local jsonish = require 'jsonish' 2 | local t = require 'testhelper' 3 | 4 | t( jsonish '', nil ) 5 | t( jsonish '1', 1 ) 6 | t( jsonish 'true', true ) 7 | t( jsonish '"hi"', "hi" ) 8 | t( jsonish '""', "" ) 9 | 10 | t( jsonish [["\u0021"]], [[!]] ) 11 | t( jsonish [["h\u0021i"]], [[h!i]] ) 12 | t( jsonish [["\\u0021"]], [[\u0021]] ) 13 | t( jsonish [["h\\u0021i"]], [[h\u0021i]] ) 14 | t( jsonish [["\\\u0021"]], [[\!]] ) 15 | 16 | t( jsonish '{}', {}, t.deepsame ) 17 | t( jsonish '{"hello":"world"}', {hello="world"}, t.deepsame ) 18 | t( jsonish '[1,2,3]', {1,2,3}, t.deepsame ) 19 | 20 | t( jsonish '{"hello":{"wor":"ld"}}', {hello={wor="ld"}}, t.deepsame ) 21 | t( jsonish '[1,2,[3,4]]', {1,2,{3,4}}, t.deepsame ) 22 | 23 | t( jsonish '["a","b]","c"]', {"a","b]","c"}, t.deepsame ) 24 | t( jsonish '["a","[b","c"]', {"a","[b","c"}, t.deepsame ) 25 | t( jsonish '["a","[b","c]"]', {"a","[b","c]"}, t.deepsame ) 26 | t( jsonish '["a",["b","c"]]', {"a",{"b","c"}}, t.deepsame ) 27 | 28 | t( jsonish[[{"a b": true}]], {["a b"]=true}, t.deepsame) 29 | t( jsonish '{"hello" :"world"}', {hello="world"}, t.deepsame ) 30 | 31 | t( jsonish[[{"\"b\"":true}]], {['"b"']=true}, t.deepsame) 32 | t( jsonish[[ ["a","b\"]","c"] ]], {"a","b\"]","c"}, t.deepsame ) 33 | 34 | t( jsonish[[{"a":"","b":[],"c":0}]], {a="",b={},c=0}, t.deepsame ) 35 | t( jsonish[[{"a":"\"","b":[],"c":0}]], {a='"',b={},c=0}, t.deepsame ) 36 | 37 | t.test_embedded_example() 38 | 39 | t() 40 | 41 | -------------------------------------------------------------------------------- /test/jsonishout.ex1.lua: -------------------------------------------------------------------------------- 1 | local jsonishout = require 'jsonishout' 2 | local t = require 'testhelper' 3 | 4 | t( jsonishout(1), '1' ) 5 | t( jsonishout'', '""' ) 6 | t( jsonishout'hi', '"hi"' ) 7 | 8 | t( jsonishout{}, "[]" ) 9 | t( jsonishout{1}, '[1]' ) 10 | t( jsonishout{2,1}, '[2,1]' ) 11 | t( jsonishout{2,1,{}}, '[2,1,[]]' ) 12 | 13 | t( jsonishout{a=1}, '{"a":1}' ) 14 | t( jsonishout{a=1,b=2}, "^{[^,]*,[^,]*}$", t.patsame ) 15 | t( jsonishout{a=1,b=2}, '"a":1', t.patsame ) 16 | t( jsonishout{a=1,b=2}, '"b":2', t.patsame ) 17 | 18 | local empty = setmetatable({},{}) 19 | t( jsonishout(empty), '{}' ) 20 | t( jsonishout{a=empty}, '{"a":{}}' ) 21 | 22 | t( jsonishout{1,2,a=1}, '[1,2]' ) 23 | 24 | t( jsonishout{{a=1},{1}}, '[{"a":1},[1]]' ) 25 | 26 | t( jsonishout'\"', '"\\x22"' ) 27 | t( jsonishout'\n', '"\\x0A"' ) 28 | 29 | t.test_embedded_example() 30 | 31 | t() 32 | 33 | -------------------------------------------------------------------------------- /test/keysort.ex1.lua: -------------------------------------------------------------------------------- 1 | local keysort = require 'keysort' 2 | local t = require 'testhelper' 3 | 4 | t( keysort{}, {}, t.deepsame ) 5 | t( keysort{a=9}, {'a'}, t.deepsame ) 6 | t( keysort{[1]=0}, {1}, t.deepsame ) 7 | 8 | t( keysort{a=9,b=9}, {'a','b'}, t.deepsame ) 9 | t( keysort{b=9,a=9,}, {'a','b'}, t.deepsame ) 10 | 11 | t( keysort{[1]=9,[2]=9}, {1,2}, t.deepsame ) 12 | t( keysort{[2]=9,[1]=9}, {1,2}, t.deepsame ) 13 | t( keysort{[3]=9,[20]=9}, {20,3}, t.deepsame ) 14 | 15 | t( keysort{[1]=9,["1"]=9,}, {'1',1}, t.deepsame ) 16 | 17 | t( keysort{[1]=9,["1"]=9,}, {'1',1}, t.deepsame ) 18 | 19 | t.test_embedded_example() 20 | 21 | t() 22 | -------------------------------------------------------------------------------- /test/lambda.ex1.lua: -------------------------------------------------------------------------------- 1 | local lambda = require "lambda" 2 | local t = require "testhelper" 3 | 4 | -- lambda-like syntax 5 | t( 1, lambda"x|x+1"( 0 ) ) 6 | 7 | -- multiple arguments 8 | t( 4, lambda"x,y|x+y"( 1, 3 ) ) 9 | 10 | -- additional statement, only the last expression is returned 11 | t( 3, lambda"x| x=x+1; x+1"( 1 ) ) 12 | 13 | -- default args are a,b,c,d,e,f,...( vararg ) 14 | t( 1, lambda"a+1"( 0 ) ) 15 | 16 | -- Memo 17 | local m = lambda'a+1' 18 | t( m, lambda'a+1' ) 19 | 20 | t.test_embedded_example() 21 | 22 | t() 23 | -------------------------------------------------------------------------------- /test/lineposition.ex1.lua: -------------------------------------------------------------------------------- 1 | local lineposition = require "lineposition" 2 | local t = require "testhelper" 3 | 4 | -- ex: column/line to byte 5 | 6 | t( lineposition("a a", 1, 1), 1 ) 7 | t( lineposition("a a\na", 1, 1), 1 ) 8 | t( lineposition("a a\na", 2, 1), 2 ) 9 | t( lineposition("a a\na", 1, 2), 5 ) 10 | t( lineposition("a dfklj\na;sdf kj\n$LA@ f\n1 3x45 \nas d f\nas dfkj", 3, 4 ), 27 ) 11 | 12 | -- ex: byte to column/line 13 | 14 | local x,y 15 | 16 | x, y = lineposition("a a", 1) 17 | t( y, 1 ) 18 | t( x, 1 ) 19 | 20 | x, y = lineposition("a a", 3) 21 | t( y, 1 ) 22 | t( x, 3 ) 23 | 24 | x, y = lineposition("a\na", 3) 25 | t( y, 2 ) 26 | t( x, 1 ) 27 | 28 | x, y = lineposition("a dfklj\na;sdf kj\n$LA@ f\n1 3x45 \nas d f\nas dfkj", 28) 29 | t( y, 4 ) 30 | t( x, 4 ) 31 | 32 | t.test_embedded_example() 33 | 34 | t() 35 | 36 | -------------------------------------------------------------------------------- /test/localbind.ex1.lua: -------------------------------------------------------------------------------- 1 | local localbind = require 'localbind' 2 | local t = require 'testhelper' 3 | 4 | -- Accessing local variable 5 | ;(function() 6 | local L = {} 7 | local lb = localbind( 1 ) 8 | t( lb.L, L ) 9 | lb.L = 1 10 | t( lb.L, 1 ) 11 | t( L, 1 ) 12 | end)() 13 | 14 | -- Accessing upvalue 15 | local U = 1 16 | ;(function() 17 | local lb = localbind( 1 ) 18 | t( lb.U, 1 ) 19 | lb.U = 2 20 | t( lb.U, 2 ) 21 | t( U, 2 ) 22 | end)() 23 | 24 | -- Accessing deeper stack position 25 | local U = 'u' 26 | ;(function() 27 | local L = U -- just to let U be linked in the compiled function 28 | L = 'l' 29 | t( localbind(1).L, 'l' ) 30 | t( localbind(1).U, 'u' ) 31 | ;(function() 32 | t( localbind(2).L, 'l' ) 33 | t( localbind(2).U, 'u' ) 34 | ;(function() 35 | t( localbind(3).L, 'l' ) 36 | t( localbind(3).U, 'u' ) 37 | localbind(3).L = 'L' 38 | localbind(3).U = 'U' 39 | t( localbind(3).U, 'U' ) 40 | t( localbind(3).L, 'L' ) 41 | end)(); 42 | t( localbind(2).U, 'U' ) 43 | t( localbind(2).L, 'L' ) 44 | end)(); 45 | t( localbind(1).U, 'U' ) 46 | t( localbind(1).L, 'L' ) 47 | t( L, 'L' ) 48 | end)(); 49 | 50 | -- Accessing global when no global is compiled-in 51 | G = 1 52 | ;(function() 53 | local lb = localbind(1) 54 | t( lb.G, nil ) 55 | lb.G = 2 56 | t( lb.G, 2 ) 57 | t( lb._ENV, nil ) 58 | end)() 59 | t( G, 1 ) 60 | 61 | -- Accessing global (compiled-in) 62 | G = 1 63 | local e = _ENV 64 | ;(function() 65 | local L = print -- print referred to let the global be linked in the compiled function 66 | local lb = localbind(1) 67 | t( lb.G, 1 ) 68 | lb.G = 2 69 | t( lb.G, 2 ) 70 | t( lb._ENV, e ) 71 | end)() 72 | t( G, 2 ) 73 | 74 | -- Check variable type 75 | G = 1 76 | local U = 1 77 | ;(function() 78 | -- Note: global is linked due to t and localbind reference 79 | local L 80 | L = U -- U referred to let it be linked in the compiled function 81 | local lb = localbind(1) 82 | t( lb('L'), 'local' ) 83 | t( lb('U'), 'upvalue' ) 84 | t( lb('G'), 'nil' ) 85 | end)() 86 | 87 | -- Check global variable type 88 | G = 1 89 | local U = 1 90 | ;(function() 91 | -- Note: global is linked due to t and localbind reference 92 | local L 93 | L = U -- U referred to let it be linked in the compiled function 94 | L = print -- print referred to let the global be linked in the compiled function 95 | local lb = localbind(1) 96 | t( lb('L'), 'local' ) 97 | t( lb('U'), 'upvalue' ) 98 | t( lb('G'), 'global' ) 99 | end)() 100 | 101 | -- Accessing different global (compiled-in) 102 | local chunkglobal = _ENV 103 | local testglobal = {G=1} 104 | G = 3 105 | _ENV = testglobal 106 | ;(function() 107 | -- Note: global is linked due to t and localbind reference 108 | local lb = localbind(1) 109 | t( lb.G, 1 ) 110 | t( G, 1 ) 111 | lb.G = 2 112 | t( lb.G, 2 ) 113 | t( G, 2 ) 114 | t( lb._ENV, _ENV ) 115 | end)(localbind, t) 116 | _ENV = chunkglobal 117 | t( G, 3 ) 118 | t( testglobal.G, 2 ) 119 | 120 | -- Accessing hidden upvalue 121 | local h = {} 122 | local auxFunc, auxTest 123 | do 124 | local H = h 125 | auxFunc = function( auxFunc ) 126 | local L = H -- H referred just to be compiled into the funcition 127 | auxFunc() 128 | return 1 -- just to avoid tail recursion 129 | end 130 | auxTest = function() return H end 131 | end 132 | auxFunc(function() 133 | local lb = localbind( 2 ) 134 | t( lb.H, h ) 135 | lb.H = 1 136 | t( lb.H, 1 ) 137 | t( lb('H'), 'upvalue' ) 138 | end) 139 | t( auxTest(), 1 ) 140 | 141 | -- Binding iterator 142 | local chunkglobal = _ENV 143 | local testglobal = {type=type, pairs=pairs} 144 | local iter = {} 145 | local count = 0 146 | _ENV = testglobal 147 | ;(function() 148 | local lb = localbind(1) 149 | for k, v in pairs(lb) do 150 | count = count + 1 151 | iter[k] = lb(k)..' '..type(v) 152 | end 153 | end)(localbind, t) 154 | _ENV = chunkglobal 155 | t( iter._ENV, 'upvalue table' ) 156 | t( iter.count, 'upvalue number' ) 157 | t( iter.lb, 'local table' ) 158 | t( iter.iter, 'upvalue table' ) 159 | t( iter.localbind, 'upvalue function' ) 160 | t( iter.pairs, 'global function' ) 161 | t( iter.type, 'global function' ) 162 | t( count, 7 ) 163 | 164 | t.test_embedded_example() 165 | 166 | t() 167 | 168 | -------------------------------------------------------------------------------- /test/locktable.ex1.lua: -------------------------------------------------------------------------------- 1 | local locktable = require 'locktable' 2 | local t = require 'testhelper' 3 | 4 | local err = t.filterr 5 | 6 | local l = { a = 1 } 7 | l = locktable( l, 'readnil' ) 8 | t( l.a, 1 ) 9 | t( err(function() return l.b end), nil, t.diff ) 10 | t( err(function() l.b = 2 end), nil ) 11 | t( err(function() l.a = 2 end), nil ) 12 | 13 | local l = { a = 1 } 14 | l = locktable( l, 'writenil' ) 15 | t( l.a, 1 ) 16 | t( l.b, nil ) 17 | t( err(function() l.b = 2 end), nil, t.diff ) 18 | t( err(function() l.a = 2 end), nil ) 19 | 20 | local l = { a = 1 } 21 | l = locktable( l, 'readnil', 'writenil' ) 22 | t( l.a, 1 ) 23 | t( err(function() return l.b end), nil, t.diff ) 24 | t( err(function() l.b = 2 end), nil, t.diff ) 25 | t( err(function() l.a = 2 end), nil ) 26 | 27 | local w = locktable( {a=1}, 'readnil', 'writenil', 'write' ) 28 | t( w.a, 1 ) 29 | t( err(function() return w.b end), nil, t.diff ) 30 | t( err(function() w.b = 2 end), nil, t.diff ) 31 | t( err(function() w.a = 2 end), nil, t.diff ) 32 | 33 | local w = locktable( {a=1}, 'write' ) 34 | t( w.a, 1 ) 35 | t( w.b, nil ) 36 | t( err(function() w.b = 2 end), nil, t.diff ) 37 | t( err(function() w.a = 2 end), nil, t.diff ) 38 | 39 | local r = locktable( {a=1}, 'read' ) 40 | t( err(function() return r.a end), nil, t.diff ) 41 | t( err(function() return r.b end), nil, t.diff ) 42 | t( err(function() r.b = 2 end), nil ) 43 | t( err(function() r.a = 2 end), nil ) 44 | 45 | local l = {a=1} 46 | local f = locktable( l, 'full' ) 47 | t( err(function() return f.a end), nil, t.diff ) 48 | t( err(function() return f.b end), nil, t.diff ) 49 | t( err(function() f.b = 2 end), nil, t.diff ) 50 | t( err(function() f.a = 2 end), nil, t.diff ) 51 | t( err(function() return l.a end), nil ) 52 | t( err(function() return l.b end), nil ) 53 | t( err(function() l.b = 2 end), nil ) 54 | t( err(function() l.a = 2 end), nil ) 55 | 56 | local l = {} 57 | local f = locktable( l, 'write' ) 58 | t( err(function() f.a = 2 end), nil, t.diff ) 59 | t( l.a, nil ) 60 | t( f.a, nil ) 61 | t( err(function() l.a = 1 end), nil ) 62 | t( l.a, 1 ) 63 | t( f.a, 1 ) 64 | t( err(function() f.a = 2 end), nil, t.diff ) 65 | t( l.a, 1 ) 66 | t( f.a, 1 ) 67 | 68 | local l = { a = 1 } 69 | l = locktable( l, 'readnil', 'writenil' ) 70 | t( l.a, 1 ) 71 | t( err(function() return l.b end), nil, t.diff ) 72 | t( err(function() l.b = 2 end), nil, t.diff ) 73 | t( err(function() l.a = 2 end), nil ) 74 | 75 | local l = { a = 1 } 76 | l = locktable( l, 'iterate' ) 77 | t( err(function() for _ in pairs(l) do end end), nil, t.diff ) 78 | 79 | t( global_a, nil ) 80 | t( global_b, nil ) 81 | 82 | local oldenv = _ENV 83 | global_a = 1 84 | _ENV = locktable( _ENV, 'readnil' ) 85 | t( global_a, 1 ) 86 | t( err(function() return global_b end), nil, t.diff ) 87 | t( err(function() global_b = 2 end), nil ) 88 | t( err(function() global_a = 2 end), nil ) 89 | 90 | _ENV = oldenv 91 | t( global_x, nil ) 92 | t( global_y, nil ) 93 | 94 | global_x = 1 95 | setmetatable(_ENV, getmetatable(locktable( _ENV, 'readnil' ))) 96 | t( global_x, 1 ) 97 | t( err(function() return global_y end), nil, t.diff ) 98 | t( err(function() global_y = 2 end), nil ) 99 | t( err(function() global_x = 2 end), nil ) 100 | 101 | t.test_embedded_example() 102 | 103 | t() 104 | -------------------------------------------------------------------------------- /test/logline.ex1.lua: -------------------------------------------------------------------------------- 1 | local logline = require "logline" 2 | local t = require 'testhelper' 3 | 4 | -- Default log level is 25 a.k.a. ERROR 5 | -- Only logline with smaller level will generate a message 6 | 7 | t( logline( 10, "test" ), "|", t.patsame ) 8 | t( logline( 25, "test" ), "|", t.patsame ) 9 | t( logline( 26, "test" ), nil, t.patsame ) 10 | t( logline( 99, "test" ), nil, t.patsame ) 11 | 12 | -- Change log level 13 | logline( 60 ) 14 | t( logline( 10, "test" ), "|", t.patsame ) 15 | t( logline( 60, "test" ), "|", t.patsame ) 16 | t( logline( 61, "test" ), nil, t.patsame ) 17 | t( logline( 99, "test" ), nil, t.patsame ) 18 | 19 | -- Symbolic log level name 20 | 21 | logline( "error" ) 22 | t( logline( 25, "test" ), "|", t.patsame ) 23 | t( logline( 26, "test" ), nil, t.patsame ) 24 | t( logline( "error", "test" ), "|", t.patsame ) 25 | t( logline( "debug", "test" ), nil, t.patsame ) 26 | t( logline( "info", "test" ), nil, t.patsame ) 27 | t( logline( "verbose", "test" ), nil, t.patsame ) 28 | 29 | logline( "debug" ) 30 | t( logline( 50, "test" ), "|", t.patsame ) 31 | t( logline( 51, "test" ), nil, t.patsame ) 32 | t( logline( "error", "test" ), "|", t.patsame ) 33 | t( logline( "debug", "test" ), "|", t.patsame ) 34 | t( logline( "info", "test" ), nil, t.patsame ) 35 | t( logline( "verbose", "test" ), nil, t.patsame ) 36 | 37 | logline( "info" ) 38 | t( logline( 75, "test" ), "|", t.patsame ) 39 | t( logline( 76, "test" ), nil, t.patsame ) 40 | t( logline( "error", "test" ), "|", t.patsame ) 41 | t( logline( "debug", "test" ), "|", t.patsame ) 42 | t( logline( "info", "test" ), "|", t.patsame ) 43 | t( logline( "verbose", "test" ), nil, t.patsame ) 44 | 45 | logline( "verbose" ) 46 | t( logline( 99, "test" ), "|", t.patsame ) 47 | t( logline( 100, "test" ), nil, t.patsame ) 48 | t( logline( "error", "test" ), "|", t.patsame ) 49 | t( logline( "debug", "test" ), "|", t.patsame ) 50 | t( logline( "info", "test" ), "|", t.patsame ) 51 | t( logline( "verbose", "test" ), "|", t.patsame ) 52 | 53 | -- Message contains source position 54 | t( logline( 99, "test" ), "logline%.ex1%.lua:54", t.patsame ) -- he line 54 is this one 55 | 56 | -- In some case the caller source position is used: 57 | -- - Tail calls 58 | -- - Functions with names that start or end with "log" 59 | 60 | function wraplog( ... ) return logline( 99, ... ) end 61 | function wraplogfakebarrier( ... ) return logline( 99, ... ) end 62 | function wraplogbarrier( ... ) 63 | local res = logline( 99, ... ) -- line 63 64 | return res 65 | end 66 | 67 | t( wraplog( "test" ), "logline%.ex1%.lua:67", t.patsame ) -- line 67 68 | t( wraplogfakebarrier( "test" ), "logline%.ex1%.lua:68", t.patsame ) -- line 68 69 | t( wraplogbarrier( "test" ), "logline%.ex1%.lua:63", t.patsame ) 70 | 71 | -- The argument are appended to the result string 72 | t( logline( 99, "a", 1), "| a | 1 | $", t.patsame ) 73 | 74 | print( "# "..logline( 80, "ok" ) ) 75 | 76 | t.test_embedded_example() 77 | 78 | t( ) 79 | 80 | -------------------------------------------------------------------------------- /test/lzw.ex1.lua: -------------------------------------------------------------------------------- 1 | local lzw = require "lzw" 2 | local t = require "testhelper" 3 | 4 | local function e(str, def) 5 | local e = lzw(def) 6 | return e(str)..e() 7 | end 8 | 9 | local function d(str, def) 10 | local _, d = lzw(def) 11 | return d(str) 12 | end 13 | 14 | local a, x 15 | 16 | t( "a", e"a" ) 17 | t( "aa\x00", e"aa" ) 18 | t( "aa\x00b\x00\x00\x01c\x00", e"aabaac" ) 19 | t( "aa\x00b\x00\x00\x01", e"aabaa" ) 20 | 21 | t( "a", d"a" ) 22 | t( "aa", d"aa\x00" ) 23 | t( "aabaac", d"aa\x00b\x00\x00\x01c\x00" ) 24 | t( "aabaa", d"aa\x00b\x00\x00\x01" ) 25 | 26 | t( "aa\x00b\x00c\x00\x00\x01\x01\x01\x02\x01\x03\x01", e"aabcaaabbcca" ) 27 | t( "aabcaaabbcca", d"aa\x00b\x00c\x00\x00\x01\x01\x01\x02\x01\x03\x01" ) 28 | 29 | -- nothing strange for compression 30 | t( "ab\x00\x00\x01\x02\x01", e"abababa" ) 31 | 32 | -- special decompression case: "ababa" sequencies 33 | -- a = single char, b = string, ab = alredy in dictionary, aba = not in dict 34 | t( "abababa", d"ab\x00\x00\x01\x02\x01" ) 35 | 36 | t( "aa\x00b\x00c\x00\x00\x01\x01\x01\x02\x01\x63\x00\x61\x00\x78\x00", e("aabcaaabbccax", {dict_size=6}) ) 37 | t( "aabcaaabbccax", d("aa\x00b\x00c\x00\x00\x01\x01\x01\x02\x01\x63\x00\x61\x00\x78\x00", {dict_size=6}) ) 38 | 39 | t( "aa\x00b\x00", e("aabaac",{max_size=5}) ) 40 | t( "aa\x00", e("aabaac",{max_size=4}) ) 41 | t( "aa\x00b\x00", e("aabaacxxx",{max_size=5}) ) 42 | t( "aa\x00", e("aabaacxxx",{max_size=4}) ) 43 | 44 | -- reasonable compression factor WITHOUT ababa sequencies 45 | local compressable = "" 46 | for _, k in pairs{"A","B","A","C","A","D","A","E","A","F","A","G"} do 47 | compressable = compressable .. "-0-1-2-3-4-5-6-7-8-9-" .. k 48 | end 49 | 50 | x = e(compressable) 51 | t(true, #compressable > #x+10) 52 | 53 | -- random split in 2 pieces (with ababa sequences) 54 | math.randomseed(os.time()) 55 | local ababa = "yaabcaaabbcca" .. ("x"):rep(40) -- the suffix is needed to bypass any possible low-compression rate protection 56 | for i=1,10 do 57 | local str = ababa 58 | local e, d = lzw() 59 | 60 | local s = math.random(1,#str) 61 | str = e(str:sub(1,s))..e(str:sub(s+1))..e() 62 | 63 | s = math.random(1,#str-1) 64 | local b = d(str:sub(1,s))..d(str:sub(s+1)) 65 | 66 | t( ababa, b ) 67 | end 68 | 69 | t.test_embedded_example() 70 | 71 | t() 72 | 73 | -------------------------------------------------------------------------------- /test/measure.ex1.lua: -------------------------------------------------------------------------------- 1 | local measure = require 'measure' 2 | local t = require 'testhelper' 3 | local e002 = t.number_tollerance(0.002) 4 | 5 | local a,b,c 6 | 7 | a = measure() 8 | t( a(), 0 ) 9 | t( a(), 0 ) 10 | t( a(1), 1 ) 11 | t( a(), 1 ) 12 | t( a(3), 2 ) 13 | t( a(5), 3 ) 14 | 15 | -- mean 16 | a = measure() 17 | t( a(), 0 ) 18 | t( a(1), 1 ) 19 | 20 | -- sample number 21 | a = measure() 22 | b = {a()} 23 | t( b[5], 0 ) 24 | a(0) 25 | b = {a()} 26 | t( b[5], 1 ) 27 | b = {a()} 28 | t( b[5], 1 ) 29 | a(0) 30 | b = {a()} 31 | t( b[5], 2 ) 32 | b = {a()} 33 | t( b[5], 2 ) 34 | 35 | -- standard deviation 36 | a = measure() 37 | a(0) 38 | a(0) 39 | a(0) 40 | a(1) 41 | b = {a()} 42 | t( b[2], 0.5 ) 43 | 44 | -- normalized skewness 45 | a = measure() 46 | a(0) 47 | a(0) 48 | a(0) 49 | a(0) 50 | a(1) 51 | b = {a()} 52 | t( b[3], 1.5, e002 ) 53 | 54 | -- normalized kurtosis 55 | a = measure() 56 | a(2) 57 | a(2) 58 | a(8) 59 | b = {a()} 60 | t( b[4], 1.5, e002 ) 61 | a(4) 62 | b = {a()} 63 | t( b[4], 2.0, e002 ) 64 | 65 | -- minimum 66 | a = measure() 67 | b = {a()} 68 | t( b[6], nil ) 69 | a(2) 70 | b = {a()} 71 | t( b[6], 2.0, e002 ) 72 | a(1) 73 | b = {a()} 74 | t( b[6], 1.0, e002 ) 75 | a(3) 76 | b = {a()} 77 | t( b[6], 1.0, e002 ) 78 | 79 | -- maximum 80 | a = measure() 81 | b = {a()} 82 | t( b[7], nil ) 83 | a(2) 84 | b = {a()} 85 | t( b[7], 2.0, e002 ) 86 | a(3) 87 | b = {a()} 88 | t( b[7], 3.0, e002 ) 89 | a(1) 90 | b = {a()} 91 | t( b[7], 3.0, e002 ) 92 | 93 | a = measure() 94 | a(2) 95 | a(2) 96 | b = {a()} 97 | t( b[1], 2.0, e002 ) 98 | t( b[2], 0, e002 ) 99 | t( b[6], 2, e002 ) 100 | t( b[7], 2, e002 ) 101 | 102 | a(8) 103 | b = {a()} 104 | t( b[1], 4.0, e002 ) 105 | t( b[2], 3.464, e002 ) 106 | t( b[3], 0.707, e002 ) 107 | t( b[4], 1.5, e002 ) 108 | t( b[5], 3 ) 109 | t( b[6], 2, e002 ) 110 | t( b[7], 8, e002 ) 111 | 112 | a(4) 113 | b = {a()} 114 | t( b[1], 4.0 ) 115 | t( b[2], 2.828, e002 ) 116 | t( b[3], 0.816, e002 ) 117 | t( b[4], 2.0, e002 ) 118 | t( b[5], 4 ) 119 | t( b[6], 2, e002 ) 120 | t( b[7], 8, e002 ) 121 | 122 | -- Merge measurements 123 | a = measure() 124 | b = measure() 125 | a(2) a(2) 126 | b(4) b(8) 127 | a = measure{a, b} 128 | a = {a()} 129 | b = measure() 130 | b(2) b(4) b(8) b(2) 131 | b = {b()} 132 | t( a[1], b[1], e002 ) 133 | t( a[2], b[2], e002 ) 134 | t( a[3], b[3], e002 ) 135 | t( a[4], b[4], e002 ) 136 | t( a[5], b[5], e002 ) 137 | t( a[6], b[6], e002 ) 138 | t( a[7], b[7], e002 ) 139 | 140 | t.test_embedded_example() 141 | 142 | t() 143 | -------------------------------------------------------------------------------- /test/memo.ex1.lua: -------------------------------------------------------------------------------- 1 | 2 | local memo = require 'memo' 3 | local t = require 'testhelper' 4 | 5 | local c = 0 6 | local add=memo(function(a,b) c=c+1 return a+b end) 7 | 8 | t(c, 0) 9 | t(add(1,2), 3) 10 | t(c, 1) 11 | t(add(1,2), 3) 12 | t(c, 1) 13 | t(add(1,2), 3) 14 | t(c, 1) 15 | t(add(2,2), 4) 16 | t(c, 2) 17 | t(add(2,2), 4) 18 | t(c, 2) 19 | 20 | t.test_embedded_example() 21 | 22 | t() 23 | 24 | -------------------------------------------------------------------------------- /test/object.ex1.lua: -------------------------------------------------------------------------------- 1 | local object = require 'object' 2 | local t = require 'testhelper' 3 | 4 | local a,b,c,d,e,f,g 5 | 6 | a = {} 7 | b = object.inherit{ a } 8 | c = object.inherit{ a } 9 | 10 | t( a, b, t.diff ) 11 | t( a, c, t.diff ) 12 | t( c, b, t.diff ) 13 | 14 | t( a.method, nil ) 15 | t( b.method, nil ) 16 | t( c.method, nil ) 17 | 18 | f = function() end 19 | a.method = f 20 | 21 | t( a.method, f ) 22 | t( b.method, f ) 23 | t( c.method, f ) 24 | 25 | g = function() end 26 | b.method = g 27 | 28 | t( a.method, f ) 29 | t( b.method, g ) 30 | t( c.method, f ) 31 | 32 | h = function() end 33 | a.method = h 34 | 35 | t( a.method, h ) 36 | t( b.method, g ) 37 | t( c.method, h ) 38 | 39 | a = {} 40 | b = {} 41 | c = object.inherit{ a, b } 42 | 43 | f = function() end 44 | b.method = f 45 | 46 | t( a.method, nil ) 47 | t( b.method, f ) 48 | t( c.method, f ) 49 | 50 | g = function() end 51 | a.method = g 52 | 53 | t( a.method, g ) 54 | t( b.method, f ) 55 | t( c.method, g ) 56 | 57 | h = function() end 58 | b.method = h 59 | 60 | t( a.method, g ) 61 | t( b.method, h ) 62 | t( c.method, g ) 63 | 64 | f = function() end 65 | c.method = f 66 | 67 | t( a.method, g ) 68 | t( b.method, h ) 69 | t( c.method, f ) 70 | 71 | a = {} 72 | b = {} 73 | c = object.inherit{ a, b } 74 | 75 | t( object.isderived( c, a ), true ) 76 | t( object.isderived( a, c ), false ) 77 | t( object.isderived( c, b ), true ) 78 | t( object.isderived( b, c ), false ) 79 | 80 | a = {} 81 | b = object.inherit{ a } 82 | c = object.inherit{ b } 83 | t( object.isderived( c, a ), true ) 84 | t( object.isderived( a, c ), false ) 85 | 86 | a = {a=true} 87 | b = {b=true} 88 | 89 | t( b.a, nil ) 90 | t( a.b, nil ) 91 | 92 | c = object.inherit({ a }, b ) 93 | t( b, c ) 94 | t( a.b, nil ) 95 | t( b.a, true ) 96 | 97 | d = {d=true} 98 | 99 | c = object.inherit({ d }, b ) 100 | t( b, c ) 101 | t( a.b, nil ) 102 | t( b.a, true ) 103 | t( d.b, nil ) 104 | t( b.d, true ) 105 | 106 | e = {e=true} 107 | 108 | object.inherit({ e }, a ) 109 | t( b, c ) 110 | t( a.b, nil ) 111 | t( b.a, true ) 112 | t( d.b, nil ) 113 | t( b.d, true ) 114 | t( e.b, nil ) 115 | t( a.e, true ) 116 | t( b.e, true ) 117 | 118 | t( object.isderived( a, b ), false ) 119 | t( object.isderived( b, a ), true ) 120 | t( object.isderived( d, b ), false ) 121 | t( object.isderived( b, d ), true ) 122 | t( object.isderived( e, b ), false ) 123 | t( object.isderived( a, e ), true ) 124 | t( object.isderived( b, e ), true ) 125 | 126 | a = {method=function()end} 127 | b = object.inherit{ a } 128 | a = {} 129 | collectgarbage() 130 | t( type(b.method), 'function') 131 | 132 | t() 133 | 134 | -------------------------------------------------------------------------------- /test/pathpart.ex1.lua: -------------------------------------------------------------------------------- 1 | local pathpart = require 'pathpart' 2 | local t = require 'testhelper' 3 | 4 | t( pathpart'', {}, t.deepsame ) 5 | t( pathpart{}, '' ) 6 | 7 | t( pathpart'path/name.ext', {'path','name.ext'}, t.deepsame ) 8 | t( pathpart'path\\name.ext', {'path','name.ext'}, t.deepsame ) 9 | 10 | t( pathpart'path/b/name.ext', {'path','b','name.ext'}, t.deepsame ) 11 | t( pathpart'/path/name.ext', {'path','name.ext'}, t.deepsame ) 12 | 13 | t( pathpart'path/to/', {'path','to'}, t.deepsame ) 14 | t( pathpart'name.ext', {'name.ext'}, t.deepsame ) 15 | 16 | local s = package.config:sub(1,1) 17 | 18 | t( pathpart{'path','name.ext'}, 'path'..s..'name.ext' ) 19 | t( pathpart{'path','pathb','name.ext'}, 'path'..s..'pathb'..s..'name.ext' ) 20 | 21 | t( pathpart{'path','to'}, 'path'..s..'to', t.deepsame ) 22 | t( pathpart{'name.ext'}, 'name.ext', t.deepsame ) 23 | 24 | t.test_embedded_example() 25 | 26 | t() 27 | -------------------------------------------------------------------------------- /test/rawhtml.ex1.lua: -------------------------------------------------------------------------------- 1 | local rawhtml = require 'rawhtml' 2 | local t = require 'testhelper' 3 | 4 | t( rawhtml'', '' ) 5 | t( rawhtml'{', '{+}' ) 6 | t( rawhtml'}', '{-}' ) 7 | t( rawhtml':', '{=}' ) 8 | 9 | t( rawhtml'
', '{div:' ) 10 | t( rawhtml'
', '}' ) 11 | t( rawhtml'
', '{div:}' ) 12 | 13 | t( rawhtml'
hi
', '{div:hi}' ) 14 | t( rawhtml'
hi
', '{div:{b:hi}}' ) 15 | t( rawhtml'{:}
xy
', '{+}{=}{-}{div:x{b:}y}' ) 16 | 17 | t( rawhtml'
', '{div:{=attribute=:x y z}' ) 18 | t( rawhtml'
', '{div:{=attribute=:x y z}' ) 19 | t( rawhtml'
', '{div:{=attribute=:x y z}}' ) 20 | t( rawhtml'
', '}' ) 21 | 22 | t( rawhtml'', 'bla bla}' ) 24 | t( rawhtml'', '{=comment=:bla bla}' ) 25 | 26 | local r = require 'rawmark' 27 | 28 | t( r( rawhtml'
x< b />y
' ), {type='',{type='=comment=','{',':','}'},{type='div',{type='=attribute=','my-attr="hi"'},'x',{type='b',''},'y'}}, t.deepsame ) 29 | 30 | t.test_embedded_example() 31 | 32 | t() 33 | 34 | -------------------------------------------------------------------------------- /test/rawmark.ex1.lua: -------------------------------------------------------------------------------- 1 | local rawmark = require 'rawmark' 2 | local t = require 'testhelper' 3 | 4 | local v = function(...) print('# '..((require'valueprint'(...)):gsub('\r?\n','\n# '))) end 5 | 6 | t( rawmark( '' ), { '', type='' }, t.deepsame ) 7 | t( rawmark( 'a' ), { 'a', type='' }, t.deepsame ) 8 | 9 | t( rawmark( '{}' ), {{ '', type='' }, type='' }, t.deepsame ) 10 | t( rawmark( '{a}' ), {{ 'a', type='' }, type='' }, t.deepsame ) 11 | t( rawmark( '{:a}' ), {{ 'a', type='' }, type='' }, t.deepsame ) 12 | 13 | t( rawmark( 'a{}' ), { 'a', { "", type='' }, type='' }, t.deepsame ) 14 | 15 | t( rawmark( 'a{b}' ), { 'a', { "b", type='' }, type='' }, t.deepsame ) 16 | t( rawmark( '{b}a' ), {{ "b", type='' }, 'a', type='' }, t.deepsame ) 17 | t( rawmark( 'a{b}c' ), { 'a', { "b", type='' }, 'c', type='' }, t.deepsame ) 18 | 19 | t( rawmark( '{a}b{c}' ), {{ "a", type='' }, 'b', { "c", type='' }, type='' }, t.deepsame ) 20 | t( rawmark( 'a{b}{c}' ), { "a", { "b", type='' }, { "c", type='' }, type='' }, t.deepsame ) 21 | t( rawmark( '{a}{b}c' ), {{ "a", type='' }, { "b", type='' }, "c", type='' }, t.deepsame ) 22 | 23 | t( rawmark( '{{a}}' ), {{{ 'a', type='' }, type='' }, type='' }, t.deepsame ) 24 | t( rawmark( '{{{a}}}' ), {{{{ 'a', type='' }, type='' }, type='' }, type='' }, t.deepsame ) 25 | t( rawmark( '{{a}}b{{c}}' ), {{{ 'a', type='' }, type='' }, 'b', {{ 'c', type='' }, type='' }, type='' }, t.deepsame ) 26 | 27 | t( rawmark( '', 't' ), { '', type='t' }, t.deepsame ) 28 | t( rawmark( '{t:}' ), {{ '', type='t' }, type='' }, t.deepsame ) 29 | t( rawmark( '{t:a}' ), {{ 'a', type='t' }, type='' }, t.deepsame ) 30 | t( rawmark( '{t::}' ), {{ ':', type='t' }, type='' }, t.deepsame ) 31 | t( rawmark( '{t:a:c}' ), {{ 'a:c', type='t' }, type='' }, t.deepsame ) 32 | t( rawmark( '{tt:a}b{TT2:c}', 't3' ), {{ "a", type='tt' }, 'b', { "c", type='TT2' }, type='t3' }, t.deepsame ) 33 | 34 | t( rawmark( '{a-+_b:}' ), {{ '', type='a-+_b' }, type='' }, t.deepsame ) 35 | 36 | t( rawmark( '{+}' ), {'{', type='' }, t.deepsame ) 37 | t( rawmark( '{-}' ), {'}', type='' }, t.deepsame ) 38 | t( rawmark( '{=}' ), {':', type='' }, t.deepsame ) 39 | t( rawmark( 'a{+}b{=}c{:d}e{-}' ), { 'a','{','b',':','c', {'d', type=''} ,'e','}', type='' }, t.deepsame ) 40 | 41 | t( rawmark( 'a{b' ), {'a{b', type='' }, t.deepsame ) 42 | t( rawmark( 'a}b' ), {'a}b', type='' }, t.deepsame ) 43 | t( rawmark( 'a{b{c}d' ), {type='', 'a{b', { type='', 'c'}, 'd' }, t.deepsame ) -- TODO : change this ? 44 | t( rawmark( 'a{b}c}d' ), {type='', 'a', { type='', 'b'}, 'c}d' }, t.deepsame ) -- TODO : change this ? 45 | 46 | t.test_embedded_example() 47 | 48 | t() 49 | 50 | -------------------------------------------------------------------------------- /test/readfile.ex1.lua: -------------------------------------------------------------------------------- 1 | local readfile = require 'readfile' 2 | local t = require 'testhelper' 3 | 4 | t.writefile('tmp_1.txt', '') 5 | t( readfile('tmp_1.txt'), '' ) 6 | 7 | t.writefile('tmp_1.txt', 'aaa\naaa') 8 | t( readfile('tmp_1.txt'), 'aaa\naaa' ) 9 | 10 | t.writefile('tmp_1.txt', 'aaa\naaa') 11 | t( readfile('tmp_1.txt', 'l'), {'aaa','aaa'}, t.deepsame ) 12 | 13 | t.writefile('tmp_1.txt', 'aaa\n') 14 | t( readfile('tmp_1.txt', 'l'), 'aaa' ) 15 | 16 | t.writefile('tmp_1.txt', 'aaa\n\raaa') 17 | t( readfile('tmp_1.txt', 'L'), {'aaa\n','\raaa'}, t.deepsame ) 18 | 19 | t.writefile('tmp_1.txt', 'aaaa') 20 | t( readfile('tmp_1.txt', 2), {'aa','aa'}, t.deepsame ) 21 | 22 | t.writefile('tmp_1.txt', '1 1.2 -1e3') 23 | t( readfile('tmp_1.txt', 'n'), {1,1.2,-1e3}, t.deepsame ) 24 | 25 | t.test_embedded_example() 26 | os.remove('tmp.txt') 27 | 28 | t() 29 | -------------------------------------------------------------------------------- /test/searchluakeyword.ex1.lua: -------------------------------------------------------------------------------- 1 | local searchluakeyword = require 'searchluakeyword' 2 | local t = require 'testhelper' 3 | 4 | t( searchluakeyword'', {}, t.deepsame ) 5 | 6 | t( searchluakeyword"do", {['do']={1}}, t.deepsame ) 7 | t( searchluakeyword("<<",'s'), {['<<']={1}}, t.deepsame ) 8 | t( searchluakeyword"::xxx::", {['::label::']={1}}, t.deepsame ) 9 | t( searchluakeyword"::yy::", {['::label::']={1}}, t.deepsame ) 10 | 11 | t( searchluakeyword"do do", {['do']={1,4}}, t.deepsame ) 12 | t( searchluakeyword"dodo", {}, t.deepsame ) 13 | t( searchluakeyword"ado", {}, t.deepsame ) 14 | t( searchluakeyword"doa", {}, t.deepsame ) 15 | t( searchluakeyword"do1", {}, t.deepsame ) 16 | t( searchluakeyword"do_", {}, t.deepsame ) 17 | 18 | t( searchluakeyword("for goto function nil false do and",'i'), {['goto']={5},['function']={10}}, t.deepsame ) 19 | 20 | t( searchluakeyword"do -- do \n", {['do']={1}}, t.deepsame ) 21 | t( searchluakeyword"do -- do \ndo", {['do']={1,11}}, t.deepsame ) 22 | t( searchluakeyword"do -- do", {['do']={1}}, t.deepsame ) 23 | 24 | t( searchluakeyword"do do end end", {['do']={1,5},['end']={9,13}}, t.deepsame ) 25 | t( searchluakeyword"do 'do' end end", {['do']={1},['end']={9,13}}, t.deepsame ) 26 | t( searchluakeyword'do "do" end end', {['do']={1},['end']={9,13}}, t.deepsame ) 27 | t( searchluakeyword"do '\"do\"' end end", {['do']={1},['end']={11,15}}, t.deepsame ) 28 | t( searchluakeyword'do "\'do\'" end end', {['do']={1},['end']={11,15}}, t.deepsame ) 29 | t( searchluakeyword"do [[do]] end end", {['do']={1},['end']={11,15}}, t.deepsame ) 30 | t( searchluakeyword"do [=[do]=] end end", {['do']={1},['end']={13,17}}, t.deepsame ) 31 | t( searchluakeyword"do [==[do]=] end]==] end", {['do']={1},['end']={22}}, t.deepsame ) 32 | t( searchluakeyword"do [[do end end", {['do']={1}}, t.deepsame ) 33 | 34 | t( searchluakeyword"for", {['for']={1}}, t.deepsame ) 35 | t( searchluakeyword"break", {['break']={1}}, t.deepsame ) 36 | t( searchluakeyword"goto", {['goto']={1}}, t.deepsame ) 37 | t( searchluakeyword"end", {['end']={1}}, t.deepsame ) 38 | t( searchluakeyword"while", {['while']={1}}, t.deepsame ) 39 | t( searchluakeyword"repeat", {['repeat']={1}}, t.deepsame ) 40 | t( searchluakeyword"until", {['until']={1}}, t.deepsame ) 41 | t( searchluakeyword"if", {['if']={1}}, t.deepsame ) 42 | t( searchluakeyword"then", {['then']={1}}, t.deepsame ) 43 | t( searchluakeyword"elseif", {['elseif']={1}}, t.deepsame ) 44 | t( searchluakeyword"else", {['else']={1}}, t.deepsame ) 45 | t( searchluakeyword"in", {['in']={1}}, t.deepsame ) 46 | t( searchluakeyword"function", {['function']={1}}, t.deepsame ) 47 | t( searchluakeyword"nil", {['nil']={1}}, t.deepsame ) 48 | t( searchluakeyword"false", {['false']={1}}, t.deepsame ) 49 | t( searchluakeyword"true", {['true']={1}}, t.deepsame ) 50 | t( searchluakeyword"and", {['and']={1}}, t.deepsame ) 51 | t( searchluakeyword"or", {['or']={1}}, t.deepsame ) 52 | t( searchluakeyword"not", {['not']={1}}, t.deepsame ) 53 | t( searchluakeyword(';' ,'s'), {[';' ]={1}}, t.deepsame ) 54 | t( searchluakeyword('{' ,'s'), {['{' ]={1}}, t.deepsame ) 55 | t( searchluakeyword('{' ,'s'), {['{' ]={1}}, t.deepsame ) 56 | t( searchluakeyword('}' ,'s'), {['}' ]={1}}, t.deepsame ) 57 | t( searchluakeyword('[' ,'s'), {['[' ]={1}}, t.deepsame ) 58 | t( searchluakeyword(']' ,'s'), {[']' ]={1}}, t.deepsame ) 59 | t( searchluakeyword('...','s'), {['...']={1}}, t.deepsame ) 60 | t( searchluakeyword('(' ,'s'), {['(' ]={1}}, t.deepsame ) 61 | t( searchluakeyword(')' ,'s'), {[')' ]={1}}, t.deepsame ) 62 | t( searchluakeyword(':' ,'s'), {[':' ]={1}}, t.deepsame ) 63 | t( searchluakeyword('.' ,'s'), {['.' ]={1}}, t.deepsame ) 64 | t( searchluakeyword('=' ,'s'), {['=' ]={1}}, t.deepsame ) 65 | t( searchluakeyword('+' ,'s'), {['+' ]={1}}, t.deepsame ) 66 | t( searchluakeyword('-' ,'s'), {['-' ]={1}}, t.deepsame ) 67 | t( searchluakeyword('*' ,'s'), {['*' ]={1}}, t.deepsame ) 68 | t( searchluakeyword('/' ,'s'), {['/' ]={1}}, t.deepsame ) 69 | t( searchluakeyword('//' ,'s'), {['//' ]={1}}, t.deepsame ) 70 | t( searchluakeyword('^' ,'s'), {['^' ]={1}}, t.deepsame ) 71 | t( searchluakeyword('%' ,'s'), {['%' ]={1}}, t.deepsame ) 72 | t( searchluakeyword('&' ,'s'), {['&' ]={1}}, t.deepsame ) 73 | t( searchluakeyword('~' ,'s'), {['~' ]={1}}, t.deepsame ) 74 | t( searchluakeyword('|' ,'s'), {['|' ]={1}}, t.deepsame ) 75 | t( searchluakeyword('>>' ,'s'), {['>>' ]={1}}, t.deepsame ) 76 | t( searchluakeyword('<<' ,'s'), {['<<' ]={1}}, t.deepsame ) 77 | t( searchluakeyword('..' ,'s'), {['..' ]={1}}, t.deepsame ) 78 | t( searchluakeyword('<' ,'s'), {['<' ]={1}}, t.deepsame ) 79 | t( searchluakeyword('<=' ,'s'), {['<=' ]={1}}, t.deepsame ) 80 | t( searchluakeyword('>' ,'s'), {['>' ]={1}}, t.deepsame ) 81 | t( searchluakeyword('>=' ,'s'), {['>=' ]={1}}, t.deepsame ) 82 | t( searchluakeyword('==' ,'s'), {['==' ]={1}}, t.deepsame ) 83 | t( searchluakeyword('~=' ,'s'), {['~=' ]={1}}, t.deepsame ) 84 | t( searchluakeyword('-' ,'s'), {['-' ]={1}}, t.deepsame ) 85 | t( searchluakeyword('#' ,'s'), {['#' ]={1}}, t.deepsame ) 86 | 87 | t() 88 | 89 | -------------------------------------------------------------------------------- /test/serialize.ex1.lua: -------------------------------------------------------------------------------- 1 | local serialize = require "serialize" 2 | local t = require "testhelper" 3 | 4 | local function reco( v ) 5 | return load( 'return ' .. serialize( v ) )() 6 | end 7 | 8 | -- Simple values 9 | t( reco( nil ), nil, t.deepsame ) 10 | t( reco( true ), true, t.deepsame ) 11 | t( reco( 1 ), 1, t.deepsame ) 12 | t( reco( "hi" ), "hi", t.deepsame ) 13 | t( reco( {} ), {}, t.deepsame ) 14 | 15 | t( serialize( "\n" ), '"\\n"' ) 16 | t( serialize( "\r" ), '"\\13"' ) 17 | 18 | -- Table with values 19 | t( reco( { a = true, b = { "c", 1, { d = "e" } }, } ), 20 | { a = true, b = { "c", 1, { d = "e" } }, }, 21 | t.deepsame ) 22 | 23 | -- Table table key 24 | t( reco( { [ { ok = "ok" } ] = "ok", } ), 25 | { [ { ok = "ok" } ] = "ok", }, 26 | t.deepsame ) 27 | 28 | -- Multiple table values 29 | t( reco( { ["a"] = { [ "a" ] = "a", }, ["b"] = { [ "b" ] = "b", }, } ), 30 | { ["a"] = { [ "a" ] = "a", }, ["b"] = { [ "b" ] = "b", }, }, 31 | t.deepsame ) 32 | 33 | -- Mixed key/value Table 34 | t( reco( { ["ok"] = { [ { ok = "ok" } ] = "ok", }, } ), 35 | { ["ok"] = { [ { ok = "ok" } ] = "ok", }, }, 36 | t.deepsame ) 37 | 38 | -- Sequence 39 | t( reco( { 'a','b',{'c','d'},'e'} ), 40 | { 'a','b',{'c','d'},'e'}, 41 | t.deepsame ) 42 | 43 | -- Sequence with holes 44 | t( reco( { nil,nil,nil,'a',{'c','d'},} ), 45 | { nil,nil,nil,'a',{'c','d'},}, 46 | t.deepsame ) 47 | 48 | -- Table with reference 49 | local atab = { a = "a" } 50 | t( reco( { atab, a = atab, } ), 51 | { atab, a = atab, }, 52 | t.deepsame ) 53 | 54 | -- Sequence with tables 55 | local atab = {} 56 | t( reco( { 1, atab, 2, atab, 3,} ), 57 | { 1, atab, 2, atab, 3,}, 58 | t.deepsame ) 59 | 60 | -- Table with cycle 61 | atab = {} 62 | atab.a = {} 63 | atab.a.a = atab 64 | t( reco( atab ), atab, t.deepsame ) 65 | 66 | -- Table with multiple cycle 67 | atab = {} 68 | atab.kv = {} 69 | atab[atab.kv] = atab.kv 70 | atab[atab.kv][atab.kv] = atab[atab.kv] 71 | t( reco( atab ), atab, t.deepsame ) 72 | 73 | -- Too deep table 74 | local cur = atab 75 | for n = 1, 200 do 76 | cur.q = {} 77 | cur = cur.q 78 | end 79 | t( reco( atab ), atab, t.deepsame ) 80 | 81 | -- Output function 82 | local atab = {'a',2,[{}]={},} 83 | local exp = serialize(atab) 84 | local got = '' 85 | t( serialize(atab, function(d) got = got .. d end), nil ) 86 | t( got, exp ) 87 | 88 | t.test_embedded_example() 89 | 90 | t() 91 | 92 | -------------------------------------------------------------------------------- /test/sha2.ex1.lua: -------------------------------------------------------------------------------- 1 | local sha2 = require 'sha2' 2 | local t = require 'testhelper' 3 | 4 | t( sha2( "Hello world!" ), "C0535E4BE2B79FFD93291305436BF889314E4A3FAEC05ECFFCBB7DF31AD9E51A", t.hexsame ) 5 | 6 | t( sha2( '' ), "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", t.hexsame ) 7 | t( sha2(( "a" ):rep( 1 )), "CA978112CA1BBDCAFAC231B39A23DC4DA786EFF8147C4E72B9807785AFEE48BB", t.hexsame ) 8 | t( sha2(( "b" ):rep( 63 )), "94E419FABAC7F930810F9636354042F8C1426D2F834D4AB65C93DC1E69326B13", t.hexsame ) 9 | t( sha2(( "c" ):rep( 64 )), "52B6419D27BD7F547CEE3B92F8C17A908B8A49601ECBEC161E5030DE1DFE9E0A", t.hexsame ) 10 | t( sha2(( "d" ):rep( 65 )), "899987F295364060C6ABD752A7E895124B467FD7CF56B52CE22F4A684A5723F4", t.hexsame ) 11 | t( sha2(( "e" ):rep( 130 )), "C78A24F98CC9596CAFD6FC954A0664CA5CAD156AD406A8CC246B5E1F56864DB7", t.hexsame ) 12 | 13 | t( sha2(( "\xFF" ), 1), "B9DEBF7D52F36E6468A54817C1FA071166C3A63D384850E1575B42F702DC5AA1", t.hexsame ) 14 | t( sha2(( "\x00" ), 1), "BD4F9E98BEB68C6EAD3243B1B4C7FED75FA4FEAAB1F84795CBD8A98676A2A375", t.hexsame ) 15 | t( sha2(( "a" ):rep( 70 ), 69*8+1), "056ECB5B2DB796F0E49B5A7F3010C5DB3ECA6E87E03EB45F4E618F4867D002A9", t.hexsame ) 16 | t( sha2(( "a" ):rep( 70 ), 69*8+2), "0926C28F521555DB93892916F22414353234FCAB237AC5DC3AE6FA41A51BE15B", t.hexsame ) 17 | t( sha2(( "a" ):rep( 70 ), 69*8+7), "6759507E5A185A774D2C980067B4451671AA70705A35080779AAA6D3CEAA00FC", t.hexsame ) 18 | 19 | local function sha256(x,y) return sha2( x, y, 256 ) end 20 | local function sha224(x,y) return sha2( x, y, 224 ) end 21 | local function sha512(x,y) return sha2( x, y, 512 ) end 22 | local function sha384(x,y) return sha2( x, y, 384 ) end 23 | 24 | t( sha256( "Hello world!" ), "C0535E4BE2B79FFD93291305436BF889314E4A3FAEC05ECFFCBB7DF31AD9E51A", t.hexsame ) 25 | t( sha224( "Hello world!" ), "7E81EBE9E604A0C97FEF0E4CFE71F9BA0ECBA13332BDE953AD1C66E4", t.hexsame ) 26 | t( sha512( "Hello world!" ), "F6CDE2A0F819314CDDE55FC227D8D7DAE3D28CC556222A0A8AD66D91CCAD4AAD6094F517A2182360C9AACF6A3DC323162CB6FD8CDFFEDB0FE038F55E85FFB5B6", t.hexsame ) 27 | t( sha384( "Hello world!" ), "86255FA2C36E4B30969EAE17DC34C772CBEBDFC58B58403900BE87614EB1A34B8780263F255EB5E65CA9BBB8641CCCFE", t.hexsame ) 28 | 29 | t( sha256( '' ), "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", t.hexsame ) 30 | t( sha256(( "a" ):rep( 1 )), "CA978112CA1BBDCAFAC231B39A23DC4DA786EFF8147C4E72B9807785AFEE48BB", t.hexsame ) 31 | t( sha256(( "b" ):rep( 63 )), "94E419FABAC7F930810F9636354042F8C1426D2F834D4AB65C93DC1E69326B13", t.hexsame ) 32 | t( sha256(( "c" ):rep( 64 )), "52B6419D27BD7F547CEE3B92F8C17A908B8A49601ECBEC161E5030DE1DFE9E0A", t.hexsame ) 33 | t( sha256(( "d" ):rep( 65 )), "899987F295364060C6ABD752A7E895124B467FD7CF56B52CE22F4A684A5723F4", t.hexsame ) 34 | t( sha256(( "e" ):rep( 130 )), "C78A24F98CC9596CAFD6FC954A0664CA5CAD156AD406A8CC246B5E1F56864DB7", t.hexsame ) 35 | 36 | t( sha512( '' ), "CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E", t.hexsame ) 37 | t( sha512(( "a" ):rep( 1 )), "1F40FC92DA241694750979EE6CF582F2D5D7D28E18335DE05ABC54D0560E0F5302860C652BF08D560252AA5E74210546F369FBBBCE8C12CFC7957B2652FE9A75", t.hexsame ) 38 | t( sha512(( "b" ):rep( 127 )), "1FB5054735807A95088312066BDD2ACEC2EB8F65454BF77873CDF93998F79C75FC0F229AB4A8FFE0BFD5310A3357272ADCECB378D1F310EE43ED4A0634C6E5B8", t.hexsame ) 39 | t( sha512(( "c" ):rep( 128 )), "1CADAE2171FD051AA72F31D7D11D232D867E9823E0DA1FAB3F40288C46C009ABA8A378454514FA6756D00C1037FFBC32B3716DF881569C545A2E190CE426C79B", t.hexsame ) 40 | t( sha512(( "d" ):rep( 129 )), "30E54405DCC986AE90F830E01FC144190FF756EFD6E7E9FE4BDF9D6416B54C63E5CE18BFCE172DC360436052DB834A37317D0E2085FAF11E3C69A59020CDD8FC", t.hexsame ) 41 | t( sha512(( "e" ):rep( 300 )), "C2202F2BC948039340224757BF24A0B59A24737A3083DF9A8DD062AB7A0717147E025FDAB38CFC5DED56B3E8AC8072D87457AFA143DBD4F26ACF4CB26BB35266", t.hexsame ) 42 | 43 | t.test_embedded_example() 44 | 45 | t() 46 | -------------------------------------------------------------------------------- /test/shellcommand.ex1.lua: -------------------------------------------------------------------------------- 1 | local shellcommand = require 'shellcommand' 2 | local t = require 'testhelper' 3 | 4 | local lua, argdumputiil, outpath = t.argdumputil() 5 | 6 | t( shellcommand(), '' ) 7 | t( shellcommand{}, '' ) 8 | 9 | os.execute( shellcommand{lua, argdumputiil, 'x'} ) 10 | t( t.readfile(outpath), 'x' ) 11 | 12 | os.execute( shellcommand{lua, argdumputiil, 'x', 'y'} ) 13 | t( t.readfile(outpath), 'xy' ) 14 | 15 | t( shellcommand{lua, argdumputiil, '-i'}, shellcommand({lua, argdumputiil})..' -i' ) 16 | t( shellcommand{lua, argdumputiil, '-o'}, shellcommand({lua, argdumputiil})..' -o' ) 17 | t( shellcommand{lua, argdumputiil, '-e'}, shellcommand({lua, argdumputiil})..' -e' ) 18 | 19 | t.writefile('tmp_1.txt','abc') 20 | os.execute( shellcommand{lua, argdumputiil, '-i', input='tmp_1.txt'} ) 21 | t( t.readfile(outpath), 'abc' ) 22 | 23 | os.execute( shellcommand{lua, argdumputiil, 'z', 'w', '-o', output='tmp_2.txt'} ) 24 | t( t.readfile(outpath), 'zw' ) 25 | t( t.readfile( 'tmp_2.txt'), 'zw' ) 26 | 27 | os.execute( shellcommand{lua, argdumputiil, '-i', '-o', input='tmp_1.txt', output='tmp_2.txt'} ) 28 | t( t.readfile(outpath), 'abc' ) 29 | t( t.readfile( 'tmp_2.txt'), 'abc' ) 30 | 31 | os.execute( shellcommand{lua, argdumputiil, 'z', 'w', '-o', append=true, output='tmp_2.txt'} ) 32 | t( t.readfile(outpath), 'zw' ) 33 | t( t.readfile( 'tmp_2.txt'), 'abczw' ) 34 | 35 | os.execute( shellcommand{lua, argdumputiil, '-i', '-e', input='tmp_1.txt', output='tmp_2.txt', error='tmp_3.txt'} ) 36 | t( t.readfile(outpath), 'abc' ) 37 | t( t.readfile( 'tmp_2.txt'), '' ) 38 | t( t.readfile( 'tmp_3.txt'), 'abc' ) 39 | 40 | os.execute( shellcommand{lua, argdumputiil, 'z', 'w', '-e', append=true, output='tmp_2.txt', error='tmp_3.txt'} ) 41 | t( t.readfile(outpath), 'zw' ) 42 | t( t.readfile( 'tmp_2.txt'), '' ) 43 | t( t.readfile( 'tmp_3.txt'), 'abczw' ) 44 | 45 | os.execute( shellcommand{lua, argdumputiil, 'a', 'b', '-o', 'c', 'd', '-e', output='tmp_2.txt', error='tmp_2.txt'} ) 46 | local o = t.readfile('tmp_2.txt') 47 | t( #o, 4 ) 48 | t( o, 'ab', t.patsame ) 49 | t( o, 'cd', t.patsame ) 50 | 51 | t.test_embedded_example() 52 | 53 | t() 54 | 55 | -------------------------------------------------------------------------------- /test/simplepath.ex1.lua: -------------------------------------------------------------------------------- 1 | local simplepath_c = require 'simplepath' 2 | local t = require 'testhelper' 3 | 4 | local sps = function(x) return x:gsub("/", package.config:sub(1,1)) end 5 | local simplepath = function(x) return simplepath_c(sps(x)) end 6 | 7 | t( simplepath'a/b/c./d/e', sps'a/b/c./d/e' ) 8 | t( simplepath'a/b/.c/d/e', sps'a/b/.c/d/e' ) 9 | t( simplepath'a/b./.c/d/e', sps'a/b./.c/d/e' ) 10 | t( simplepath'a/b/c../d/e', sps'a/b/c../d/e' ) 11 | t( simplepath'a/b/..c/d/e', sps'a/b/..c/d/e' ) 12 | t( simplepath'a/b../..c/d/e', sps'a/b../..c/d/e' ) 13 | 14 | t( simplepath'', '.' ) 15 | 16 | t( simplepath'./', sps'.' ) 17 | t( simplepath'./.', sps'.' ) 18 | t( simplepath'././', sps'.' ) 19 | t( simplepath'./././.', sps'.' ) 20 | 21 | t( simplepath'./asd', sps'asd' ) 22 | t( simplepath'./.asd', sps'.asd' ) 23 | t( simplepath'./asd/q', sps'asd/q' ) 24 | 25 | t( simplepath'./asd/.', sps'asd' ) 26 | t( simplepath'./asd/q/.', sps'asd/q' ) 27 | 28 | t( simplepath'/asd/q/./w', sps'/asd/q/w' ) 29 | t( simplepath'/asd/q/./w/./e', sps'/asd/q/w/e' ) 30 | 31 | t( simplepath'././asd', sps'asd' ) 32 | 33 | t( simplepath'../', sps'..' ) 34 | t( simplepath'../asd', sps'../asd' ) 35 | t( simplepath'../asd/q', sps'../asd/q' ) 36 | 37 | t( simplepath'a/b/..', sps'a' ) 38 | t( simplepath'a/b/c/..', sps'a/b' ) 39 | 40 | t( simplepath'a/b/../c', sps'a/c' ) 41 | t( simplepath'a/b/../c/d/..', sps'a/c' ) 42 | 43 | t( simplepath'a/b/c/../../d', sps'a/d' ) 44 | t( simplepath'a/b/c/d/../../../e', sps'a/e' ) 45 | t( simplepath'a/b/c/d/../../..', sps'a' ) 46 | 47 | t( simplepath'../../a/b/c', sps'../../a/b/c' ) 48 | 49 | t( simplepath'./..', sps'..' ) 50 | t( simplepath'../.', sps'..' ) 51 | t( simplepath'././../../a/b/././.././..', sps'../..' ) 52 | 53 | t.test_embedded_example() 54 | 55 | t() 56 | -------------------------------------------------------------------------------- /test/stepdebug.ex1.lua: -------------------------------------------------------------------------------- 1 | local stepdebug = require 'stepdebug' 2 | local t = require 'testhelper' 3 | 4 | -- Test setup 5 | local input='' 6 | local output={} 7 | stepdebug(function() 8 | if input~=nil then 9 | output[1+#output] = stepdebug(input) 10 | end 11 | stepdebug'next' 12 | end) 13 | 14 | stepdebug'break' 15 | input="1" 16 | input='continue' 17 | 18 | t( #output, 1 ) 19 | t( output[1], 1 ) 20 | 21 | output, input = {}, nil 22 | 23 | stepdebug'break' 24 | input="return 2" 25 | input='continue' 26 | 27 | t( #output, 1 ) 28 | t( output[1], 2 ) 29 | 30 | output, input = {}, nil 31 | 32 | input='break' 33 | input='1' 34 | input='2' 35 | stepdebug'break' 36 | input='3' 37 | input='4' 38 | input='continue' 39 | input='5' 40 | input='6' 41 | 42 | t( #output, 3 ) 43 | t( output[1], 2 ) 44 | t( output[2], 3 ) 45 | t( output[3], 4 ) 46 | 47 | output, input = {}, nil 48 | 49 | stepdebug'break' 50 | input='1' 51 | input='2' 52 | ;(function() 53 | input='3' 54 | input='4' 55 | end)() 56 | input='5' 57 | input='6' 58 | input='continue' 59 | 60 | t( #output, 6 ) 61 | t( output[1], 1 ) 62 | t( output[2], 2 ) 63 | t( output[3], 2 ) 64 | t( output[4], 4 ) 65 | t( output[5], 5 ) 66 | t( output[6], 6 ) 67 | 68 | output, input = {}, nil 69 | 70 | stepdebug'break' 71 | input='step' 72 | input='1' 73 | input='2' 74 | ;(function() 75 | input='3' 76 | input='4' 77 | ;(function() 78 | input='5' 79 | input='6' 80 | end)() 81 | input='7' 82 | input='8' 83 | end)() 84 | input='9' 85 | input='10' 86 | input='continue' 87 | 88 | t( #output, 13 ) 89 | t( output[1], 1 ) 90 | t( output[2], 2 ) 91 | t( output[3], 2 ) 92 | t( output[4], 2 ) 93 | t( output[5], 3 ) 94 | t( output[6], 4 ) 95 | t( output[7], 4 ) 96 | t( output[8], 6 ) 97 | t( output[9], 7 ) 98 | t( output[10], 8 ) 99 | t( output[11], 8 ) 100 | t( output[12], 9 ) 101 | t( output[13], 10 ) 102 | 103 | output, input = {}, nil 104 | 105 | stepdebug'break' 106 | input='step' 107 | input='1' 108 | input='2' 109 | ;(function() 110 | input='3' 111 | input='4' 112 | end)() 113 | input='5' 114 | input='6' 115 | ;(function() 116 | input='7' 117 | input='8' 118 | end)() 119 | input='9' 120 | input='10' 121 | input='continue' 122 | 123 | t( #output, 13 ) 124 | t( output[1], 1 ) 125 | t( output[2], 2 ) 126 | t( output[3], 2 ) 127 | t( output[4], 2 ) 128 | t( output[5], 3 ) 129 | t( output[6], 4 ) 130 | t( output[7], 4 ) 131 | t( output[8], 5 ) 132 | t( output[9], 6 ) 133 | t( output[10], 6 ) 134 | t( output[11], 8 ) 135 | t( output[12], 9 ) 136 | t( output[13], 10 ) 137 | 138 | output, input = {}, nil 139 | 140 | stepdebug'break' 141 | input='step' 142 | input='1' 143 | input='2' 144 | ;(function() 145 | input='3' 146 | input='4' 147 | input='finish' 148 | input='5' 149 | input='6' 150 | input='7' 151 | end)() 152 | input='8' 153 | input='9' 154 | input='continue' 155 | 156 | t( #output, 9 ) 157 | t( output[1], 1 ) 158 | t( output[2], 2 ) 159 | t( output[3], 2 ) 160 | t( output[4], 2 ) 161 | t( output[5], 3 ) 162 | t( output[6], 4 ) 163 | t( output[7], 7 ) 164 | t( output[8], 8 ) 165 | t( output[9], 9 ) 166 | 167 | output, input = {}, nil 168 | 169 | function gupnam() -- must be global 170 | return debug.getinfo(6).name or '' 171 | end 172 | 173 | stepdebug'break' 174 | input='step' 175 | input='gupnam()' 176 | function NL() 177 | input='gupnam()' 178 | end 179 | NL() 180 | input='gupnam()' 181 | input='continue' 182 | 183 | t( #output, 7 ) 184 | t( output[4], 'NL' ) 185 | t( output[5], 'NL' ) 186 | 187 | t() 188 | 189 | -------------------------------------------------------------------------------- /test/subbytebase.ex1.lua: -------------------------------------------------------------------------------- 1 | local subbytebase = require 'subbytebase' 2 | local t = require 'testhelper' 3 | 4 | t( subbytebase(6,'' ) , '' , t.bytesame ) 5 | t( subbytebase(6,'a' ) , 'YQ==' , t.bytesame ) 6 | t( subbytebase(6,'aa' ) , 'YWE=' , t.bytesame ) 7 | t( subbytebase(6,'aaa' ) , 'YWFh' , t.bytesame ) 8 | t( subbytebase(6,'aaaa' ) , 'YWFhYQ==' , t.bytesame ) 9 | t( subbytebase(6,'aaaaa' ) , 'YWFhYWE=' , t.bytesame ) 10 | t( subbytebase(6,'aaaaaa' ) , 'YWFhYWFh' , t.bytesame ) 11 | 12 | t( subbytebase(-6, '' ) , '' , t.bytesame ) 13 | t( subbytebase(-6, 'YQ==' ) , 'a' , t.bytesame ) 14 | t( subbytebase(-6, 'YWE=' ) , 'aa' , t.bytesame ) 15 | t( subbytebase(-6, 'YWFh' ) , 'aaa' , t.bytesame ) 16 | t( subbytebase(-6, 'YWFhYQ==') , 'aaaa' , t.bytesame ) 17 | t( subbytebase(-6, 'YWFhYWE=') , 'aaaaa' , t.bytesame ) 18 | t( subbytebase(-6, 'YWFhYWFh') , 'aaaaaa' , t.bytesame ) 19 | 20 | t( subbytebase(1, 'hi' ), '0110100001101001', t.bytesame ) 21 | t( subbytebase(-1, '0110100001101001' ), 'hi', t.bytesame ) 22 | 23 | t( subbytebase(2, 'hi' ), '12201221', t.bytesame ) 24 | t( subbytebase(-2, '12201221' ), 'hi', t.bytesame ) 25 | 26 | t( subbytebase(3, 'hi' ), '320644=', t.bytesame ) 27 | t( subbytebase(-3, '320644=' ), 'hi', t.bytesame ) 28 | 29 | t( subbytebase(4, 'hi' ), '6869', t.bytesame ) 30 | t( subbytebase(-4, '6869' ), 'hi', t.bytesame ) 31 | 32 | t( subbytebase(5, 'hi' ), 'D1MG===', t.bytesame ) 33 | t( subbytebase(-5, 'D1MG===' ), 'hi', t.bytesame ) 34 | 35 | t( subbytebase(6, 'hi' ), 'aGk=', t.bytesame ) 36 | t( subbytebase(-6, 'aGk=' ), 'hi', t.bytesame ) 37 | 38 | t( subbytebase(7, '\xFF' ), '\x7F\x40======', t.bytesame ) 39 | t( subbytebase(-7, '\x7F\x40======' ), '\xFF', t.bytesame ) 40 | 41 | t( subbytebase(8, 'hi' ), 'hi', t.bytesame ) 42 | t( subbytebase(-8, 'hi' ), 'hi', t.bytesame ) 43 | 44 | t.test_embedded_example() 45 | 46 | t() 47 | 48 | -------------------------------------------------------------------------------- /test/tapfail.ex1.lua: -------------------------------------------------------------------------------- 1 | local tapfail = require 'tapfail' 2 | local t = require 'testhelper' 3 | 4 | local ts = tapfail() 5 | t( type(ts), 'function' ) 6 | t( ts'', nil ) 7 | 8 | local ts = tapfail() 9 | t( type(ts), 'function' ) 10 | t( ts'not ok', 'no diagnostic or ok line' ) 11 | 12 | local ts = tapfail() 13 | t( type(ts), 'function' ) 14 | t( ts'ok 1', nil ) 15 | t( ts'1..1', nil ) 16 | t( ts(), nil ) 17 | 18 | local ts = tapfail() 19 | t( type(ts), 'function' ) 20 | t( ts'ok 1', nil ) 21 | t( ts'ok 2', nil ) 22 | t( ts'1..2', nil ) 23 | 24 | local ts = tapfail() 25 | t( type(ts), 'function' ) 26 | t( ts'ok 1', nil ) 27 | t( ts'#not ok masked by diagnostic', nil ) 28 | t( ts'1..1', nil ) 29 | 30 | local ts = tapfail() 31 | t( type(ts), 'function' ) 32 | t( ts'ok 2', 'invalid count sequence' ) 33 | t( ts'ok 1', 'invalid count sequence' ) 34 | 35 | local ts = tapfail() 36 | t( type(ts), 'function' ) 37 | t( ts'ok 1', nil ) 38 | t( ts'ok 3', 'invalid count sequence' ) 39 | t( ts'ok 2', 'invalid count sequence' ) 40 | 41 | local ts = tapfail() 42 | t( type(ts), 'function' ) 43 | t( ts'ok 1', nil ) 44 | t( ts'1..2', 'invalid test count' ) 45 | 46 | local ts = tapfail() 47 | t( type(ts), 'function' ) 48 | t( ts'ok 1', nil ) 49 | t( ts'not ok', 'no diagnostic or ok line' ) 50 | t( ts'1..2', 'invalid test count' ) 51 | 52 | local ts = tapfail() 53 | t( type(ts), 'function' ) 54 | t( ts'ok 1', nil ) 55 | t( ts'not ok', 'no diagnostic or ok line' ) 56 | t( ts'1..1', nil ) 57 | 58 | local ts = tapfail() 59 | t( type(ts), 'function' ) 60 | t( ts'ok 1', nil ) 61 | t( ts(), 'summary missing' ) 62 | 63 | local ts = tapfail() 64 | t( type(ts), 'function' ) 65 | t( ts'ok 1', nil ) 66 | t( ts'1..1', nil ) 67 | t( ts'ok 2', 'line after summary' ) 68 | 69 | local ts = tapfail() 70 | t( type(ts), 'function' ) 71 | t( ts'ok 1', nil ) 72 | t( ts'1..2', 'invalid test count' ) 73 | t( ts'ok 2', 'line after summary' ) 74 | 75 | local ts = tapfail() 76 | t( type(ts), 'function' ) 77 | t( ts'ok 1', nil ) 78 | t( ts'ok 2', nil ) 79 | t( ts'ok 3', nil ) 80 | t( ts'1..N', nil ) 81 | t( ts(), nil ) 82 | 83 | local ts = tapfail() 84 | t( type(ts), 'function' ) 85 | t( ts'1..3', nil ) 86 | t( ts'ok 1', nil ) 87 | t( ts'ok 2', nil ) 88 | t( ts'ok 3', nil ) 89 | t( ts(), nil ) 90 | 91 | local ts = tapfail() 92 | t( type(ts), 'function' ) 93 | t( ts'1..2', nil ) 94 | t( ts'ok 1', nil ) 95 | t( ts'ok 2', nil ) 96 | t( ts'ok 3', 'invalid count sequence' ) 97 | 98 | local ts = tapfail() 99 | t( type(ts), 'function' ) 100 | t( ts'1..N', nil ) 101 | t( ts'ok 1', nil ) 102 | t( ts'ok 2', nil ) 103 | t( ts'ok 3', nil ) 104 | t( ts(), nil ) 105 | 106 | local ts = tapfail() 107 | t( type(ts), 'function' ) 108 | t( ts'1..3', nil ) 109 | t( ts'ok 1', nil ) 110 | t( ts'ok 2', nil ) 111 | t( ts(), 'missing test' ) 112 | 113 | local ts = tapfail() 114 | t( type(ts), 'function' ) 115 | t( ts'1..N', nil ) 116 | t( ts'ok 1', nil ) 117 | t( ts'ok 2', nil ) 118 | t( ts'ok 3', nil ) 119 | t( ts'1..N', 'summary already found at line 1' ) 120 | 121 | local ts = tapfail() 122 | t( type(ts), 'function' ) 123 | t( ts'1..N', nil ) 124 | t( ts'ok 1', nil ) 125 | t( ts'ok 2', nil ) 126 | t( ts'1..N', 'summary already found at line 1' ) 127 | t( ts'ok 3', nil ) 128 | 129 | t.test_embedded_example() 130 | 131 | t() 132 | -------------------------------------------------------------------------------- /test/taptest.ex1.lua: -------------------------------------------------------------------------------- 1 | local taptest = require "taptest" 2 | local t = require "testhelper" 3 | -- taptest is both the "Unit under test" (taptest) and the "Test framework" (t - testhelper) 4 | 5 | -- To avoid confusion (as much as it is possible) t will be always used in its 6 | -- easest form: it just checks that the two argument are equals. 7 | -- Since taptest always returns what it print on stdout, the returned 8 | -- value of taptest is checked 9 | 10 | -- wrap the taptest to simplify line number checks 11 | local fake_test_count = 1 12 | local taptest_wrapped = taptest 13 | local function taptest( ... ) 14 | fake_test_count = fake_test_count + 2 15 | local result = taptest_wrapped( ... ) 16 | return result -- avoid tail call 17 | end 18 | 19 | t( taptest( 1, 1 ), "ok 1" ) 20 | t( taptest( 1, 1 ), "ok 2" ) 21 | 22 | -- Additional infos when the test fails 23 | t( taptest( 1, 2 ), 24 | "not ok 3 - taptest.ex1.lua:15. Mismatch: [1] VS [2]. " ) 25 | 26 | -- Custom infos on fail 27 | t( taptest( 1, 2, "Not good!" ), 28 | "not ok 4 - taptest.ex1.lua:15. Mismatch: [1] VS [2]. Not good!" ) 29 | 30 | -- Custom compare function 31 | t( taptest( 1, 2, function( a, b ) return a < b end ), 32 | "ok 5" ) 33 | t( taptest( 2, 1, function( a, b ) return a < b end ), 34 | "not ok 6 - taptest.ex1.lua:15. Mismatch: [2] VS [1]. " ) 35 | 36 | -- Custom compare function and message 37 | t( taptest( 1, 1, function( a, b ) return a ~= b end, "Not good!" ), 38 | "not ok 7 - taptest.ex1.lua:15. Mismatch: [1] VS [1]. Not good!" ) 39 | t( taptest( 1, 1, "Not good!", function( a, b ) return a ~= b end ), 40 | "not ok 8 - taptest.ex1.lua:15. Mismatch: [1] VS [1]. Not good!" ) 41 | 42 | -- Single argument = Tap diagnostic 43 | t( taptest( "new\nsuite" ), "# new\n# suite" ) 44 | 45 | -- Checker function can add useful information 46 | t( taptest( 1, 1, function( a, b ) return a == b, "- additional info" end ), 47 | "ok 9 - additional info" ) 48 | 49 | t( taptest( 1, 2, function( a, b ) return a == b, "- additional info" end ), 50 | "not ok 10 - taptest.ex1.lua:15. - additional info" ) 51 | 52 | -- No argument = Summary and final plan 53 | t( taptest(), "# \n# 6 tests failed\n# \n1..10" ) 54 | 55 | local function taptest_masked(...) 56 | local taptest_blame_caller = true 57 | r = taptest_wrapped(...) 58 | return r -- no tail call 59 | end 60 | 61 | t( taptest_masked( 1, 2 ), "not ok 11 - taptest.ex1.lua:61. Mismatch: [1] VS [2]. " ) 62 | 63 | t( taptest( nil, nil ), "ok 12" ) 64 | t( taptest( nil, true, function(a,b) return a~=b end ), "ok 13" ) 65 | t( taptest( true, nil, function(a,b) return a~=b end ), "ok 14" ) 66 | 67 | t.test_embedded_example() 68 | 69 | t() 70 | 71 | -- In case all the tests are successful, the line 72 | -- # all is right 73 | -- will be substitued to the '# 5 tests failed' one 74 | -------------------------------------------------------------------------------- /test/templua.ex1.lua: -------------------------------------------------------------------------------- 1 | local templua = require( "templua" ) 2 | local t = require 'testhelper' 3 | 4 | -- Blank templates are not touched 5 | local m = templua( "ok" ) 6 | t( 'ok', m{} ) 7 | 8 | -- Lua expression expansion with @{} 9 | m = templua( "@{item.a} @{item.b:upper()}" ) 10 | t( 'a B', m{ item = { a = 'a', b = 'b' } } ) 11 | m = templua( "@{item.a} @{item.b:upper()}" ) 12 | t( 'B A', m{ item = { a = 'B', b = 'a' } } ) 13 | 14 | -- Call same template multiple times 15 | m = templua( "@{x}" ) 16 | t( '1', m{ x=1 } ) 17 | t( '2', m{ x=2 } ) 18 | 19 | -- Mix lua statements and text with @{{}} 20 | m = templua( "@{{for i=1,3 do}} hello @{item}!@{{end}}" ) 21 | t( ' hello world! hello world! hello world!', m{ item = 'world' } ) 22 | 23 | -- Use the output function to expand text from complex lua code 24 | m = templua( "@{{for i=1,3 do out(' hello '..item..'!') end}}" ) 25 | t( ' hello dude! hello dude! hello dude!', m{ item = 'dude' } ) 26 | 27 | -- Statement that do not cover all the string 28 | m = templua( "hello @{{a=1}} world" ) 29 | t( 'hello world', m{} ) 30 | 31 | -- Last text appending 32 | m = templua( "@{'true'} ok" ) 33 | t( 'true ok', m{} ) 34 | 35 | -- Value cast in the output function 36 | m = templua( "@{true} ok" ) 37 | t( 'true ok', m{} ) 38 | 39 | -- Compile error is found 40 | local m, e = templua( "@{{][}}" ) 41 | t( m, nil ) 42 | t( e, 'string "templua_script"%]:1: unexpected symbol', t.patsame ) 43 | 44 | -- Error while expanding 45 | m = templua( "@{{undefined_function()}}" ) 46 | local s, e = m{} 47 | t( s, nil ) 48 | t( e, 'string "templua_script"%]:1: attempt to call a nil value', t.patsame ) 49 | 50 | -- Ignoring @ between templates 51 | m = templua( "@{x} @ @{x}" ) 52 | t( 'y @ y', m{ x='y' } ) 53 | 54 | -- Nested template 55 | local s = {} 56 | function s.nestcall() 57 | return templua( "@{'B'}" )( s ) 58 | end 59 | t( templua( "@{nestcall()}@{nestcall()}" )( s ), 'BB' ) 60 | 61 | t.test_embedded_example() 62 | 63 | t() 64 | 65 | -------------------------------------------------------------------------------- /test/timeprof.ex1.lua: -------------------------------------------------------------------------------- 1 | local timeprof = require 'timeprof' 2 | local t = require 'testhelper' 3 | 4 | local e02, e002 = t.number_tollerance(0.02), t.number_tollerance(0.002) 5 | local a, b, c, f, m, s 6 | 7 | -- Get timers, same are returned if same argument is passed (except nil) 8 | 9 | a = timeprof'a' 10 | t( a, timeprof'a' ) 11 | b = timeprof'b' 12 | c = timeprof() 13 | t( b, a, t.diff ) 14 | t( b, c, t.diff ) 15 | t( a, c, t.diff ) 16 | 17 | -- Timer Api 18 | 19 | a = timeprof() 20 | 21 | t( a:start(), nil ) 22 | t( a:stop(), nil ) 23 | t( a:reset(), nil ) 24 | 25 | -- Single time measurement 26 | 27 | a = timeprof() 28 | f, m, s = a:summary() 29 | 30 | t( f, 0 ) 31 | t( m, 0 ) 32 | t( s, 0 ) 33 | 34 | a:start() 35 | t.wait(0.2) 36 | a:stop() 37 | f, m, s = a:summary() 38 | 39 | t( f, 0.2, e02 ) 40 | t( m, 0.2, e02 ) 41 | t( s, 0, e02 ) 42 | 43 | t.wait(0.1) 44 | 45 | -- Adding two time measurement 46 | 47 | a:start() 48 | t.wait(0.1) 49 | a:stop() 50 | f, m, s = a:summary() 51 | 52 | t( f, 0.3, e02 ) 53 | t( m, 0.15, e02 ) 54 | t( s, 0.0707, e002 ) 55 | 56 | a:start() 57 | t.wait(0.3) 58 | a:stop() 59 | f, m, s = a:summary() 60 | 61 | t( f, 0.6, e02 ) 62 | t( m, 0.2, e02 ) 63 | t( s, 0.1, e002 ) 64 | 65 | -- Resetting measurements 66 | 67 | a:reset() 68 | f, m, s = a:summary() 69 | 70 | t( f, 0 ) 71 | t( m, 0 ) 72 | t( s, 0 ) 73 | 74 | a:start() 75 | t.wait(0.01) 76 | a:stop() 77 | f, m, s = a:summary() 78 | 79 | t( f, 0.01, e002 ) 80 | t( m, 0.01, e002 ) 81 | t( s, 0 ) 82 | 83 | -- Multiple timers 84 | 85 | a = timeprof() 86 | b = timeprof() 87 | 88 | a:start() 89 | t.wait(0.01) 90 | b:start() 91 | t.wait(0.02) 92 | a:stop() 93 | b:stop() 94 | f, m, s = a:summary() 95 | 96 | t( f, 0.03, e002 ) 97 | t( m, 0.03, e002 ) 98 | t( s, 0 ) 99 | 100 | f, m, s = b:summary() 101 | 102 | t( f, 0.02, e002 ) 103 | t( m, 0.02, e002 ) 104 | t( s, 0 ) 105 | 106 | t() 107 | 108 | -------------------------------------------------------------------------------- /test/toposort.ex1.lua: -------------------------------------------------------------------------------- 1 | local toposort = require 'toposort' 2 | local t = require 'testhelper' 3 | 4 | t( toposort(), {}, t.deepsame ) 5 | 6 | t( toposort{a={'b'}}, {'b','a'}, t.deepsame ) 7 | 8 | t( toposort{a={'b','c'}}, {'b','a'}, t.itemorder ) 9 | t( toposort{a={'b','c'}}, {'c','a'}, t.itemorder ) 10 | 11 | t( toposort{a={'b'},b={'c'}}, {'b','a'}, t.itemorder ) 12 | t( toposort{a={'b'},b={'c'}}, {'c','b'}, t.itemorder ) 13 | 14 | t( toposort{a={'b','c'},b={'d'}}, {'b','a'}, t.itemorder ) 15 | t( toposort{a={'b','c'},b={'d'}}, {'c','a'}, t.itemorder ) 16 | t( toposort{a={'b','c'},b={'d'}}, {'d','b'}, t.itemorder ) 17 | 18 | t( toposort{a={'b','c'},c={'b'}}, {'b','a'}, t.itemorder ) 19 | t( toposort{a={'b','c'},c={'b'}}, {'c','a'}, t.itemorder ) 20 | t( toposort{a={'b','c'},c={'b'}}, {'b','c'}, t.itemorder ) 21 | 22 | t( toposort{a={'c','b'},b={'d'}}, {'c','a'}, t.itemorder ) 23 | t( toposort{a={'c','b'},b={'d'}}, {'b','a'}, t.itemorder ) 24 | t( toposort{a={'c','b'},b={'d'}}, {'d','b'}, t.itemorder ) 25 | 26 | t( toposort{a={'b','c'},d={'b','c'},e={'f','g'}}, {'b','a'}, t.itemorder ) 27 | t( toposort{a={'b','c'},d={'b','c'},e={'f','g'}}, {'c','a'}, t.itemorder ) 28 | t( toposort{a={'b','c'},d={'b','c'},e={'f','g'}}, {'b','d'}, t.itemorder ) 29 | t( toposort{a={'b','c'},d={'b','c'},e={'f','g'}}, {'c','d'}, t.itemorder ) 30 | t( toposort{a={'b','c'},d={'b','c'},e={'f','g'}}, {'f','e'}, t.itemorder ) 31 | t( toposort{a={'b','c'},d={'b','c'},e={'f','g'}}, {'g','e'}, t.itemorder ) 32 | 33 | local _, err = toposort{a={'b'},b={'a'}} 34 | t( err, 'cycle detected' ) 35 | 36 | t.test_embedded_example() 37 | 38 | t() 39 | 40 | -------------------------------------------------------------------------------- /test/trimstring.ex1.lua: -------------------------------------------------------------------------------- 1 | local trimstring = require 'trimstring' 2 | local t = require 'testhelper' 3 | 4 | t( trimstring(''), '' ) 5 | t( trimstring('a'), 'a' ) 6 | 7 | t( trimstring(' a'), 'a' ) 8 | t( trimstring('a '), 'a' ) 9 | t( trimstring(' a '), 'a' ) 10 | 11 | t( trimstring(' a a'), 'a a' ) 12 | t( trimstring('a a '), 'a a' ) 13 | t( trimstring(' a a '), 'a a' ) 14 | 15 | t( trimstring(' \nstr\r\t '), 'str' ) 16 | 17 | t.test_embedded_example() 18 | 19 | t() 20 | -------------------------------------------------------------------------------- /test/tuple.ex1.lua: -------------------------------------------------------------------------------- 1 | local tuple = require 'tuple' 2 | local t = require 'testhelper' 3 | 4 | -- Equality operation 5 | t( type(tuple(1,'a',true,3)), 'table' ) 6 | t( tuple(1,'a',true,3), tuple(1,'a',true,3) ) 7 | 8 | -- Read fields 9 | local field = tuple(1,'a',true,3) 10 | t( field.n, 4 ) 11 | t( field[1], 1 ) 12 | t( field[2], 'a' ) 13 | t( field[3], true ) 14 | t( field[4], 3 ) 15 | 16 | -- Store nil and NaN 17 | field = tuple(1,nil,0/0,3) 18 | t( field.n, 4 ) 19 | t( field[1], 1 ) 20 | t( field[2], nil ) 21 | t( field[3], field[3], t.diff ) 22 | t( field[4], 3 ) 23 | 24 | -- Can not change field 25 | local a, b = pcall(function() tuple( 1, nil, 0/0, 3 )[1] = 2 end) 26 | t( a, false ) 27 | t( b:match( 'can not change tuple field' ), 'can not change tuple field' ) 28 | 29 | -- Garbage collection test 30 | 31 | local gccount = 0 32 | local x = tuple(2,nil,0/0,4) 33 | x = setmetatable( x, {__gc=function(t) gccount = gccount + 1 end} ) 34 | 35 | -- No collection if some reference is still around 36 | collectgarbage('collect') 37 | t( gccount, 0 ) 38 | 39 | -- Automatic collection 40 | x = nil 41 | collectgarbage('collect') 42 | t( gccount, 1 ) 43 | 44 | t.test_embedded_example() 45 | 46 | t() 47 | 48 | -------------------------------------------------------------------------------- /test/uniontab.ex1.lua: -------------------------------------------------------------------------------- 1 | local uniontab = require 'uniontab' 2 | local t = require 'testhelper' 3 | 4 | t( uniontab(), {}, t.deepsame ) 5 | t( uniontab({}), {}, t.deepsame ) 6 | t( uniontab({},{}), {}, t.deepsame ) 7 | 8 | t( uniontab({a='a'}), {a='a'}, t.deepsame ) 9 | t( uniontab({},{a='a'}), {a='a'}, t.deepsame ) 10 | 11 | t( uniontab({a='a'},{b='b'}), {a='a',b='b'}, t.deepsame ) 12 | t( uniontab({a='a'},{a='b'}), {a='a'}, t.deepsame ) 13 | 14 | t( uniontab({a='a'},{a='b'},function(a,b) return a..b end), {a='ab'}, t.deepsame ) 15 | 16 | t( uniontab({a='a',b='b',c='c'},{a='A',d='d'}), {a='a',b='b',c='c',d='d'}, t.deepsame ) 17 | 18 | t.test_embedded_example() 19 | 20 | t() 21 | -------------------------------------------------------------------------------- /test/valueprint.ex1.lua: -------------------------------------------------------------------------------- 1 | local valueprint = require "valueprint" 2 | local t = require "testhelper" 3 | 4 | t( valueprint(1), '1' ) 5 | t( valueprint(true), 'true' ) 6 | t( valueprint("hi"), '"hi"' ) 7 | t( valueprint({}), '^table 0?x?%x*$', t.patsame ) 8 | t( valueprint(nil), 'nil' ) 9 | 10 | t( valueprint({1,2}), '^table 0?x?%x*\n| 1: 1\n| 2: 2$' , t.patsame ) 11 | t( valueprint({a="b",c="d"}), '^table 0?x?%x*\n.*| "a": "b"' , t.patsame ) 12 | t( valueprint({a="b",c="d"}), '^table 0?x?%x*\n.*| "c": "d"' , t.patsame ) 13 | t( valueprint({a={b="c"}}), '^table 0?x?%x*\n| "a": table 0?x?%x*\n| | "b": "c"$' , t.patsame ) 14 | 15 | local at = {} 16 | at[1] = {} 17 | at[1][1] = at[1] 18 | at[1][at[1]]=true 19 | local r = tostring(at):gsub(':','') 20 | local r1 = tostring(at[1]):gsub(':','') 21 | 22 | local v = valueprint( at ) 23 | t( v, '^' 24 | .."table 0?x?%x*\n" 25 | .."| 1: (table 0?x?%x*)\n" 26 | .."| | 1: %1 content is not shown here\n" 27 | .."| | %1 content is not shown here: true" 28 | ..'$', t.patsame ) 29 | 30 | local function p(k,v,d,i) 31 | local y = '<'..(k or 'nil')..'|'..v..'|'..d..'|'..i..'>' 32 | x = x..y 33 | return y 34 | end 35 | 36 | x = '' 37 | local v = valueprint({101,102,{b="c"},true,x=nil}, p) 38 | t( v, x ) 39 | 40 | t( v, '^' 41 | ..'' 42 | ..'<1|101|1|number>' 43 | ..'<2|102|1|number>' 44 | ..'<3|(table 0?x?%x*)|1|table>' 45 | ..'' 46 | ..'<"b"|"c"|2|string>' 47 | ..'' 48 | ..'<4|true|1|boolean>' 49 | ..'' 50 | ..'$', t.patsame ) 51 | 52 | t.test_embedded_example() 53 | 54 | t() 55 | 56 | -------------------------------------------------------------------------------- /tool/debugger_stdinout.lua: -------------------------------------------------------------------------------- 1 | --[===[DOC 2 | 3 | = Command line debugger 4 | 5 | The 'debugger_stdinout' module provide a full command line debugger for lua. It 6 | is based on 'stepdebug' module of Luasnip. It install a step-debug handler that 7 | read from the standard input and passes the line to 'stepdebug', so you can 8 | refer to <> documentation for a list of accepted commands. 9 | 10 | As described in the <> documentataion, it does not support classical 11 | breakpoint through filename and line number, but the execution can be 12 | explicitally stopped in the debugged source code with somethig like 13 | 14 | ``` 15 | LD = require 'debug_stdinout' ; LD"break" 16 | ``` 17 | 18 | Moreover the 'localbind' module of Luasnip is exposed in the 'L' global, so you 19 | can access locals and upvalues of the current executed line with simple 20 | expressions like `print(L.a_local_variable)`. Values can be changed with the 21 | intuitive syntax `L.a_local_variable = "New value"`. Also deeper stack 22 | inspections are possible with expressions like 23 | `print(L(1).a_caller_local_variable)`. 24 | 25 | No command line history or completion is supported. 26 | 27 | ]===] 28 | 29 | local ls = require 'luasnip' 30 | local stepdebug = ls.stepdebug 31 | local localbind = ls.localbind 32 | 33 | do 34 | 35 | local cachesource = {} 36 | 37 | function getsource( level, pre, post ) 38 | if not level then level = 1 end 39 | local info = debug.getinfo( level ) 40 | if not info then return nil, 'Invalid level' end 41 | local cur = info.currentline 42 | local fil = info.short_src 43 | local path = info.source 44 | path = path:sub(2) 45 | local s = cachesource[ path ] 46 | if not s then 47 | local f = io.open( path, 'r' ) 48 | if not f then error() end 49 | s = {} 50 | while true do 51 | local line = f:read('l') 52 | if not line then break end 53 | s[1+#s] = line 54 | end 55 | f:close() 56 | cachesource[ path ] = s 57 | end 58 | local result = {} 59 | if not pre then pre = 1 end 60 | if not post then post = #s end 61 | if post < 0 then post = #s +1 -post end 62 | for l = cur-pre, cur+post do 63 | result[1+#result] = s[l] 64 | end 65 | return result, fil, cur 66 | end 67 | end 68 | 69 | stepdebug(function(b,e) 70 | L = localbind(b) -- global table to access local variables 71 | local pre, post = 5, 5 72 | local src, fil, lnn = getsource(b+1, pre, post) 73 | print('> '..b..' @ '..fil..' : '..lnn) 74 | print('+---------------------') 75 | for i, s in ipairs(src) do 76 | if i == pre+1 then 77 | print('> '..s) 78 | else 79 | print('| '..s) 80 | end 81 | end 82 | print('+---------------------') 83 | io.write('> ') io.flush() 84 | print(stepdebug(io.read("*l"))) 85 | end) 86 | 87 | --------------------------------------------------------------------------------