]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Increase code coverage for Lua libraries
authorDon Brady <don.brady@delphix.com>
Thu, 8 Feb 2018 16:31:15 +0000 (09:31 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 8 Feb 2018 23:29:38 +0000 (15:29 -0800)
Add test coverage for lua libraries
Remove dead code in Lua implementation

Signed-off-by: Don Brady <don.brady@delphix.com>
17 files changed:
lib/libzpool/Makefile.am
module/lua/Makefile.in
module/lua/lapi.c
module/lua/lbitlib.c [deleted file]
module/lua/lcorolib.c
module/lua/ldo.c
module/lua/ldump.c [deleted file]
module/lua/lstrlib.c
module/lua/lundump.c [deleted file]
module/lua/lundump.h [deleted file]
tests/runfiles/linux.run
tests/zfs-tests/tests/functional/channel_program/lua_core/Makefile.am
tests/zfs-tests/tests/functional/channel_program/lua_core/tst.lib_base.lua [new file with mode: 0644]
tests/zfs-tests/tests/functional/channel_program/lua_core/tst.lib_coroutine.lua [new file with mode: 0644]
tests/zfs-tests/tests/functional/channel_program/lua_core/tst.lib_strings.lua [new file with mode: 0644]
tests/zfs-tests/tests/functional/channel_program/lua_core/tst.lib_table.lua [new file with mode: 0644]
tests/zfs-tests/tests/functional/channel_program/lua_core/tst.libraries.ksh [new file with mode: 0755]

index 4ea7961f92730bfe61a97b3437ff39792b56fb32..4edc60cb01dfb08f0410e46ff0c4be62c686fd76 100644 (file)
@@ -149,14 +149,12 @@ LUA_C = \
        lapi.c \
        lauxlib.c \
        lbaselib.c \
-       lbitlib.c \
        lcode.c \
        lcompat.c \
        lcorolib.c \
        lctype.c \
        ldebug.c \
        ldo.c \
-       ldump.c \
        lfunc.c \
        lgc.c \
        llex.c \
@@ -170,7 +168,6 @@ LUA_C = \
        ltable.c \
        ltablib.c \
        ltm.c \
-       lundump.c \
        lvm.c \
        lzio.c
 
index 6728a5aae490e282354c8d1e8a78de2a33ffdfa1..d49065fbe811ee6c4e921380849c3ffea561ed20 100644 (file)
@@ -15,14 +15,12 @@ ccflags-y += $(NO_UNUSED_BUT_SET_VARIABLE)
 $(MODULE)-objs += lapi.o
 $(MODULE)-objs += lauxlib.o
 $(MODULE)-objs += lbaselib.o
-$(MODULE)-objs += lbitlib.o
 $(MODULE)-objs += lcode.o
 $(MODULE)-objs += lcompat.o
 $(MODULE)-objs += lcorolib.o
 $(MODULE)-objs += lctype.o
 $(MODULE)-objs += ldebug.o
 $(MODULE)-objs += ldo.o
-$(MODULE)-objs += ldump.o
 $(MODULE)-objs += lfunc.o
 $(MODULE)-objs += lgc.o
 $(MODULE)-objs += llex.o
@@ -36,7 +34,6 @@ $(MODULE)-objs += lstrlib.o
 $(MODULE)-objs += ltable.o
 $(MODULE)-objs += ltablib.o
 $(MODULE)-objs += ltm.o
-$(MODULE)-objs += lundump.o
 $(MODULE)-objs += lvm.o
 $(MODULE)-objs += lzio.o
 $(MODULE)-objs += setjmp/setjmp.o
index cd2cc42aea017226321e38c13dc165b10e69c66f..c8b49dc632625ea3f92784ce82f145ffb710cff9 100644 (file)
@@ -22,7 +22,6 @@
 #include "lstring.h"
 #include "ltable.h"
 #include "ltm.h"
-#include "lundump.h"
 #include "lvm.h"
 
 
@@ -991,7 +990,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
   return status;
 }
 
-
+#if defined(LUA_USE_DUMP)
 LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) {
   int status;
   TValue *o;
@@ -1005,7 +1004,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) {
   lua_unlock(L);
   return status;
 }
-
+#endif
 
 LUA_API int lua_status (lua_State *L) {
   return L->status;
diff --git a/module/lua/lbitlib.c b/module/lua/lbitlib.c
deleted file mode 100644 (file)
index 1294e45..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-/* BEGIN CSTYLED */
-/*
-** $Id: lbitlib.c,v 1.18.1.2 2013/07/09 18:01:41 roberto Exp $
-** Standard library for bitwise operations
-** See Copyright Notice in lua.h
-*/
-
-#define lbitlib_c
-#define LUA_LIB
-
-#include <sys/lua/lua.h>
-
-#include <sys/lua/lauxlib.h>
-#include <sys/lua/lualib.h>
-
-
-/* number of bits to consider in a number */
-#if !defined(LUA_NBITS)
-#define LUA_NBITS      32
-#endif
-
-
-#define ALLONES                (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1))
-
-/* macro to trim extra bits */
-#define trim(x)                ((x) & ALLONES)
-
-
-/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */
-#define mask(n)                (~((ALLONES << 1) << ((n) - 1)))
-
-
-typedef lua_Unsigned b_uint;
-
-
-
-static b_uint andaux (lua_State *L) {
-  int i, n = lua_gettop(L);
-  b_uint r = ~(b_uint)0;
-  for (i = 1; i <= n; i++)
-    r &= luaL_checkunsigned(L, i);
-  return trim(r);
-}
-
-
-static int b_and (lua_State *L) {
-  b_uint r = andaux(L);
-  lua_pushunsigned(L, r);
-  return 1;
-}
-
-
-static int b_test (lua_State *L) {
-  b_uint r = andaux(L);
-  lua_pushboolean(L, r != 0);
-  return 1;
-}
-
-
-static int b_or (lua_State *L) {
-  int i, n = lua_gettop(L);
-  b_uint r = 0;
-  for (i = 1; i <= n; i++)
-    r |= luaL_checkunsigned(L, i);
-  lua_pushunsigned(L, trim(r));
-  return 1;
-}
-
-
-static int b_xor (lua_State *L) {
-  int i, n = lua_gettop(L);
-  b_uint r = 0;
-  for (i = 1; i <= n; i++)
-    r ^= luaL_checkunsigned(L, i);
-  lua_pushunsigned(L, trim(r));
-  return 1;
-}
-
-
-static int b_not (lua_State *L) {
-  b_uint r = ~luaL_checkunsigned(L, 1);
-  lua_pushunsigned(L, trim(r));
-  return 1;
-}
-
-
-static int b_shift (lua_State *L, b_uint r, int i) {
-  if (i < 0) {  /* shift right? */
-    i = -i;
-    r = trim(r);
-    if (i >= LUA_NBITS) r = 0;
-    else r >>= i;
-  }
-  else {  /* shift left */
-    if (i >= LUA_NBITS) r = 0;
-    else r <<= i;
-    r = trim(r);
-  }
-  lua_pushunsigned(L, r);
-  return 1;
-}
-
-
-static int b_lshift (lua_State *L) {
-  return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkint(L, 2));
-}
-
-
-static int b_rshift (lua_State *L) {
-  return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkint(L, 2));
-}
-
-
-static int b_arshift (lua_State *L) {
-  b_uint r = luaL_checkunsigned(L, 1);
-  int i = luaL_checkint(L, 2);
-  if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1))))
-    return b_shift(L, r, -i);
-  else {  /* arithmetic shift for 'negative' number */
-    if (i >= LUA_NBITS) r = ALLONES;
-    else
-      r = trim((r >> i) | ~(~(b_uint)0 >> i));  /* add signal bit */
-    lua_pushunsigned(L, r);
-    return 1;
-  }
-}
-
-
-static int b_rot (lua_State *L, int i) {
-  b_uint r = luaL_checkunsigned(L, 1);
-  i &= (LUA_NBITS - 1);  /* i = i % NBITS */
-  r = trim(r);
-  if (i != 0)  /* avoid undefined shift of LUA_NBITS when i == 0 */
-    r = (r << i) | (r >> (LUA_NBITS - i));
-  lua_pushunsigned(L, trim(r));
-  return 1;
-}
-
-
-static int b_lrot (lua_State *L) {
-  return b_rot(L, luaL_checkint(L, 2));
-}
-
-
-static int b_rrot (lua_State *L) {
-  return b_rot(L, -luaL_checkint(L, 2));
-}
-
-
-/*
-** get field and width arguments for field-manipulation functions,
-** checking whether they are valid.
-** ('luaL_error' called without 'return' to avoid later warnings about
-** 'width' being used uninitialized.)
-*/
-static int fieldargs (lua_State *L, int farg, int *width) {
-  int f = luaL_checkint(L, farg);
-  int w = luaL_optint(L, farg + 1, 1);
-  luaL_argcheck(L, 0 <= f, farg, "field cannot be negative");
-  luaL_argcheck(L, 0 < w, farg + 1, "width must be positive");
-  if (f + w > LUA_NBITS)
-    luaL_error(L, "trying to access non-existent bits");
-  *width = w;
-  return f;
-}
-
-
-static int b_extract (lua_State *L) {
-  int w;
-  b_uint r = luaL_checkunsigned(L, 1);
-  int f = fieldargs(L, 2, &w);
-  r = (r >> f) & mask(w);
-  lua_pushunsigned(L, r);
-  return 1;
-}
-
-
-static int b_replace (lua_State *L) {
-  int w;
-  b_uint r = luaL_checkunsigned(L, 1);
-  b_uint v = luaL_checkunsigned(L, 2);
-  int f = fieldargs(L, 3, &w);
-  int m = mask(w);
-  v &= m;  /* erase bits outside given width */
-  r = (r & ~(m << f)) | (v << f);
-  lua_pushunsigned(L, r);
-  return 1;
-}
-
-
-static const luaL_Reg bitlib[] = {
-  {"arshift", b_arshift},
-  {"band", b_and},
-  {"bnot", b_not},
-  {"bor", b_or},
-  {"bxor", b_xor},
-  {"btest", b_test},
-  {"extract", b_extract},
-  {"lrotate", b_lrot},
-  {"lshift", b_lshift},
-  {"replace", b_replace},
-  {"rrotate", b_rrot},
-  {"rshift", b_rshift},
-  {NULL, NULL}
-};
-
-
-
-LUAMOD_API int luaopen_bit32 (lua_State *L) {
-  luaL_newlib(L, bitlib);
-  return 1;
-}
-/* END CSTYLED */
index 1e96a9aebd3fdc1a632f3fa3529b3d9754843844..af8bea6951441425bf049418b809bbca040fd35f 100644 (file)
@@ -57,7 +57,7 @@ static int luaB_coresume (lua_State *L) {
   else {
     lua_pushboolean(L, 1);
     lua_insert(L, -(r + 1));
-    return r + 1;  /* return true + `resume' returns */
+    return r + 1;  /* return true + 'resume' returns */
   }
 }
 
index ead29427e7c3ac1593559ba57260cd1dd5510233..aca02b234770d2c30b793999d8a12dc3e5c92949 100644 (file)
@@ -24,7 +24,6 @@
 #include "lstring.h"
 #include "ltable.h"
 #include "ltm.h"
-#include "lundump.h"
 #include "lvm.h"
 #include "lzio.h"
 
@@ -684,14 +683,9 @@ static void f_parser (lua_State *L, void *ud) {
   Closure *cl;
   struct SParser *p = cast(struct SParser *, ud);
   int c = zgetc(p->z);  /* read first character */
-  if (c == LUA_SIGNATURE[0]) {
-    checkmode(L, p->mode, "binary");
-    cl = luaU_undump(L, p->z, &p->buff, p->name);
-  }
-  else {
-    checkmode(L, p->mode, "text");
-    cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
-  }
+  lua_assert(c != LUA_SIGNATURE[0]);   /* binary not supported */
+  checkmode(L, p->mode, "text");
+  cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
   lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
   for (i = 0; i < cl->l.nupvalues; i++) {  /* initialize upvalues */
     UpVal *up = luaF_newupval(L);
diff --git a/module/lua/ldump.c b/module/lua/ldump.c
deleted file mode 100644 (file)
index b448869..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/* BEGIN CSTYLED */
-/*
-** $Id: ldump.c,v 2.17.1.1 2013/04/12 18:48:47 roberto Exp $
-** save precompiled Lua chunks
-** See Copyright Notice in lua.h
-*/
-
-#define ldump_c
-#define LUA_CORE
-
-#include <sys/lua/lua.h>
-
-#include "lobject.h"
-#include "lstate.h"
-#include "lundump.h"
-
-typedef struct {
- lua_State* L;
- lua_Writer writer;
- void* data;
- int strip;
- int status;
-} DumpState;
-
-#define DumpMem(b,n,size,D)    DumpBlock(b,(n)*(size),D)
-#define DumpVar(x,D)           DumpMem(&x,1,sizeof(x),D)
-
-static void DumpBlock(const void* b, size_t size, DumpState* D)
-{
- if (D->status==0)
- {
-  lua_unlock(D->L);
-  D->status=(*D->writer)(D->L,b,size,D->data);
-  lua_lock(D->L);
- }
-}
-
-static void DumpChar(int y, DumpState* D)
-{
- char x=(char)y;
- DumpVar(x,D);
-}
-
-static void DumpInt(int x, DumpState* D)
-{
- DumpVar(x,D);
-}
-
-static void DumpNumber(lua_Number x, DumpState* D)
-{
- DumpVar(x,D);
-}
-
-static void DumpVector(const void* b, int n, size_t size, DumpState* D)
-{
- DumpInt(n,D);
- DumpMem(b,n,size,D);
-}
-
-static void DumpString(const TString* s, DumpState* D)
-{
- if (s==NULL)
- {
-  size_t size=0;
-  DumpVar(size,D);
- }
- else
- {
-  size_t size=s->tsv.len+1;            /* include trailing '\0' */
-  DumpVar(size,D);
-  DumpBlock(getstr(s),size*sizeof(char),D);
- }
-}
-
-#define DumpCode(f,D)   DumpVector(f->code,f->sizecode,sizeof(Instruction),D)
-
-static void DumpFunction(const Proto* f, DumpState* D);
-
-static void DumpConstants(const Proto* f, DumpState* D)
-{
- int i,n=f->sizek;
- DumpInt(n,D);
- for (i=0; i<n; i++)
- {
-  const TValue* o=&f->k[i];
-  DumpChar(ttypenv(o),D);
-  switch (ttypenv(o))
-  {
-   case LUA_TNIL:
-       break;
-   case LUA_TBOOLEAN:
-       DumpChar(bvalue(o),D);
-       break;
-   case LUA_TNUMBER:
-       DumpNumber(nvalue(o),D);
-       break;
-   case LUA_TSTRING:
-       DumpString(rawtsvalue(o),D);
-       break;
-    default: lua_assert(0);
-  }
- }
- n=f->sizep;
- DumpInt(n,D);
- for (i=0; i<n; i++) DumpFunction(f->p[i],D);
-}
-
-static void DumpUpvalues(const Proto* f, DumpState* D)
-{
- int i,n=f->sizeupvalues;
- DumpInt(n,D);
- for (i=0; i<n; i++)
- {
-  DumpChar(f->upvalues[i].instack,D);
-  DumpChar(f->upvalues[i].idx,D);
- }
-}
-
-static void DumpDebug(const Proto* f, DumpState* D)
-{
- int i,n;
- DumpString((D->strip) ? NULL : f->source,D);
- n= (D->strip) ? 0 : f->sizelineinfo;
- DumpVector(f->lineinfo,n,sizeof(int),D);
- n= (D->strip) ? 0 : f->sizelocvars;
- DumpInt(n,D);
- for (i=0; i<n; i++)
- {
-  DumpString(f->locvars[i].varname,D);
-  DumpInt(f->locvars[i].startpc,D);
-  DumpInt(f->locvars[i].endpc,D);
- }
- n= (D->strip) ? 0 : f->sizeupvalues;
- DumpInt(n,D);
- for (i=0; i<n; i++) DumpString(f->upvalues[i].name,D);
-}
-
-static void DumpFunction(const Proto* f, DumpState* D)
-{
- DumpInt(f->linedefined,D);
- DumpInt(f->lastlinedefined,D);
- DumpChar(f->numparams,D);
- DumpChar(f->is_vararg,D);
- DumpChar(f->maxstacksize,D);
- DumpCode(f,D);
- DumpConstants(f,D);
- DumpUpvalues(f,D);
- DumpDebug(f,D);
-}
-
-static void DumpHeader(DumpState* D)
-{
- lu_byte h[LUAC_HEADERSIZE];
- luaU_header(h);
- DumpBlock(h,LUAC_HEADERSIZE,D);
-}
-
-/*
-** dump Lua function as precompiled chunk
-*/
-int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
-{
- DumpState D;
- D.L=L;
- D.writer=w;
- D.data=data;
- D.strip=strip;
- D.status=0;
- DumpHeader(&D);
- DumpFunction(f,&D);
- return D.status;
-}
-/* END CSTYLED */
index 7020f1bb7b22545ada51d8fad315d9759b5960c1..cff5e894d472800c9e1ce1ffa93900fafe480ddf 100644 (file)
@@ -174,6 +174,7 @@ static int str_char (lua_State *L) {
 }
 
 
+#if defined(LUA_USE_DUMP)
 static int writer (lua_State *L, const void* b, size_t size, void* B) {
   (void)L;
   luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
@@ -191,7 +192,7 @@ static int str_dump (lua_State *L) {
   luaL_pushresult(&b);
   return 1;
 }
-
+#endif
 
 
 /*
@@ -992,7 +993,9 @@ static int str_format (lua_State *L) {
 static const luaL_Reg strlib[] = {
   {"byte", str_byte},
   {"char", str_char},
+#if defined(LUA_USE_DUMP)
   {"dump", str_dump},
+#endif
   {"find", str_find},
   {"format", str_format},
   {"gmatch", str_gmatch},
diff --git a/module/lua/lundump.c b/module/lua/lundump.c
deleted file mode 100644 (file)
index 66efc54..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-/* BEGIN CSTYLED */
-/*
-** $Id: lundump.c,v 2.22.1.1 2013/04/12 18:48:47 roberto Exp $
-** load precompiled Lua chunks
-** See Copyright Notice in lua.h
-*/
-
-#define lundump_c
-#define LUA_CORE
-
-#include <sys/lua/lua.h>
-
-#include "ldebug.h"
-#include "ldo.h"
-#include "lfunc.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lstring.h"
-#include "lundump.h"
-#include "lzio.h"
-
-typedef struct {
- lua_State* L;
- ZIO* Z;
- Mbuffer* b;
- const char* name;
-} LoadState;
-
-static l_noret error(LoadState* S, const char* why)
-{
- luaO_pushfstring(S->L,"%s: %s precompiled chunk",S->name,why);
- luaD_throw(S->L,LUA_ERRSYNTAX);
-}
-
-#define LoadMem(S,b,n,size)    LoadBlock(S,b,(n)*(size))
-#define LoadByte(S)            (lu_byte)LoadChar(S)
-#define LoadVar(S,x)           LoadMem(S,&x,1,sizeof(x))
-#define LoadVector(S,b,n,size) LoadMem(S,b,n,size)
-
-#if !defined(luai_verifycode)
-#define luai_verifycode(L,b,f) /* empty */
-#endif
-
-static void LoadBlock(LoadState* S, void* b, size_t size)
-{
- if (luaZ_read(S->Z,b,size)!=0) error(S,"truncated");
-}
-
-static int LoadChar(LoadState* S)
-{
- char x;
- LoadVar(S,x);
- return x;
-}
-
-static int LoadInt(LoadState* S)
-{
- int x;
- LoadVar(S,x);
- if (x<0) error(S,"corrupted");
- return x;
-}
-
-static lua_Number LoadNumber(LoadState* S)
-{
- lua_Number x;
- LoadVar(S,x);
- return x;
-}
-
-static TString* LoadString(LoadState* S)
-{
- size_t size;
- LoadVar(S,size);
- if (size==0)
-  return NULL;
- else
- {
-  char* s=luaZ_openspace(S->L,S->b,size);
-  LoadBlock(S,s,size*sizeof(char));
-  return luaS_newlstr(S->L,s,size-1);          /* remove trailing '\0' */
- }
-}
-
-static void LoadCode(LoadState* S, Proto* f)
-{
- int n=LoadInt(S);
- f->code=luaM_newvector(S->L,n,Instruction);
- f->sizecode=n;
- LoadVector(S,f->code,n,sizeof(Instruction));
-}
-
-static void LoadFunction(LoadState* S, Proto* f);
-
-static void LoadConstants(LoadState* S, Proto* f)
-{
- int i,n;
- n=LoadInt(S);
- f->k=luaM_newvector(S->L,n,TValue);
- f->sizek=n;
- for (i=0; i<n; i++) setnilvalue(&f->k[i]);
- for (i=0; i<n; i++)
- {
-  TValue* o=&f->k[i];
-  int t=LoadChar(S);
-  switch (t)
-  {
-   case LUA_TNIL:
-       setnilvalue(o);
-       break;
-   case LUA_TBOOLEAN:
-       setbvalue(o,LoadChar(S));
-       break;
-   case LUA_TNUMBER:
-       setnvalue(o,LoadNumber(S));
-       break;
-   case LUA_TSTRING:
-       setsvalue2n(S->L,o,LoadString(S));
-       break;
-    default: lua_assert(0);
-  }
- }
- n=LoadInt(S);
- f->p=luaM_newvector(S->L,n,Proto*);
- f->sizep=n;
- for (i=0; i<n; i++) f->p[i]=NULL;
- for (i=0; i<n; i++)
- {
-  f->p[i]=luaF_newproto(S->L);
-  LoadFunction(S,f->p[i]);
- }
-}
-
-static void LoadUpvalues(LoadState* S, Proto* f)
-{
- int i,n;
- n=LoadInt(S);
- f->upvalues=luaM_newvector(S->L,n,Upvaldesc);
- f->sizeupvalues=n;
- for (i=0; i<n; i++) f->upvalues[i].name=NULL;
- for (i=0; i<n; i++)
- {
-  f->upvalues[i].instack=LoadByte(S);
-  f->upvalues[i].idx=LoadByte(S);
- }
-}
-
-static void LoadDebug(LoadState* S, Proto* f)
-{
- int i,n;
- f->source=LoadString(S);
- n=LoadInt(S);
- f->lineinfo=luaM_newvector(S->L,n,int);
- f->sizelineinfo=n;
- LoadVector(S,f->lineinfo,n,sizeof(int));
- n=LoadInt(S);
- f->locvars=luaM_newvector(S->L,n,LocVar);
- f->sizelocvars=n;
- for (i=0; i<n; i++) f->locvars[i].varname=NULL;
- for (i=0; i<n; i++)
- {
-  f->locvars[i].varname=LoadString(S);
-  f->locvars[i].startpc=LoadInt(S);
-  f->locvars[i].endpc=LoadInt(S);
- }
- n=LoadInt(S);
- for (i=0; i<n; i++) f->upvalues[i].name=LoadString(S);
-}
-
-static void LoadFunction(LoadState* S, Proto* f)
-{
- f->linedefined=LoadInt(S);
- f->lastlinedefined=LoadInt(S);
- f->numparams=LoadByte(S);
- f->is_vararg=LoadByte(S);
- f->maxstacksize=LoadByte(S);
- LoadCode(S,f);
- LoadConstants(S,f);
- LoadUpvalues(S,f);
- LoadDebug(S,f);
-}
-
-/* the code below must be consistent with the code in luaU_header */
-#define N0     LUAC_HEADERSIZE
-#define N1     (sizeof(LUA_SIGNATURE)-sizeof(char))
-#define N2     N1+2
-#define N3     N2+6
-
-static void LoadHeader(LoadState* S)
-{
- lu_byte h[LUAC_HEADERSIZE];
- lu_byte s[LUAC_HEADERSIZE];
- luaU_header(h);
- memcpy(s,h,sizeof(char));                     /* first char already read */
- LoadBlock(S,s+sizeof(char),LUAC_HEADERSIZE-sizeof(char));
- if (memcmp(h,s,N0)==0) return;
- if (memcmp(h,s,N1)!=0) error(S,"not a");
- if (memcmp(h,s,N2)!=0) error(S,"version mismatch in");
- if (memcmp(h,s,N3)!=0) error(S,"incompatible"); else error(S,"corrupted");
-}
-
-/*
-** load precompiled chunk
-*/
-Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)
-{
- LoadState S;
- Closure* cl;
- if (*name=='@' || *name=='=')
-  S.name=name+1;
- else if (*name==LUA_SIGNATURE[0])
-  S.name="binary string";
- else
-  S.name=name;
- S.L=L;
- S.Z=Z;
- S.b=buff;
- LoadHeader(&S);
- cl=luaF_newLclosure(L,1);
- setclLvalue(L,L->top,cl); incr_top(L);
- cl->l.p=luaF_newproto(L);
- LoadFunction(&S,cl->l.p);
- if (cl->l.p->sizeupvalues != 1)
- {
-  Proto* p=cl->l.p;
-  cl=luaF_newLclosure(L,cl->l.p->sizeupvalues);
-  cl->l.p=p;
-  setclLvalue(L,L->top-1,cl);
- }
- luai_verifycode(L,buff,cl->l.p);
- return cl;
-}
-
-#define MYINT(s)       (s[0]-'0')
-#define VERSION                MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)
-#define FORMAT         0               /* this is the official format */
-
-/*
-* make header for precompiled chunks
-* if you change the code below be sure to update LoadHeader and FORMAT above
-* and LUAC_HEADERSIZE in lundump.h
-*/
-void luaU_header (lu_byte* h)
-{
- int x=1;
- memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-sizeof(char));
- h+=sizeof(LUA_SIGNATURE)-sizeof(char);
- *h++=cast_byte(VERSION);
- *h++=cast_byte(FORMAT);
- *h++=cast_byte(*(char*)&x);                   /* endianness */
- *h++=cast_byte(sizeof(int));
- *h++=cast_byte(sizeof(size_t));
- *h++=cast_byte(sizeof(Instruction));
- *h++=cast_byte(sizeof(lua_Number));
- *h++=cast_byte(((lua_Number)0.5)==0);         /* is lua_Number integral? */
- memcpy(h,LUAC_TAIL,sizeof(LUAC_TAIL)-sizeof(char));
-}
-/* END CSTYLED */
diff --git a/module/lua/lundump.h b/module/lua/lundump.h
deleted file mode 100644 (file)
index dc8b0d8..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* BEGIN CSTYLED */
-/*
-** $Id: lundump.h,v 1.39.1.1 2013/04/12 18:48:47 roberto Exp $
-** load precompiled Lua chunks
-** See Copyright Notice in lua.h
-*/
-
-#ifndef lundump_h
-#define lundump_h
-
-#include "lobject.h"
-#include "lzio.h"
-
-/* load one chunk; from lundump.c */
-LUAI_FUNC Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name);
-
-/* make header; from lundump.c */
-LUAI_FUNC void luaU_header (lu_byte* h);
-
-/* dump one chunk; from ldump.c */
-LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip);
-
-/* data to catch conversion errors */
-#define LUAC_TAIL              "\x19\x93\r\n\x1a\n"
-
-/* size in bytes of header of binary files */
-#define LUAC_HEADERSIZE                (sizeof(LUA_SIGNATURE)-sizeof(char)+2+6+sizeof(LUAC_TAIL)-sizeof(char))
-
-#endif
-/* END CSTYLED */
index 1bd3fd6053d406f74d0e775f4abc32fd54fd7e80..6bbc3a6b6a89367b628a695d54972de63cea0490 100644 (file)
@@ -65,8 +65,8 @@ tags = ['functional', 'casenorm']
 [tests/functional/channel_program/lua_core]
 tests = ['tst.args_to_lua', 'tst.divide_by_zero', 'tst.exists',
     'tst.integer_illegal', 'tst.integer_overflow', 'tst.language_functions_neg',
-    'tst.language_functions_pos', 'tst.large_prog', 'tst.memory_limit',
-    'tst.nested_neg', 'tst.nested_pos', 'tst.nvlist_to_lua',
+    'tst.language_functions_pos', 'tst.large_prog', 'tst.libraries',
+    'tst.memory_limit', 'tst.nested_neg', 'tst.nested_pos', 'tst.nvlist_to_lua',
     'tst.recursive_neg', 'tst.recursive_pos', 'tst.return_large',
     'tst.return_nvlist_neg', 'tst.return_nvlist_pos',
     'tst.return_recursive_table', 'tst.timeout']
index dba3da0f1c225c2b94afff94f78d1f7c94aa4ff3..6de88d723b625231ef6d8a7bf4ddb25345b10c77 100644 (file)
@@ -17,6 +17,11 @@ dist_pkgdata_SCRIPTS = \
        tst.large_prog.ksh \
        tst.large_prog.out \
        tst.large_prog.zcp \
+       tst.lib_base.lua \
+       tst.lib_coroutine.lua \
+       tst.lib_strings.lua \
+       tst.lib_table.lua \
+       tst.libraries.ksh \
        tst.memory_limit.ksh \
        tst.nested_neg.ksh \
        tst.nested_neg.zcp \
diff --git a/tests/zfs-tests/tests/functional/channel_program/lua_core/tst.lib_base.lua b/tests/zfs-tests/tests/functional/channel_program/lua_core/tst.lib_base.lua
new file mode 100644 (file)
index 0000000..c391449
--- /dev/null
@@ -0,0 +1,469 @@
+--[[
+--*****************************************************************************
+--* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
+--*
+--* Permission is hereby granted, free of charge, to any person obtaining
+--* a copy of this software and associated documentation files (the
+--* "Software"), to deal in the Software without restriction, including
+--* without limitation the rights to use, copy, modify, merge, publish,
+--* distribute, sublicense, and/or sell copies of the Software, and to
+--* permit persons to whom the Software is furnished to do so, subject to
+--* the following conditions:
+--*
+--* The above copyright notice and this permission notice shall be
+--* included in all copies or substantial portions of the Software.
+--*
+--* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+--* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+--* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+--* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+--* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+--* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+--* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+--*****************************************************************************
+--]]
+
+-- testing metatables
+
+X = 20; B = 30
+
+_ENV = setmetatable({}, {__index=_G})
+
+collectgarbage()
+
+X = X+10
+assert(X == 30 and _G.X == 20)
+B = false
+assert(B == false)
+B = nil
+assert(B == 30)
+
+assert(getmetatable{} == nil)
+assert(getmetatable(4) == nil)
+assert(getmetatable(nil) == nil)
+a={name = "NAME"}; setmetatable(a, {__metatable = "xuxu",
+                    __tostring=function(x) return x.name end})
+assert(getmetatable(a) == "xuxu")
+assert(tostring(a) == "NAME")
+
+local a, t = {10,20,30; x="10", y="20"}, {}
+assert(setmetatable(a,t) == a)
+assert(getmetatable(a) == t)
+assert(setmetatable(a,nil) == a)
+assert(getmetatable(a) == nil)
+assert(setmetatable(a,t) == a)
+
+
+function f (t, i, e)
+  assert(not e)
+  local p = rawget(t, "parent")
+  return (p and p[i]+3), "dummy return"
+end
+
+t.__index = f
+
+a.parent = {z=25, x=12, [4] = 24}
+assert(a[1] == 10 and a.z == 28 and a[4] == 27 and a.x == "10")
+
+collectgarbage()
+
+a = setmetatable({}, t)
+function f(t, i, v) rawset(t, i, v-3) end
+setmetatable(t, t)   -- causes a bug in 5.1 !
+t.__newindex = f
+a[1] = 30; a.x = "101"; a[5] = 200
+assert(a[1] == 27 and a.x == 98 and a[5] == 197)
+
+
+local c = {}
+a = setmetatable({}, t)
+t.__newindex = c
+a[1] = 10; a[2] = 20; a[3] = 90
+assert(c[1] == 10 and c[2] == 20 and c[3] == 90)
+
+
+do
+  local a;
+  a = setmetatable({}, {__index = setmetatable({},
+                     {__index = setmetatable({},
+                     {__index = function (_,n) return a[n-3]+4, "lixo" end})})})
+  a[0] = 20
+  for i=0,10 do
+    assert(a[i*3] == 20 + i*4)
+  end
+end
+
+
+do  -- newindex
+  local foi
+  local a = {}
+  for i=1,10 do a[i] = 0; a['a'..i] = 0; end
+  setmetatable(a, {__newindex = function (t,k,v) foi=true; rawset(t,k,v) end})
+  foi = false; a[1]=0; assert(not foi)
+  foi = false; a['a1']=0; assert(not foi)
+  foi = false; a['a11']=0; assert(foi)
+  foi = false; a[11]=0; assert(foi)
+  foi = false; a[1]=nil; assert(not foi)
+  foi = false; a[1]=nil; assert(foi)
+end
+
+
+setmetatable(t, nil)
+function f (t, ...) return t, {...} end
+t.__call = f
+
+do
+  local x,y = a(table.unpack{'a', 1})
+  assert(x==a and y[1]=='a' and y[2]==1 and y[3]==nil)
+  x,y = a()
+  assert(x==a and y[1]==nil)
+end
+
+
+local b = setmetatable({}, t)
+setmetatable(b,t)
+
+function f(op)
+  return function (...) cap = {[0] = op, ...} ; return (...) end
+end
+t.__add = f("add")
+t.__sub = f("sub")
+t.__mul = f("mul")
+t.__div = f("div")
+t.__mod = f("mod")
+t.__unm = f("unm")
+t.__pow = f("pow")
+t.__len = f("len")
+
+assert(b+5 == b)
+assert(cap[0] == "add" and cap[1] == b and cap[2] == 5 and cap[3]==nil)
+assert(b+'5' == b)
+assert(cap[0] == "add" and cap[1] == b and cap[2] == '5' and cap[3]==nil)
+assert(5+b == 5)
+assert(cap[0] == "add" and cap[1] == 5 and cap[2] == b and cap[3]==nil)
+assert('5'+b == '5')
+assert(cap[0] == "add" and cap[1] == '5' and cap[2] == b and cap[3]==nil)
+b=b-3; assert(getmetatable(b) == t)
+assert(5-a == 5)
+assert(cap[0] == "sub" and cap[1] == 5 and cap[2] == a and cap[3]==nil)
+assert('5'-a == '5')
+assert(cap[0] == "sub" and cap[1] == '5' and cap[2] == a and cap[3]==nil)
+assert(a*a == a)
+assert(cap[0] == "mul" and cap[1] == a and cap[2] == a and cap[3]==nil)
+assert(a/0 == a)
+assert(cap[0] == "div" and cap[1] == a and cap[2] == 0 and cap[3]==nil)
+assert(a%2 == a)
+assert(cap[0] == "mod" and cap[1] == a and cap[2] == 2 and cap[3]==nil)
+assert(-a == a)
+assert(cap[0] == "unm" and cap[1] == a)
+assert(a^4 == a)
+assert(cap[0] == "pow" and cap[1] == a and cap[2] == 4 and cap[3]==nil)
+assert(a^'4' == a)
+assert(cap[0] == "pow" and cap[1] == a and cap[2] == '4' and cap[3]==nil)
+assert(4^a == 4)
+assert(cap[0] == "pow" and cap[1] == 4 and cap[2] == a and cap[3]==nil)
+assert('4'^a == '4')
+assert(cap[0] == "pow" and cap[1] == '4' and cap[2] == a and cap[3]==nil)
+assert(#a == a)
+assert(cap[0] == "len" and cap[1] == a)
+
+
+-- test for rawlen
+t = setmetatable({1,2,3}, {__len = function () return 10 end})
+assert(#t == 10 and rawlen(t) == 3)
+assert(rawlen"abc" == 3)
+assert(rawlen(string.rep('a', 1000)) == 1000)
+
+t = {}
+t.__lt = function (a,b,c)
+  collectgarbage()
+  assert(c == nil)
+  if type(a) == 'table' then a = a.x end
+  if type(b) == 'table' then b = b.x end
+ return a<b, "dummy"
+end
+
+function Op(x) return setmetatable({x=x}, t) end
+
+local function test ()
+  assert(not(Op(1)<Op(1)) and (Op(1)<Op(2)) and not(Op(2)<Op(1)))
+  assert(not(1 < Op(1)) and (Op(1) < 2) and not(2 < Op(1)))
+  assert(not(Op('a')<Op('a')) and (Op('a')<Op('b')) and not(Op('b')<Op('a')))
+  assert(not('a' < Op('a')) and (Op('a') < 'b') and not(Op('b') < Op('a')))
+  assert((Op(1)<=Op(1)) and (Op(1)<=Op(2)) and not(Op(2)<=Op(1)))
+  assert((Op('a')<=Op('a')) and (Op('a')<=Op('b')) and not(Op('b')<=Op('a')))
+  assert(not(Op(1)>Op(1)) and not(Op(1)>Op(2)) and (Op(2)>Op(1)))
+  assert(not(Op('a')>Op('a')) and not(Op('a')>Op('b')) and (Op('b')>Op('a')))
+  assert((Op(1)>=Op(1)) and not(Op(1)>=Op(2)) and (Op(2)>=Op(1)))
+  assert((1 >= Op(1)) and not(1 >= Op(2)) and (Op(2) >= 1))
+  assert((Op('a')>=Op('a')) and not(Op('a')>=Op('b')) and (Op('b')>=Op('a')))
+  assert(('a' >= Op('a')) and not(Op('a') >= 'b') and (Op('b') >= Op('a')))
+end
+
+test()
+
+t.__le = function (a,b,c)
+  assert(c == nil)
+  if type(a) == 'table' then a = a.x end
+  if type(b) == 'table' then b = b.x end
+ return a<=b, "dummy"
+end
+
+test()  -- retest comparisons, now using both `lt' and `le'
+
+
+-- test `partial order'
+
+local function Set(x)
+  local y = {}
+  for _,k in pairs(x) do y[k] = 1 end
+  return setmetatable(y, t)
+end
+
+t.__lt = function (a,b)
+  for k in pairs(a) do
+    if not b[k] then return false end
+    b[k] = nil
+  end
+  return next(b) ~= nil
+end
+
+t.__le = nil
+
+assert(Set{1,2,3} < Set{1,2,3,4})
+assert(not(Set{1,2,3,4} < Set{1,2,3,4}))
+assert((Set{1,2,3,4} <= Set{1,2,3,4}))
+assert((Set{1,2,3,4} >= Set{1,2,3,4}))
+assert((Set{1,3} <= Set{3,5}))   -- wrong!! model needs a `le' method ;-)
+
+t.__le = function (a,b)
+  for k in pairs(a) do
+    if not b[k] then return false end
+  end
+  return true
+end
+
+assert(not (Set{1,3} <= Set{3,5}))   -- now its OK!
+assert(not(Set{1,3} <= Set{3,5}))
+assert(not(Set{1,3} >= Set{3,5}))
+
+t.__eq = function (a,b)
+  for k in pairs(a) do
+    if not b[k] then return false end
+    b[k] = nil
+  end
+  return next(b) == nil
+end
+
+local s = Set{1,3,5}
+assert(s == Set{3,5,1})
+assert(not rawequal(s, Set{3,5,1}))
+assert(rawequal(s, s))
+assert(Set{1,3,5,1} == Set{3,5,1})
+assert(Set{1,3,5} ~= Set{3,5,1,6})
+t[Set{1,3,5}] = 1
+assert(t[Set{1,3,5}] == nil)   -- `__eq' is not valid for table accesses
+
+
+t.__concat = function (a,b,c)
+  assert(c == nil)
+  if type(a) == 'table' then a = a.val end
+  if type(b) == 'table' then b = b.val end
+  if A then return a..b
+  else
+    return setmetatable({val=a..b}, t)
+  end
+end
+
+c = {val="c"}; setmetatable(c, t)
+d = {val="d"}; setmetatable(d, t)
+
+A = true
+assert(c..d == 'cd')
+assert(0 .."a".."b"..c..d.."e".."f"..(5+3).."g" == "0abcdef8g")
+
+A = false
+assert((c..d..c..d).val == 'cdcd')
+x = c..d
+assert(getmetatable(x) == t and x.val == 'cd')
+x = 0 .."a".."b"..c..d.."e".."f".."g"
+assert(x.val == "0abcdefg")
+
+
+-- concat metamethod x numbers (bug in 5.1.1)
+c = {}
+local x
+setmetatable(c, {__concat = function (a,b)
+  assert(type(a) == "number" and b == c or type(b) == "number" and a == c)
+  return c
+end})
+assert(c..5 == c and 5 .. c == c)
+assert(4 .. c .. 5 == c and 4 .. 5 .. 6 .. 7 .. c == c)
+
+
+-- test comparison compatibilities
+local t1, t2, c, d
+t1 = {};  c = {}; setmetatable(c, t1)
+d = {}
+t1.__eq = function () return true end
+t1.__lt = function () return true end
+setmetatable(d, t1)
+assert(c == d and c < d and not(d <= c))
+t2 = {}
+t2.__eq = t1.__eq
+t2.__lt = t1.__lt
+setmetatable(d, t2)
+assert(c == d and c < d and not(d <= c))
+
+
+
+-- test for several levels of calls
+local i
+local tt = {
+  __call = function (t, ...)
+    i = i+1
+    if t.f then return t.f(...)
+    else return {...}
+    end
+  end
+}
+
+local a = setmetatable({}, tt)
+local b = setmetatable({f=a}, tt)
+local c = setmetatable({f=b}, tt)
+
+i = 0
+x = c(3,4,5)
+assert(i == 3 and x[1] == 3 and x[3] == 5)
+
+
+assert(_G.X == 20)
+
+
+local _g = _G
+_ENV = setmetatable({}, {__index=function (_,k) return _g[k] end})
+
+
+a = {}
+rawset(a, "x", 1, 2, 3)
+assert(a.x == 1 and rawget(a, "x", 3) == 1)
+
+
+-- bug in 5.1
+T, K, V = nil
+grandparent = {}
+grandparent.__newindex = function(t,k,v) T=t; K=k; V=v end
+
+parent = {}
+parent.__newindex = parent
+setmetatable(parent, grandparent)
+
+child = setmetatable({}, parent)
+child.foo = 10      --> CRASH (on some machines)
+assert(T == parent and K == "foo" and V == 10)
+
+
+-- testing 'tonumber'
+assert(tonumber{} == nil)
+assert(tonumber('-012') == -010-2)
+assert(tonumber("0xffffffffffff") == 2^(4*12) - 1)
+assert(tonumber("0x"..string.rep("f", 150)) == 2^(4*150) - 1)
+
+-- testing 'tonumber' with base
+assert(tonumber('  001010  ', 2) == 10)
+assert(tonumber('  001010  ', 10) == 1010)
+assert(tonumber('  -1010  ', 2) == -10)
+assert(tonumber('10', 36) == 36)
+assert(tonumber('  -10  ', 36) == -36)
+assert(tonumber('  +1Z  ', 36) == 36 + 35)
+assert(tonumber('  -1z  ', 36) == -36 + -35)
+assert(tonumber('-fFfa', 16) == -(10+(16*(15+(16*(15+(16*15)))))))
+assert(tonumber(string.rep('1', 42), 2) + 1 == 2^42)
+assert(tonumber(string.rep('1', 34), 2) + 1 == 2^34)
+assert(tonumber('ffffFFFF', 16)+1 == 2^32)
+assert(tonumber('0ffffFFFF', 16)+1 == 2^32)
+assert(tonumber('-0ffffffFFFF', 16) - 1 == -2^40)
+for i = 2,36 do
+  assert(tonumber('\t10000000000\t', i) == i^10)
+end
+
+-- testing 'tonumber' for invalid formats
+function f(...)
+  if select('#', ...) == 1 then
+    return (...)
+  else
+    return "***"
+  end
+end
+
+assert(f(tonumber('fFfa', 15)) == nil)
+assert(f(tonumber('099', 8)) == nil)
+assert(f(tonumber('1\0', 2)) == nil)
+assert(f(tonumber('', 8)) == nil)
+assert(f(tonumber('  ', 9)) == nil)
+assert(f(tonumber('0xf', 10)) == nil)
+
+assert(f(tonumber('inf')) == nil)
+assert(f(tonumber(' INF ')) == nil)
+assert(f(tonumber('Nan')) == nil)
+assert(f(tonumber('nan')) == nil)
+
+assert(f(tonumber('')) == nil)
+assert(f(tonumber('1  a')) == nil)
+assert(f(tonumber('1\0')) == nil)
+assert(f(tonumber('1 \0')) == nil)
+assert(f(tonumber('1\0 ')) == nil)
+assert(f(tonumber('e1')) == nil)
+assert(f(tonumber('e  1')) == nil)
+
+
+-- testing 'tonumber' for invalid hexadecimal formats
+assert(tonumber('0x') == nil)
+assert(tonumber('x') == nil)
+assert(tonumber('x3') == nil)
+assert(tonumber('00x2') == nil)
+assert(tonumber('0x 2') == nil)
+assert(tonumber('0 x2') == nil)
+assert(tonumber('23x') == nil)
+assert(tonumber('- 0xaa') == nil)
+
+
+-- testing hexadecimal numerals
+assert(tonumber('+0x2') == 2)
+assert(tonumber('-0xaA') == -170)
+assert(tonumber('-0xffFFFfff') == -2^32 + 1)
+
+
+-- testing 'tostring'
+assert(tostring("alo") == "alo")
+assert(tostring(12) == "12")
+assert(tostring(1234567890123) == '1234567890123')
+assert(type(tostring("hello")) == "string")
+assert(tostring(true) == "true")
+assert(tostring(false) == "false")
+assert(string.find(tostring{}, 'table:'))
+assert(string.find(tostring(select), 'function:'))
+assert(#tostring('\0') == 1)
+
+
+-- testing ipairs
+local x = 0
+for k,v in ipairs{10,20,30;x=12} do
+  x = x + 1
+  assert(k == x and v == x * 10)
+end
+
+for _ in ipairs{x=12, y=24} do assert(nil) end
+
+-- test for 'false' x ipair
+x = false
+local i = 0
+for k,v in ipairs{true,false,true,false} do
+  i = i + 1
+  x = not x
+  assert(x == v)
+end
+assert(i == 4)
+
+
+return "OK"
diff --git a/tests/zfs-tests/tests/functional/channel_program/lua_core/tst.lib_coroutine.lua b/tests/zfs-tests/tests/functional/channel_program/lua_core/tst.lib_coroutine.lua
new file mode 100644 (file)
index 0000000..e0e9e2a
--- /dev/null
@@ -0,0 +1,362 @@
+--[[
+--*****************************************************************************
+--* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
+--*
+--* Permission is hereby granted, free of charge, to any person obtaining
+--* a copy of this software and associated documentation files (the
+--* "Software"), to deal in the Software without restriction, including
+--* without limitation the rights to use, copy, modify, merge, publish,
+--* distribute, sublicense, and/or sell copies of the Software, and to
+--* permit persons to whom the Software is furnished to do so, subject to
+--* the following conditions:
+--*
+--* The above copyright notice and this permission notice shall be
+--* included in all copies or substantial portions of the Software.
+--*
+--* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+--* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+--* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+--* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+--* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+--* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+--* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+--*****************************************************************************
+--]]
+
+local f
+
+local main, ismain = coroutine.running()
+assert(type(main) == "thread" and ismain)
+assert(not coroutine.resume(main))
+
+
+-- tests for multiple yield/resume arguments
+
+local function eqtab (t1, t2)
+  assert(#t1 == #t2)
+  for i = 1, #t1 do
+    local v = t1[i]
+    assert(t2[i] == v)
+  end
+end
+
+_G.x = nil   -- declare x
+function foo (a, ...)
+  local x, y = coroutine.running()
+  assert(x == f and y == false)
+  -- next call should not corrupt coroutine (but must fail,
+  -- as it attempts to resume the running coroutine)
+  assert(coroutine.resume(f) == false)
+  assert(coroutine.status(f) == "running")
+  local arg = {...}
+  for i=1,#arg do
+    _G.x = {coroutine.yield(table.unpack(arg[i]))}
+  end
+  return table.unpack(a)
+end
+
+f = coroutine.create(foo)
+assert(type(f) == "thread" and coroutine.status(f) == "suspended")
+assert(string.find(tostring(f), "thread"))
+local s,a,b,c,d
+s,a,b,c,d = coroutine.resume(f, {1,2,3}, {}, {1}, {'a', 'b', 'c'})
+assert(s and a == nil and coroutine.status(f) == "suspended")
+s,a,b,c,d = coroutine.resume(f)
+eqtab(_G.x, {})
+assert(s and a == 1 and b == nil)
+s,a,b,c,d = coroutine.resume(f, 1, 2, 3)
+eqtab(_G.x, {1, 2, 3})
+assert(s and a == 'a' and b == 'b' and c == 'c' and d == nil)
+s,a,b,c,d = coroutine.resume(f, "xuxu")
+eqtab(_G.x, {"xuxu"})
+assert(s and a == 1 and b == 2 and c == 3 and d == nil)
+assert(coroutine.status(f) == "dead")
+s, a = coroutine.resume(f, "xuxu")
+assert(not s and string.find(a, "dead") and coroutine.status(f) == "dead")
+
+
+-- yields in tail calls
+local function foo (i) return coroutine.yield(i) end
+f = coroutine.wrap(function ()
+  for i=1,10 do
+    assert(foo(i) == _G.x)
+  end
+  return 'a'
+end)
+for i=1,10 do _G.x = i; assert(f(i) == i) end
+_G.x = 'xuxu'; assert(f('xuxu') == 'a')
+
+-- recursive
+function pf (n, i)
+  coroutine.yield(n)
+  pf(n*i, i+1)
+end
+
+f = coroutine.wrap(pf)
+local s=1
+for i=1,10 do
+  assert(f(1, 1) == s)
+  s = s*i
+end
+
+-- sieve implemented with co-routines
+
+-- generate all the numbers from 2 to n
+function gen (n)
+  return coroutine.wrap(function ()
+    for i=2,n do coroutine.yield(i) end
+  end)
+end
+
+-- filter the numbers generated by 'g', removing multiples of 'p'
+function filter (p, g)
+  return coroutine.wrap(function ()
+    for n in g do
+      if n%p ~= 0 then coroutine.yield(n) end
+    end
+  end)
+end
+
+-- generate primes up to 20
+local x = gen(20)
+local a = {}
+while 1 do
+  local n = x()
+  if n == nil then break end
+  table.insert(a, n)
+  x = filter(n, x)
+end
+
+-- expect 8 primes and last one is 19
+assert(#a == 8 and a[#a] == 19)
+x, a = nil
+
+
+-- yielding across C boundaries
+
+co = coroutine.wrap(function()
+       coroutine.yield(20)
+       return 30
+     end)
+
+assert(co() == 20)
+assert(co() == 30)
+
+
+local f = function (s, i) return coroutine.yield(i) end
+function f (a, b) a = coroutine.yield(a);  error{a + b} end
+function g(x) return x[1]*2 end
+
+
+-- unyieldable C call
+do
+  local function f (c)
+          return c .. c
+        end
+
+  local co = coroutine.wrap(function (c)
+               local s = string.gsub("a", ".", f)
+               return s
+             end)
+  assert(co() == "aa")
+end
+
+
+-- errors in coroutines
+function foo ()
+  coroutine.yield(3)
+  error(foo)
+end
+
+function goo() foo() end
+x = coroutine.wrap(goo)
+assert(x() == 3)
+x = coroutine.create(goo)
+a,b = coroutine.resume(x)
+assert(a and b == 3)
+a,b = coroutine.resume(x)
+assert(not a and b == foo and coroutine.status(x) == "dead")
+a,b = coroutine.resume(x)
+assert(not a and string.find(b, "dead") and coroutine.status(x) == "dead")
+
+
+-- co-routines x for loop
+function all (a, n, k)
+  if k == 0 then coroutine.yield(a)
+  else
+    for i=1,n do
+      a[k] = i
+      all(a, n, k-1)
+    end
+  end
+end
+
+local a = 0
+for t in coroutine.wrap(function () all({}, 5, 4) end) do
+  a = a+1
+end
+assert(a == 5^4)
+
+
+-- access to locals of collected corroutines
+local C = {}; setmetatable(C, {__mode = "kv"})
+local x = coroutine.wrap (function ()
+            local a = 10
+            local function f () a = a+10; return a end
+            while true do
+              a = a+1
+              coroutine.yield(f)
+            end
+          end)
+
+C[1] = x;
+
+local f = x()
+assert(f() == 21 and x()() == 32 and x() == f)
+x = nil
+collectgarbage()
+assert(C[1] == nil)
+assert(f() == 43 and f() == 53)
+
+
+-- old bug: attempt to resume itself
+
+function co_func (current_co)
+  assert(coroutine.running() == current_co)
+  assert(coroutine.resume(current_co) == false)
+  coroutine.yield(10, 20)
+  assert(coroutine.resume(current_co) == false)
+  coroutine.yield(23)
+  return 10
+end
+
+local co = coroutine.create(co_func)
+local a,b,c = coroutine.resume(co, co)
+assert(a == true and b == 10 and c == 20)
+a,b = coroutine.resume(co, co)
+assert(a == true and b == 23)
+a,b = coroutine.resume(co, co)
+assert(a == true and b == 10)
+assert(coroutine.resume(co, co) == false)
+assert(coroutine.resume(co, co) == false)
+
+
+-- attempt to resume 'normal' coroutine
+local co1, co2
+co1 = coroutine.create(function () return co2() end)
+co2 = coroutine.wrap(function ()
+        assert(coroutine.status(co1) == 'normal')
+        assert(not coroutine.resume(co1))
+        coroutine.yield(3)
+      end)
+
+a,b = coroutine.resume(co1)
+assert(a and b == 3)
+assert(coroutine.status(co1) == 'dead')
+
+
+-- access to locals of erroneous coroutines
+local x = coroutine.create (function ()
+            local a = 10
+            _G.f = function () a=a+1; return a end
+            error('x')
+          end)
+
+assert(not coroutine.resume(x))
+-- overwrite previous position of local `a'
+assert(not coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1))
+assert(_G.f() == 11)
+assert(_G.f() == 12)
+
+
+-- leaving a pending coroutine open
+_X = coroutine.wrap(function ()
+      local a = 10
+      local x = function () a = a+1 end
+      coroutine.yield()
+    end)
+
+_X()
+
+assert(coroutine.running() == main)
+
+
+
+-- testing yields inside metamethods
+
+local mt = {
+  __eq = function(a,b) coroutine.yield(nil, "eq"); return a.x == b.x end,
+  __lt = function(a,b) coroutine.yield(nil, "lt"); return a.x < b.x end,
+  __le = function(a,b) coroutine.yield(nil, "le"); return a - b <= 0 end,
+  __add = function(a,b) coroutine.yield(nil, "add"); return a.x + b.x end,
+  __sub = function(a,b) coroutine.yield(nil, "sub"); return a.x - b.x end,
+  __mod = function(a,b) coroutine.yield(nil, "mod"); return a.x % b.x end,
+  __unm = function(a,b) coroutine.yield(nil, "unm"); return -a.x end,
+
+  __concat = function(a,b)
+               coroutine.yield(nil, "concat");
+               a = type(a) == "table" and a.x or a
+               b = type(b) == "table" and b.x or b
+               return a .. b
+             end,
+  __index = function (t,k) coroutine.yield(nil, "idx"); return t.k[k] end,
+  __newindex = function (t,k,v) coroutine.yield(nil, "nidx"); t.k[k] = v end,
+}
+
+
+local function new (x)
+  return setmetatable({x = x, k = {}}, mt)
+end
+
+
+local a = new(10)
+local b = new(12)
+local c = new"hello"
+
+local function run (f, t)
+  local i = 1
+  local c = coroutine.wrap(f)
+  while true do
+    local res, stat = c()
+    if res then assert(t[i] == nil); return res, t end
+    assert(stat == t[i])
+    i = i + 1
+  end
+end
+
+
+assert(run(function () if (a>=b) then return '>=' else return '<' end end,
+       {"le", "sub"}) == "<")
+-- '<=' using '<'
+mt.__le = nil
+assert(run(function () if (a<=b) then return '<=' else return '>' end end,
+       {"lt"}) == "<=")
+assert(run(function () if (a==b) then return '==' else return '~=' end end,
+       {"eq"}) == "~=")
+
+assert(run(function () return a % b end, {"mod"}) == 10)
+
+assert(run(function () return a..b end, {"concat"}) == "1012")
+
+assert(run(function() return a .. b .. c .. a end,
+       {"concat", "concat", "concat"}) == "1012hello10")
+
+assert(run(function() return "a" .. "b" .. a .. "c" .. c .. b .. "x" end,
+       {"concat", "concat", "concat"}) == "ab10chello12x")
+
+
+-- testing yields inside 'for' iterators
+
+local f = function (s, i)
+      if i%2 == 0 then coroutine.yield(nil, "for") end
+      if i < s then return i + 1 end
+    end
+
+assert(run(function ()
+             local s = 0
+             for i in f, 4, 0 do s = s + i end
+             return s
+           end, {"for", "for", "for"}) == 10)
+
+
+return "OK"
diff --git a/tests/zfs-tests/tests/functional/channel_program/lua_core/tst.lib_strings.lua b/tests/zfs-tests/tests/functional/channel_program/lua_core/tst.lib_strings.lua
new file mode 100644 (file)
index 0000000..1725fd1
--- /dev/null
@@ -0,0 +1,241 @@
+--[[
+--*****************************************************************************
+--* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
+--*
+--* Permission is hereby granted, free of charge, to any person obtaining
+--* a copy of this software and associated documentation files (the
+--* "Software"), to deal in the Software without restriction, including
+--* without limitation the rights to use, copy, modify, merge, publish,
+--* distribute, sublicense, and/or sell copies of the Software, and to
+--* permit persons to whom the Software is furnished to do so, subject to
+--* the following conditions:
+--*
+--* The above copyright notice and this permission notice shall be
+--* included in all copies or substantial portions of the Software.
+--*
+--* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+--* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+--* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+--* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+--* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+--* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+--* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+--*****************************************************************************
+--]]
+
+-- testing string library
+
+local maxi, mini = 0x7fffffffffffffff, 0x8000000000000000
+
+-- testing string.sub
+assert(string.sub("123456789",2,4) == "234")
+assert(string.sub("123456789",7) == "789")
+assert(string.sub("123456789",7,6) == "")
+assert(string.sub("123456789",7,7) == "7")
+assert(string.sub("123456789",0,0) == "")
+assert(string.sub("123456789",-10,10) == "123456789")
+assert(string.sub("123456789",1,9) == "123456789")
+assert(string.sub("123456789",-10,-20) == "")
+assert(string.sub("123456789",-1) == "9")
+assert(string.sub("123456789",-4) == "6789")
+assert(string.sub("123456789",-6, -4) == "456")
+assert(string.sub("123456789", mini, -4) == "123456")
+assert(string.sub("123456789", mini, maxi) == "123456789")
+assert(string.sub("123456789", mini, mini) == "")
+assert(string.sub("\000123456789",3,5) == "234")
+assert(("\000123456789"):sub(8) == "789")
+
+-- testing string.find
+assert(string.find("123456789", "345") == 3)
+a,b = string.find("123456789", "345")
+assert(string.sub("123456789", a, b) == "345")
+assert(string.find("1234567890123456789", "345", 3) == 3)
+assert(string.find("1234567890123456789", "345", 4) == 13)
+assert(string.find("1234567890123456789", "346", 4) == nil)
+assert(string.find("1234567890123456789", ".45", -9) == 13)
+assert(string.find("abcdefg", "\0", 5, 1) == nil)
+assert(string.find("", "") == 1)
+assert(string.find("", "", 1) == 1)
+assert(not string.find("", "", 2))
+assert(string.find('', 'aaa', 1) == nil)
+assert(('alo(.)alo'):find('(.)', 1, 1) == 4)
+
+assert(string.len("") == 0)
+assert(string.len("\0\0\0") == 3)
+assert(string.len("1234567890") == 10)
+
+assert(#"" == 0)
+assert(#"\0\0\0" == 3)
+assert(#"1234567890" == 10)
+
+-- testing string.byte/string.char
+assert(string.byte("a") == 97)
+assert(string.byte("\xe4") > 127)
+assert(string.byte(string.char(255)) == 255)
+assert(string.byte(string.char(0)) == 0)
+assert(string.byte("\0") == 0)
+assert(string.byte("\0\0alo\0x", -1) == string.byte('x'))
+assert(string.byte("ba", 2) == 97)
+assert(string.byte("\n\n", 2, -1) == 10)
+assert(string.byte("\n\n", 2, 2) == 10)
+assert(string.byte("") == nil)
+assert(string.byte("hi", -3) == nil)
+assert(string.byte("hi", 3) == nil)
+assert(string.byte("hi", 9, 10) == nil)
+assert(string.byte("hi", 2, 1) == nil)
+assert(string.char() == "")
+assert(string.char(0, 255, 0) == "\0\255\0")
+assert(string.char(0, string.byte("\xe4"), 0) == "\0\xe4\0")
+assert(string.char(string.byte("\xe4l\0\195\179u", 1, -1)) == "\xe4l\0\195\179u")
+assert(string.char(string.byte("\xe4l\0\195\179u", 1, 0)) == "")
+assert(string.char(string.byte("\xe4l\0\195\179u", -10, 100)) == "\xe4l\0\195\179u")
+
+assert(string.upper("ab\0c") == "AB\0C")
+assert(string.lower("\0ABCc%$") == "\0abcc%$")
+assert(string.rep('teste', 0) == '')
+assert(string.rep('t\195\169s\00t\195\170', 2) == 't\195\169s\0t\195\170t\195\169s\000t\195\170')
+assert(string.rep('', 10) == '')
+
+-- repetitions with separator
+assert(string.rep('teste', 0, 'xuxu') == '')
+assert(string.rep('teste', 1, 'xuxu') == 'teste')
+assert(string.rep('\1\0\1', 2, '\0\0') == '\1\0\1\0\0\1\0\1')
+assert(string.rep('', 10, '.') == string.rep('.', 9))
+
+assert(string.reverse"" == "")
+assert(string.reverse"\0\1\2\3" == "\3\2\1\0")
+assert(string.reverse"\0001234" == "4321\0")
+
+for i=0,30 do assert(string.len(string.rep('a', i)) == i) end
+
+
+x = '"\195\174lo"\n\\'
+assert(string.format('%q%s', x, x) == '"\\"\195\174lo\\"\\\n\\\\""\195\174lo"\n\\')
+assert(string.format('%q', "\0") == [["\0"]])
+x = "\0\1\0023\5\0009"
+assert(string.format("\0%c\0%c%x\0", string.byte("\xe4"), string.byte("b"), 140) ==
+              "\0\xe4\0b8c\0")
+assert(string.format('') == "")
+assert(string.format("%c",34)..string.format("%c",48)..string.format("%c",90)..string.format("%c",100) ==
+       string.format("%c%c%c%c", 34, 48, 90, 100))
+assert(string.format("%s\0 is not \0%s", 'not be', 'be') == 'not be\0 is not \0be')
+assert(string.format("%%%d %010d", 10, 23) == "%10 0000000023")
+x = string.format('"%-50s"', 'a')
+assert(#x == 52)
+assert(string.sub(x, 1, 4) == '"a  ')
+
+assert(string.format("-%.20s.20s", string.rep("%", 2000)) ==
+                     "-"..string.rep("%", 20)..".20s")
+assert(string.format('"-%20s.20s"', string.rep("%", 2000)) ==
+       string.format("%q", "-"..string.rep("%", 2000)..".20s"))
+
+-- format x tostring
+assert(string.format("%s %s", nil, true) == "nil true")
+assert(string.format("%s %.4s", false, true) == "false true")
+assert(string.format("%.3s %.3s", false, true) == "fal tru")
+
+
+-- testing large numbers for format
+do
+  local max, min = 0x7fffffff, -0x80000000    -- "large" for 32 bits
+  assert(string.sub(string.format("%8x", -1), -8) == "ffffffff")
+  assert(string.format("%x", max) == "7fffffff")
+  assert(string.sub(string.format("%x", min), -8) == "80000000")
+  assert(string.format("%d", max) ==  "2147483647")
+  assert(string.format("%d", min) == "-2147483648")
+  assert(string.format("%u", 0xffffffff) == "4294967295")
+  assert(string.format("%o", 0xABCD) == "125715")
+
+  max, min = 0x7fffffffffffffff, -0x8000000000000000
+  assert(string.format("0x%8X", 0x8f000003) == "0x8F000003")
+  assert(string.format("%d", 2^53) == "9007199254740992")
+  assert(string.format("%x", max) == "7fffffffffffffff")
+  assert(string.format("%x", min) == "8000000000000000")
+  assert(string.format("%d", max) ==  "9223372036854775807")
+  assert(string.format("%d", min) == "-9223372036854775808")
+end
+
+
+assert(table.concat{} == "")
+assert(table.concat({}, 'x') == "")
+assert(table.concat({'\0', '\0\1', '\0\1\2'}, '.\0.') == "\0.\0.\0\1.\0.\0\1\2")
+local a = {}; for i=1,300 do a[i] = "xuxu" end
+assert(table.concat(a, "123").."123" == string.rep("xuxu123", 300))
+assert(table.concat(a, "b", 20, 20) == "xuxu")
+assert(table.concat(a, "", 20, 21) == "xuxuxuxu")
+assert(table.concat(a, "x", 22, 21) == "")
+assert(table.concat(a, "3", 299) == "xuxu3xuxu")
+assert(table.concat({}, "x", 2^31-1, 2^31-2) == "")
+assert(table.concat({}, "x", -2^31+1, -2^31) == "")
+assert(table.concat({}, "x", 2^31-1, -2^31) == "")
+assert(table.concat({[2^31-1] = "alo"}, "x", 2^31-1, 2^31-1) == "alo")
+
+a = {"a","b","c"}
+assert(table.concat(a, ",", 1, 0) == "")
+assert(table.concat(a, ",", 1, 1) == "a")
+assert(table.concat(a, ",", 1, 2) == "a,b")
+assert(table.concat(a, ",", 2) == "b,c")
+assert(table.concat(a, ",", 3) == "c")
+assert(table.concat(a, ",", 4) == "")
+
+
+-- tests for gmatch
+local a = 0
+for i in string.gmatch('abcde', '()') do assert(i == a+1); a=i end
+assert(a==6)
+
+t = {n=0}
+for w in string.gmatch("first second word", "%w+") do
+      t.n=t.n+1; t[t.n] = w
+end
+assert(t[1] == "first" and t[2] == "second" and t[3] == "word")
+
+t = {3, 6, 9}
+for i in string.gmatch ("xuxx uu ppar r", "()(.)%2") do
+  assert(i == table.remove(t, 1))
+end
+assert(#t == 0)
+
+t = {}
+for i,j in string.gmatch("13 14 10 = 11, 15= 16, 22=23", "(%d+)%s*=%s*(%d+)") do
+  t[i] = j
+end
+a = 0
+for k,v in pairs(t) do assert(k+1 == v+0); a=a+1 end
+assert(a == 3)
+
+
+-- tests for gsub
+function f1(s, p)
+  p = string.gsub(p, "%%([0-9])", function (s) return "%" .. (s+1) end)
+  p = string.gsub(p, "^(^?)", "%1()", 1)
+  p = string.gsub(p, "($?)$", "()%1", 1)
+  local t = {string.match(s, p)}
+  return string.sub(s, t[1], t[#t] - 1)
+end
+
+assert(f1('alo alx 123 b\0o b\0o', '(..*) %1') == "b\0o b\0o")
+assert(f1('axz123= 4= 4 34', '(.+)=(.*)=%2 %1') == '3= 4= 4 3')
+assert(f1('=======', '^(=*)=%1$') == '=======')
+
+-- gsub with tables
+assert(string.gsub("alo alo", ".", {}) == "alo alo")
+assert(string.gsub("alo alo", "(.)", {a="AA", l=""}) == "AAo AAo")
+assert(string.gsub("alo alo", "(.).", {a="AA", l="K"}) == "AAo AAo")
+assert(string.gsub("alo alo", "((.)(.?))", {al="AA", o=false}) == "AAo AAo")
+
+assert(string.gsub("alo alo", "().", {2,5,6}) == "256 alo")
+
+t = {}; setmetatable(t, {__index = function (t,s) return string.upper(s) end})
+assert(string.gsub("a alo b hi", "%w%w+", t) == "a ALO b HI")
+
+
+-- tests for match
+assert(string.match('==========', '^([=]*)=%1$') == nil)
+assert(string.match("alo xyzK", "(%w+)K") == "xyz")
+assert(string.match("254 K", "(%d*)K") == "")
+assert(string.match("alo ", "(%w*)$") == "")
+assert(string.match("alo ", "(%w+)$") == nil)
+assert(string.match("ab\0\1\2c", "[\0-\2]+") == "\0\1\2")
+
+return "OK"
diff --git a/tests/zfs-tests/tests/functional/channel_program/lua_core/tst.lib_table.lua b/tests/zfs-tests/tests/functional/channel_program/lua_core/tst.lib_table.lua
new file mode 100644 (file)
index 0000000..500117b
--- /dev/null
@@ -0,0 +1,252 @@
+--[[
+--*****************************************************************************
+--* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
+--*
+--* Permission is hereby granted, free of charge, to any person obtaining
+--* a copy of this software and associated documentation files (the
+--* "Software"), to deal in the Software without restriction, including
+--* without limitation the rights to use, copy, modify, merge, publish,
+--* distribute, sublicense, and/or sell copies of the Software, and to
+--* permit persons to whom the Software is furnished to do so, subject to
+--* the following conditions:
+--*
+--* The above copyright notice and this permission notice shall be
+--* included in all copies or substantial portions of the Software.
+--*
+--* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+--* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+--* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+--* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+--* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+--* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+--* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+--*****************************************************************************
+--]]
+
+-- testing table library
+
+-- workaround missing pcall in zfs lua implementation
+local function tuple(...)
+  return {n=select('#', ...), ...}
+end
+
+function pcall(f, ...)
+  local co = coroutine.create(f)
+  local res = tuple(coroutine.resume(co, ...))
+  if res[1] and coroutine.status(co) == "suspended" then
+    res[1] = false
+  end
+  return table.unpack(res, 1, res.n)
+end
+
+
+-- workaround missing math lib in zfs lua implementation
+local A1, A2 = 727595, 798405  -- 5^17=D20*A1+A2
+local D20, D40 = 1048576, 1099511627776  -- 2^20, 2^40
+local X1, X2 = 0, 1
+function rand()
+    local U = X2*A2
+    local V = (X1*A2 + X2*A1) % D20
+    V = (V*D20 + U) % D40
+    X1 = V/D20
+    X2 = V - X1*D20
+    return V*100/D40
+end
+
+
+-- testing unpack
+
+local unpack = table.unpack
+
+local x,y,z,a,n
+a = {}; lim = 2000
+for i=1, lim do a[i]=i end
+assert(select(lim, unpack(a)) == lim and select('#', unpack(a)) == lim)
+x = unpack(a)
+assert(x == 1)
+x = {unpack(a)}
+assert(#x == lim and x[1] == 1 and x[lim] == lim)
+x = {unpack(a, lim-2)}
+assert(#x == 3 and x[1] == lim-2 and x[3] == lim)
+x = {unpack(a, 10, 6)}
+assert(next(x) == nil)   -- no elements
+x = {unpack(a, 11, 10)}
+assert(next(x) == nil)   -- no elements
+x,y = unpack(a, 10, 10)
+assert(x == 10 and y == nil)
+x,y,z = unpack(a, 10, 11)
+assert(x == 10 and y == 11 and z == nil)
+a,x = unpack{1}
+assert(a==1 and x==nil)
+a,x = unpack({1,2}, 1, 1)
+assert(a==1 and x==nil)
+
+if not _no32 then
+  assert(not pcall(unpack, {}, 0, 2^31-1))
+  assert(not pcall(unpack, {}, 1, 2^31-1))
+  assert(not pcall(unpack, {}, -(2^31), 2^31-1))
+  assert(not pcall(unpack, {}, -(2^31 - 1), 2^31-1))
+  assert(pcall(unpack, {}, 2^31-1, 0))
+  assert(pcall(unpack, {}, 2^31-1, 1))
+  pcall(unpack, {}, 1, 2^31)
+  a, b = unpack({[2^31-1] = 20}, 2^31-1, 2^31-1)
+  assert(a == 20 and b == nil)
+  a, b = unpack({[2^31-1] = 20}, 2^31-2, 2^31-1)
+  assert(a == nil and b == 20)
+end
+
+-- testing pack
+
+a = table.pack()
+assert(a[1] == nil and a.n == 0)
+
+a = table.pack(table)
+assert(a[1] == table and a.n == 1)
+
+a = table.pack(nil, nil, nil, nil)
+assert(a[1] == nil and a.n == 4)
+
+
+-- testing sort
+
+
+-- test checks for invalid order functions
+local function check (t)
+  local function f(a, b) assert(a and b); return true end
+  local s, e = pcall(table.sort, t, f)
+  assert(not s and e:find("invalid order function"))
+end
+
+check{1,2,3,4}
+check{1,2,3,4,5}
+check{1,2,3,4,5,6}
+
+
+function check (a, f)
+  f = f or function (x,y) return x<y end;
+  for n = #a, 2, -1 do
+    assert(not f(a[n], a[n-1]))
+  end
+end
+
+a = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
+     "Oct", "Nov", "Dec"}
+
+table.sort(a)
+check(a)
+
+function perm (s, n)
+  n = n or #s
+  if n == 1 then
+    local t = {unpack(s)}
+    table.sort(t)
+    check(t)
+  else
+    for i = 1, n do
+      s[i], s[n] = s[n], s[i]
+      perm(s, n - 1)
+      s[i], s[n] = s[n], s[i]
+    end
+  end
+end
+
+perm{}
+perm{1}
+perm{1,2}
+perm{1,2,3}
+perm{1,2,3,4}
+perm{2,2,3,4}
+perm{1,2,3,4,5}
+perm{1,2,3,3,5}
+perm{1,2,3,4,5,6}
+perm{2,2,3,3,5,6}
+
+limit = 5000
+
+a = {}
+for i=1,limit do
+  a[i] = rand()
+end
+
+table.sort(a)
+check(a)
+
+table.sort(a)
+check(a)
+
+a = {}
+for i=1,limit do
+  a[i] = rand()
+end
+
+i=0
+table.sort(a, function(x,y) i=i+1; return y<x end)
+check(a, function(x,y) return y<x end)
+
+
+table.sort{}  -- empty array
+
+for i=1,limit do a[i] = false end
+table.sort(a, function(x,y) return nil end)
+check(a, function(x,y) return nil end)
+for i,v in pairs(a) do assert(not v or i=='n' and v==limit) end
+
+A = {"álo", "\0first :-)", "alo", "then this one", "45", "and a new"}
+table.sort(A)
+check(A)
+
+tt = {__lt = function (a,b) return a.val < b.val end}
+a = {}
+for i=1,10 do  a[i] = {val=rand(100)}; setmetatable(a[i], tt); end
+table.sort(a)
+check(a, tt.__lt)
+check(a)
+
+
+-- test remove
+local function test (a)
+  table.insert(a, 10); table.insert(a, 2, 20);
+  table.insert(a, 1, -1); table.insert(a, 40);
+  table.insert(a, #a+1, 50)
+  table.insert(a, 2, -2)
+  assert(table.remove(a,1) == -1)
+  assert(table.remove(a,1) == -2)
+  assert(table.remove(a,1) == 10)
+  assert(table.remove(a,1) == 20)
+  assert(table.remove(a,1) == 40)
+  assert(table.remove(a,1) == 50)
+  assert(table.remove(a,1) == nil)
+end
+
+a = {n=0, [-7] = "ban"}
+test(a)
+assert(a.n == 0 and a[-7] == "ban")
+
+a = {[-7] = "ban"};
+test(a)
+assert(a.n == nil and #a == 0 and a[-7] == "ban")
+
+
+table.insert(a, 1, 10); table.insert(a, 1, 20); table.insert(a, 1, -1)
+assert(table.remove(a) == 10)
+assert(table.remove(a) == 20)
+assert(table.remove(a) == -1)
+
+a = {'c', 'd'}
+table.insert(a, 3, 'a')
+table.insert(a, 'b')
+assert(table.remove(a, 1) == 'c')
+assert(table.remove(a, 1) == 'd')
+assert(table.remove(a, 1) == 'a')
+assert(table.remove(a, 1) == 'b')
+assert(#a == 0 and a.n == nil)
+
+a = {10,20,30,40}
+assert(a[#a] == 40)
+assert(table.remove(a, #a) == 40)
+assert(a[#a] == 30)
+assert(table.remove(a, 2) == 20)
+assert(a[#a] == 30 and #a == 2)
+
+
+return "OK"
diff --git a/tests/zfs-tests/tests/functional/channel_program/lua_core/tst.libraries.ksh b/tests/zfs-tests/tests/functional/channel_program/lua_core/tst.libraries.ksh
new file mode 100755 (executable)
index 0000000..71afabd
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/ksh -p
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2017 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/channel_program/channel_common.kshlib
+
+verify_runnable "global"
+arch=$(uname -m)
+
+if [[ "$arch" == "sparc64" ]]; then
+       log_note "Skipping lib_base and lib_coroutine on sparc64 to avoid stack overflow"
+else
+       log_must_program $TESTPOOL $ZCP_ROOT/lua_core/tst.lib_base.lua
+       log_must_program $TESTPOOL $ZCP_ROOT/lua_core/tst.lib_coroutine.lua
+fi
+log_must_program $TESTPOOL $ZCP_ROOT/lua_core/tst.lib_strings.lua
+log_must_program -m 40000000 $TESTPOOL $ZCP_ROOT/lua_core/tst.lib_table.lua
+
+log_pass "lua libraries work correctly."