Write more redbean unit tests

- Fix DescribeSigset()
- Introduce new unix.rmrf() API
- Fix redbean sigaction() doc example code
- Fix unix.sigaction() w/ more than two args
- Improve redbean re module API (non-breaking)
- Enhance Lua with Python string multiplication
- Make third parameter of unix.socket() default to 0
This commit is contained in:
Justine Tunney 2022-07-08 23:06:46 -07:00
parent c5b9902ac9
commit 1c83670229
20 changed files with 738 additions and 204 deletions

View file

@ -0,0 +1,38 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/sigset.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/sig.h"
#include "libc/testlib/testlib.h"
TEST(DescribeSigset, present) {
sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGINT);
sigaddset(&ss, SIGUSR1);
EXPECT_STREQ("{INT,USR1}", DescribeSigset(0, &ss));
}
TEST(DescribeSigset, absent) {
sigset_t ss;
sigfillset(&ss);
sigdelset(&ss, SIGINT);
sigdelset(&ss, SIGUSR1);
EXPECT_STREQ("~{INT,USR1}", DescribeSigset(0, &ss));
}

View file

@ -0,0 +1,28 @@
-- Copyright 2022 Justine Alexandra Roberts Tunney
--
-- Permission to use, copy, modify, and/or distribute this software for
-- any purpose with or without fee is hereby granted, provided that the
-- above copyright notice and this permission notice appear in all copies.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
-- WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
-- WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
-- AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
-- DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
-- PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-- PERFORMANCE OF THIS SOFTWARE.
assert(assert(argon2.hash_encoded("password", "somesalt", {
variant = argon2.variants.argon2_i,
m_cost = 65536,
hash_len = 24,
parallelism = 4,
t_cost = 2,
})) ==
"$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG")
assert(argon2.verify(
"$argon2i$v=19$m=65536,t=2," ..
"p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG",
"password"))

View file

@ -17,6 +17,9 @@ x = Rdtsc()
y = Rdtsc()
assert(y > x)
assert(Rdrand() ~= Rdrand())
assert(Rdseed() ~= Rdseed())
assert(Bsr(1) == 0)
assert(Bsr(2) == 1)
assert(Bsr(3) == 1)
@ -29,22 +32,54 @@ assert(Bsf(3) == 0)
assert(Bsf(4) == 2)
assert(Bsf(0x80000001) == 0)
assert(Popcnt(0) == 0)
assert(Popcnt(1) == 1)
assert(Popcnt(2) == 1)
assert(Popcnt(3) == 2)
assert(Popcnt(0b0111101001101001) == 9)
assert(Lemur64() == 0x1940efe9d47ae889)
assert(Lemur64() == 0xd4b3103f567f9974)
assert(hex(0x1940efe9d47ae889) == "0x1940efe9d47ae889")
assert(oct(0x1940efe9d47ae889) == "0145007376472436564211")
assert(bin(0x1940efe9d47ae889) == "0b0001100101000000111011111110100111010100011110101110100010001001")
assert(EscapeHtml("?hello&there<>") == "?hello&amp;there&lt;&gt;")
assert(EscapeParam("?hello&there<>") == "%3Fhello%26there%3C%3E")
assert(DecodeLatin1("hello\xff\xc0") == "helloÿÀ")
assert(EncodeLatin1("helloÿÀ") == "hello\xff\xc0")
assert(EncodeLua(nil) == "nil")
assert(EncodeLua(0) == "0")
assert(EncodeLua(3.14) == "3.14")
assert(EncodeLua({1, 2}) == "{1, 2}")
x = {1, 2}
x[3] = x
assert(string.match(EncodeLua(x), "{1, 2, \"cyclic@0x%x+\"}"))
-- TODO(jart): EncodeLua() should sort tables
-- x = {}
-- x.c = 'c'
-- x.a = 'a'
-- x.b = 'b'
-- assert(EncodeLua(x) == '{a="a", b="b", c="c"}')
assert(EncodeJson(nil) == "null")
assert(EncodeJson(0) == "0")
assert(EncodeJson(3.14) == "3.14")
assert(EncodeJson({1, 2}) == "[1,2]")
assert(hex(0x1940efe9d47ae889) == "0x1940efe9d47ae889")
assert(oct(0x1940efe9d47ae889) == "0145007376472436564211")
assert(bin(0x1940efe9d47ae889) == "0b0001100101000000111011111110100111010100011110101110100010001001")
url = ParseUrl("https://jart:pass@redbean.dev/2.0.html?x&y=z#frag")
assert(url.scheme == "https")
assert(url.user == "jart")
assert(url.pass == "pass")
assert(url.host == "redbean.dev")
assert(not url.port)
assert(url.path == "/2.0.html")
assert(EncodeLua(url.params) == '{{"x"}, {"y", "z"}}')
assert(url.fragment == "frag")
assert(DecodeBase64("abcdefgABCDE") == "\x69\xb7\x1d\x79\xf8\x00\x04\x20\xc4")
assert(EncodeBase64("\x69\xb7\x1d\x79\xf8\x00\x04\x20\xc4") == "abcdefgABCDE")
@ -82,6 +117,7 @@ assert(IndentLines("hi\nthere\n") == " hi\n there\n")
assert(IndentLines("hi\nthere\n", 2) == " hi\n there\n")
assert(ParseHttpDateTime("Fri, 08 Jul 2022 16:17:43 GMT") == 1657297063)
assert(FormatHttpDateTime(1657297063) == "Fri, 08 Jul 2022 16:17:43 GMT")
assert(VisualizeControlCodes("hello\x00") == "hello␀")
@ -97,8 +133,8 @@ assert(Sha256("hello") == "\x2c\xf2\x4d\xba\x5f\xb0\xa3\x0e\x26\xe8\x3b\x2a\xc5\
assert(Sha384("hello") == "\x59\xe1\x74\x87\x77\x44\x8c\x69\xde\x6b\x80\x0d\x7a\x33\xbb\xfb\x9f\xf1\xb4\x63\xe4\x43\x54\xc3\x55\x3b\xcd\xb9\xc6\x66\xfa\x90\x12\x5a\x3c\x79\xf9\x03\x97\xbd\xf5\xf6\xa1\x3d\xe8\x28\x68\x4f")
assert(Sha512("hello") == "\x9b\x71\xd2\x24\xbd\x62\xf3\x78\x5d\x96\xd4\x6a\xd3\xea\x3d\x73\x31\x9b\xfb\xc2\x89\x0c\xaa\xda\xe2\xdf\xf7\x25\x19\x67\x3c\xa7\x23\x23\xc3\xd9\x9b\xa5\xc1\x1d\x7c\x7a\xcc\x6e\x14\xb8\xc5\xda\x0c\x46\x63\x47\x5c\x2e\x5c\x3a\xde\xf4\x6f\x73\xbc\xde\xc0\x43")
assert(Deflate("hello") == "\xcbH\xcd\xc9\xc9\x07\x00")
assert(Inflate("\xcbH\xcd\xc9\xc9\x07\x00", 5) == "hello")
assert(assert(Deflate("hello")) == "\xcbH\xcd\xc9\xc9\x07\x00")
assert(assert(Inflate("\xcbH\xcd\xc9\xc9\x07\x00", 5)) == "hello")
-- deprecated compression api we wish to forget as quickly as possible
assert(Uncompress(Compress("hello")) == "hello")

View file

@ -0,0 +1,40 @@
-- Copyright 2022 Justine Alexandra Roberts Tunney
--
-- Permission to use, copy, modify, and/or distribute this software for
-- any purpose with or without fee is hereby granted, provided that the
-- above copyright notice and this permission notice appear in all copies.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
-- WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
-- WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
-- AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
-- DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
-- PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-- PERFORMANCE OF THIS SOFTWARE.
m,a,b,c,d = assert(re.search([[^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$]], "127.0.0.1"))
assert(m == "127.0.0.1")
assert(a == "127")
assert(b == "0")
assert(c == "0")
assert(d == "1")
p = assert(re.compile[[^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$]])
m,a,b,c,d = assert(p:search("127.0.0.1"))
assert(m == "127.0.0.1")
assert(a == "127")
assert(b == "0")
assert(c == "0")
assert(d == "1")
m,a,b,c,d = assert(re.search([[\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)]], "127.0.0.1", re.BASIC))
assert(m == "127.0.0.1")
assert(a == "127")
assert(b == "0")
assert(c == "0")
assert(d == "1")
p,e = re.compile("[{")
assert(e:errno() == re.EBRACK)
assert(e:doc() == "Missing ']'")

View file

@ -0,0 +1,21 @@
-- Copyright 2022 Justine Alexandra Roberts Tunney
--
-- Permission to use, copy, modify, and/or distribute this software for
-- any purpose with or without fee is hereby granted, provided that the
-- above copyright notice and this permission notice appear in all copies.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
-- WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
-- WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
-- AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
-- DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
-- PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-- PERFORMANCE OF THIS SOFTWARE.
-- test redbean lua language extensions
assert(0b100 == 4)
assert(0200 == 128)
assert("\e" == "\x1b")
assert("hi" * 3 == "hihihi")
assert("hello %d" % {123} == "hello 123")

View file

@ -13,40 +13,147 @@
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-- PERFORMANCE OF THIS SOFTWARE.
-- dup()+close()
fd = assert(unix.dup(2))
assert(unix.close(fd))
gotsigusr1 = false
tmpdir = "o/tmp/lunix_test.%d" % {unix.getpid()}
-- dup2()+close()
assert(assert(unix.dup(2, 10)) == 10)
assert(unix.close(10))
-- fork()+exit()
if assert(unix.fork()) == 0 then
unix.exit(42)
function OnSigUsr1(sig)
gotsigusr1 = true
end
pid, ws = assert(unix.wait())
assert(unix.WIFEXITED(ws))
assert(unix.WEXITSTATUS(ws) == 42)
-- pledge()
if GetHostOs() == "LINUX" then
function UnixTest()
-- strsignal
assert(unix.strsignal(9) == "SIGKILL")
assert(unix.strsignal(unix.SIGKILL) == "SIGKILL")
-- gmtime
year,mon,mday,hour,min,sec,gmtoffsec,wday,yday,dst,zone = assert(unix.gmtime(1657297063))
assert(year == 2022)
assert(mon == 7)
assert(mday == 8)
assert(hour == 16)
assert(min == 17)
assert(sec == 43)
assert(gmtoffsec == 0)
assert(wday == 5)
assert(yday == 188)
assert(dst == 0)
assert(zone == "GMT")
-- dup
-- 1. duplicate stderr as lowest available fd
-- 1. close the newly assigned file descriptor
fd = assert(unix.dup(2))
assert(unix.close(fd))
-- dup2
-- 1. duplicate stderr as fd 10
-- 1. close the new file descriptor
assert(assert(unix.dup(2, 10)) == 10)
assert(unix.close(10))
-- fork
-- basic subprocess creation
if assert(unix.fork()) == 0 then
assert(unix.pledge("stdio"))
_, err = unix.socket()
assert(err:errno() == unix.EPERM)
unix.exit(0)
unix.pledge("")
unix.exit(42)
end
pid, ws = assert(unix.wait())
assert(unix.WIFEXITED(ws))
assert(unix.WEXITSTATUS(ws) == 0)
elseif GetHostOs() == "OPENBSD" then
if assert(unix.fork()) == 0 then
assert(unix.pledge("stdio"))
unix.socket()
unix.exit(1)
assert(unix.WEXITSTATUS(ws) == 42)
-- pledge
-- 1. fork off a process
-- 2. sandbox the process
-- 3. then violate its security
if GetHostOs() == "LINUX" then
if assert(unix.fork()) == 0 then
assert(unix.pledge("stdio"))
_, err = unix.socket()
assert(err:errno() == unix.EPERM)
unix.exit(0)
end
pid, ws = assert(unix.wait())
assert(unix.WIFEXITED(ws))
assert(unix.WEXITSTATUS(ws) == 0)
elseif GetHostOs() == "OPENBSD" then
if assert(unix.fork()) == 0 then
assert(unix.pledge("stdio"))
unix.socket()
unix.exit(1)
end
pid, ws = assert(unix.wait())
assert(unix.WIFSIGNALED(ws))
assert(unix.WTERMSIG(ws) == unix.SIGABRT)
end
pid, ws = assert(unix.wait())
assert(unix.WIFSIGNALED(ws))
assert(unix.WTERMSIG(ws) == unix.SIGABRT)
-- sigaction
-- 1. install a signal handler for USR1
-- 2. block USR1
-- 3. trigger USR1 signal [it gets enqueued]
-- 4. pause() w/ atomic unblocking of USR1 [now it gets delivered!]
-- 5. restore old signal mask
-- 6. restore old sig handler
oldhand, oldflags, oldmask = assert(unix.sigaction(unix.SIGUSR1, OnSigUsr1))
oldmask = assert(unix.sigprocmask(unix.SIG_BLOCK, unix.Sigset(unix.SIGUSR1)))
assert(unix.raise(unix.SIGUSR1))
assert(not gotsigusr1)
ok, err = unix.sigsuspend(oldmask)
assert(not ok)
assert(err:errno() == unix.EINTR)
assert(gotsigusr1)
assert(unix.sigprocmask(unix.SIG_SETMASK, oldmask))
assert(unix.sigaction(unix.SIGUSR1, oldhand, oldflags, oldmask))
-- open
-- 1. create file
-- 2. fill it up
-- 3. inspect it
-- 4. mess with it
fd = assert(unix.open("%s/foo" % {tmpdir}, unix.O_RDWR | unix.O_CREAT | unix.O_TRUNC, 0600))
assert(assert(unix.fstat(fd)):size() == 0)
assert(unix.ftruncate(fd, 8192))
assert(assert(unix.fstat(fd)):size() == 8192)
assert(unix.write(fd, "hello"))
assert(unix.lseek(fd, 4096))
assert(unix.write(fd, "poke"))
assert(unix.lseek(fd, 8192-4))
assert(unix.write(fd, "poke"))
st = assert(unix.fstat(fd))
assert(st:size() == 8192)
assert(st:blocks() == 8192/512)
assert((st:mode() & 0777) == 0600)
assert(st:uid() == unix.getuid())
assert(st:gid() == unix.getgid())
assert(unix.write(fd, "bear", 4))
assert(unix.read(fd, 10, 0) == "hellbear\x00\x00")
assert(unix.close(fd))
fd = assert(unix.open("%s/foo" % {tmpdir}))
assert(unix.lseek(fd, 4))
assert(unix.read(fd, 4) == "bear")
assert(unix.close(fd))
fd = assert(unix.open("%s/foo" % {tmpdir}, unix.O_RDWR))
assert(unix.write(fd, "bear"))
assert(unix.close(fd))
fd = assert(unix.open("%s/foo" % {tmpdir}))
assert(unix.read(fd, 8) == "bearbear")
assert(unix.close(fd))
-- getdents
for name, kind, ino, off in assert(unix.opendir(tmpdir)) do
end
end
function main()
assert(unix.makedirs(tmpdir))
ok, err = pcall(UnixTest)
if ok then
assert(unix.rmrf(tmpdir))
else
print(err)
error('UnixTest failed (%s)' % {tmpdir})
end
end
main()