github.com/erikdubbelboer/gopher-lua@v0.0.0-20160512044044-e68f0dc85040/state_test.go (about)

     1  package lua
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  )
     7  
     8  func TestCallStackOverflow(t *testing.T) {
     9  	L := NewState(Options{
    10  		CallStackSize: 3,
    11  	})
    12  	defer L.Close()
    13  	errorIfScriptNotFail(t, L, `
    14      local function a()
    15      end
    16      local function b()
    17        a()
    18      end
    19      local function c()
    20        print(_printregs())
    21        b()
    22      end
    23      c()
    24      `, "stack overflow")
    25  }
    26  
    27  func TestSkipOpenLibs(t *testing.T) {
    28  	L := NewState(Options{SkipOpenLibs: true})
    29  	defer L.Close()
    30  	errorIfScriptNotFail(t, L, `print("")`,
    31  		"attempt to call a non-function object")
    32  	L2 := NewState()
    33  	defer L2.Close()
    34  	errorIfScriptFail(t, L2, `print("")`)
    35  }
    36  
    37  func TestGetAndReplace(t *testing.T) {
    38  	L := NewState()
    39  	defer L.Close()
    40  	L.Push(LString("a"))
    41  	L.Replace(1, LString("b"))
    42  	L.Replace(0, LString("c"))
    43  	errorIfNotEqual(t, LNil, L.Get(0))
    44  	errorIfNotEqual(t, LNil, L.Get(-10))
    45  	errorIfNotEqual(t, L.Env, L.Get(EnvironIndex))
    46  	errorIfNotEqual(t, LString("b"), L.Get(1))
    47  	L.Push(LString("c"))
    48  	L.Push(LString("d"))
    49  	L.Replace(-2, LString("e"))
    50  	errorIfNotEqual(t, LString("e"), L.Get(-2))
    51  	registry := L.NewTable()
    52  	L.Replace(RegistryIndex, registry)
    53  	L.G.Registry = registry
    54  	errorIfGFuncNotFail(t, L, func(L *LState) int {
    55  		L.Replace(RegistryIndex, LNil)
    56  		return 0
    57  	}, "registry must be a table")
    58  	errorIfGFuncFail(t, L, func(L *LState) int {
    59  		env := L.NewTable()
    60  		L.Replace(EnvironIndex, env)
    61  		errorIfNotEqual(t, env, L.Get(EnvironIndex))
    62  		return 0
    63  	})
    64  	errorIfGFuncNotFail(t, L, func(L *LState) int {
    65  		L.Replace(EnvironIndex, LNil)
    66  		return 0
    67  	}, "environment must be a table")
    68  	errorIfGFuncFail(t, L, func(L *LState) int {
    69  		gbl := L.NewTable()
    70  		L.Replace(GlobalsIndex, gbl)
    71  		errorIfNotEqual(t, gbl, L.G.Global)
    72  		return 0
    73  	})
    74  	errorIfGFuncNotFail(t, L, func(L *LState) int {
    75  		L.Replace(GlobalsIndex, LNil)
    76  		return 0
    77  	}, "_G must be a table")
    78  
    79  	L2 := NewState()
    80  	defer L2.Close()
    81  	clo := L2.NewClosure(func(L2 *LState) int {
    82  		L2.Replace(UpvalueIndex(1), LNumber(3))
    83  		errorIfNotEqual(t, LNumber(3), L2.Get(UpvalueIndex(1)))
    84  		return 0
    85  	}, LNumber(1), LNumber(2))
    86  	L2.SetGlobal("clo", clo)
    87  	errorIfScriptFail(t, L2, `clo()`)
    88  }
    89  
    90  func TestRemove(t *testing.T) {
    91  	L := NewState()
    92  	defer L.Close()
    93  	L.Push(LString("a"))
    94  	L.Push(LString("b"))
    95  	L.Push(LString("c"))
    96  
    97  	L.Remove(4)
    98  	errorIfNotEqual(t, LString("a"), L.Get(1))
    99  	errorIfNotEqual(t, LString("b"), L.Get(2))
   100  	errorIfNotEqual(t, LString("c"), L.Get(3))
   101  	errorIfNotEqual(t, 3, L.GetTop())
   102  
   103  	L.Remove(3)
   104  	errorIfNotEqual(t, LString("a"), L.Get(1))
   105  	errorIfNotEqual(t, LString("b"), L.Get(2))
   106  	errorIfNotEqual(t, LNil, L.Get(3))
   107  	errorIfNotEqual(t, 2, L.GetTop())
   108  	L.Push(LString("c"))
   109  
   110  	L.Remove(-10)
   111  	errorIfNotEqual(t, LString("a"), L.Get(1))
   112  	errorIfNotEqual(t, LString("b"), L.Get(2))
   113  	errorIfNotEqual(t, LString("c"), L.Get(3))
   114  	errorIfNotEqual(t, 3, L.GetTop())
   115  
   116  	L.Remove(2)
   117  	errorIfNotEqual(t, LString("a"), L.Get(1))
   118  	errorIfNotEqual(t, LString("c"), L.Get(2))
   119  	errorIfNotEqual(t, LNil, L.Get(3))
   120  	errorIfNotEqual(t, 2, L.GetTop())
   121  }
   122  
   123  func TestToInt(t *testing.T) {
   124  	L := NewState()
   125  	defer L.Close()
   126  	L.Push(LNumber(10))
   127  	L.Push(LString("99.9"))
   128  	L.Push(L.NewTable())
   129  	errorIfNotEqual(t, 10, L.ToInt(1))
   130  	errorIfNotEqual(t, 99, L.ToInt(2))
   131  	errorIfNotEqual(t, 0, L.ToInt(3))
   132  }
   133  
   134  func TestToInt64(t *testing.T) {
   135  	L := NewState()
   136  	defer L.Close()
   137  	L.Push(LNumber(10))
   138  	L.Push(LString("99.9"))
   139  	L.Push(L.NewTable())
   140  	errorIfNotEqual(t, int64(10), L.ToInt64(1))
   141  	errorIfNotEqual(t, int64(99), L.ToInt64(2))
   142  	errorIfNotEqual(t, int64(0), L.ToInt64(3))
   143  }
   144  
   145  func TestToNumber(t *testing.T) {
   146  	L := NewState()
   147  	defer L.Close()
   148  	L.Push(LNumber(10))
   149  	L.Push(LString("99.9"))
   150  	L.Push(L.NewTable())
   151  	errorIfNotEqual(t, LNumber(10), L.ToNumber(1))
   152  	errorIfNotEqual(t, LNumber(99.9), L.ToNumber(2))
   153  	errorIfNotEqual(t, LNumber(0), L.ToNumber(3))
   154  }
   155  
   156  func TestToString(t *testing.T) {
   157  	L := NewState()
   158  	defer L.Close()
   159  	L.Push(LNumber(10))
   160  	L.Push(LString("99.9"))
   161  	L.Push(L.NewTable())
   162  	errorIfNotEqual(t, "10", L.ToString(1))
   163  	errorIfNotEqual(t, "99.9", L.ToString(2))
   164  	errorIfNotEqual(t, "", L.ToString(3))
   165  }
   166  
   167  func TestToTable(t *testing.T) {
   168  	L := NewState()
   169  	defer L.Close()
   170  	L.Push(LNumber(10))
   171  	L.Push(LString("99.9"))
   172  	L.Push(L.NewTable())
   173  	errorIfFalse(t, L.ToTable(1) == nil, "index 1 must be nil")
   174  	errorIfFalse(t, L.ToTable(2) == nil, "index 2 must be nil")
   175  	errorIfNotEqual(t, L.Get(3), L.ToTable(3))
   176  }
   177  
   178  func TestToFunction(t *testing.T) {
   179  	L := NewState()
   180  	defer L.Close()
   181  	L.Push(LNumber(10))
   182  	L.Push(LString("99.9"))
   183  	L.Push(L.NewFunction(func(L *LState) int { return 0 }))
   184  	errorIfFalse(t, L.ToFunction(1) == nil, "index 1 must be nil")
   185  	errorIfFalse(t, L.ToFunction(2) == nil, "index 2 must be nil")
   186  	errorIfNotEqual(t, L.Get(3), L.ToFunction(3))
   187  }
   188  
   189  func TestToUserData(t *testing.T) {
   190  	L := NewState()
   191  	defer L.Close()
   192  	L.Push(LNumber(10))
   193  	L.Push(LString("99.9"))
   194  	L.Push(L.NewUserData())
   195  	errorIfFalse(t, L.ToUserData(1) == nil, "index 1 must be nil")
   196  	errorIfFalse(t, L.ToUserData(2) == nil, "index 2 must be nil")
   197  	errorIfNotEqual(t, L.Get(3), L.ToUserData(3))
   198  }
   199  
   200  func TestToChannel(t *testing.T) {
   201  	L := NewState()
   202  	defer L.Close()
   203  	L.Push(LNumber(10))
   204  	L.Push(LString("99.9"))
   205  	var ch chan LValue
   206  	L.Push(LChannel(ch))
   207  	errorIfFalse(t, L.ToChannel(1) == nil, "index 1 must be nil")
   208  	errorIfFalse(t, L.ToChannel(2) == nil, "index 2 must be nil")
   209  	errorIfNotEqual(t, ch, L.ToChannel(3))
   210  }
   211  
   212  func TestObjLen(t *testing.T) {
   213  	L := NewState()
   214  	defer L.Close()
   215  	errorIfNotEqual(t, 3, L.ObjLen(LString("abc")))
   216  	tbl := L.NewTable()
   217  	tbl.Append(LTrue)
   218  	tbl.Append(LTrue)
   219  	errorIfNotEqual(t, 2, L.ObjLen(tbl))
   220  	mt := L.NewTable()
   221  	L.SetField(mt, "__len", L.NewFunction(func(L *LState) int {
   222  		tbl := L.CheckTable(1)
   223  		L.Push(LNumber(tbl.Len() + 1))
   224  		return 1
   225  	}))
   226  	L.SetMetatable(tbl, mt)
   227  	errorIfNotEqual(t, 3, L.ObjLen(tbl))
   228  	errorIfNotEqual(t, 0, L.ObjLen(LNumber(10)))
   229  }
   230  
   231  func TestConcat(t *testing.T) {
   232  	L := NewState()
   233  	defer L.Close()
   234  	errorIfNotEqual(t, "a1c", L.Concat(LString("a"), LNumber(1), LString("c")))
   235  }
   236  
   237  func TestPCall(t *testing.T) {
   238  	L := NewState()
   239  	defer L.Close()
   240  	L.Register("f1", func(L *LState) int {
   241  		panic("panic!")
   242  		return 0
   243  	})
   244  	errorIfScriptNotFail(t, L, `f1()`, "panic!")
   245  	L.Push(L.GetGlobal("f1"))
   246  	err := L.PCall(0, 0, L.NewFunction(func(L *LState) int {
   247  		L.Push(LString("by handler"))
   248  		return 1
   249  	}))
   250  	errorIfFalse(t, strings.Contains(err.Error(), "by handler"), "")
   251  
   252  	err = L.PCall(0, 0, L.NewFunction(func(L *LState) int {
   253  		L.RaiseError("error!")
   254  		return 1
   255  	}))
   256  	errorIfFalse(t, strings.Contains(err.Error(), "error!"), "")
   257  
   258  	err = L.PCall(0, 0, L.NewFunction(func(L *LState) int {
   259  		panic("panicc!")
   260  		return 1
   261  	}))
   262  	errorIfFalse(t, strings.Contains(err.Error(), "panicc!"), "")
   263  }
   264  
   265  func TestCoroutineApi1(t *testing.T) {
   266  	L := NewState()
   267  	defer L.Close()
   268  	co := L.NewThread()
   269  	errorIfScriptFail(t, L, `
   270        function coro(v)
   271          assert(v == 10)
   272          local ret1, ret2 = coroutine.yield(1,2,3)
   273          assert(ret1 == 11)
   274          assert(ret2 == 12)
   275          coroutine.yield(4)
   276          return 5
   277        end
   278      `)
   279  	fn := L.GetGlobal("coro").(*LFunction)
   280  	st, err, values := L.Resume(co, fn, LNumber(10))
   281  	errorIfNotEqual(t, ResumeYield, st)
   282  	errorIfNotNil(t, err)
   283  	errorIfNotEqual(t, 3, len(values))
   284  	errorIfNotEqual(t, LNumber(1), values[0].(LNumber))
   285  	errorIfNotEqual(t, LNumber(2), values[1].(LNumber))
   286  	errorIfNotEqual(t, LNumber(3), values[2].(LNumber))
   287  
   288  	st, err, values = L.Resume(co, fn, LNumber(11), LNumber(12))
   289  	errorIfNotEqual(t, ResumeYield, st)
   290  	errorIfNotNil(t, err)
   291  	errorIfNotEqual(t, 1, len(values))
   292  	errorIfNotEqual(t, LNumber(4), values[0].(LNumber))
   293  
   294  	st, err, values = L.Resume(co, fn)
   295  	errorIfNotEqual(t, ResumeOK, st)
   296  	errorIfNotNil(t, err)
   297  	errorIfNotEqual(t, 1, len(values))
   298  	errorIfNotEqual(t, LNumber(5), values[0].(LNumber))
   299  
   300  	L.Register("myyield", func(L *LState) int {
   301  		return L.Yield(L.ToNumber(1))
   302  	})
   303  	errorIfScriptFail(t, L, `
   304        function coro_error()
   305          coroutine.yield(1,2,3)
   306          myyield(4)
   307          assert(false, "--failed--")
   308        end
   309      `)
   310  	fn = L.GetGlobal("coro_error").(*LFunction)
   311  	co = L.NewThread()
   312  	st, err, values = L.Resume(co, fn)
   313  	errorIfNotEqual(t, ResumeYield, st)
   314  	errorIfNotNil(t, err)
   315  	errorIfNotEqual(t, 3, len(values))
   316  	errorIfNotEqual(t, LNumber(1), values[0].(LNumber))
   317  	errorIfNotEqual(t, LNumber(2), values[1].(LNumber))
   318  	errorIfNotEqual(t, LNumber(3), values[2].(LNumber))
   319  
   320  	st, err, values = L.Resume(co, fn)
   321  	errorIfNotEqual(t, ResumeYield, st)
   322  	errorIfNotNil(t, err)
   323  	errorIfNotEqual(t, 1, len(values))
   324  	errorIfNotEqual(t, LNumber(4), values[0].(LNumber))
   325  
   326  	st, err, values = L.Resume(co, fn)
   327  	errorIfNotEqual(t, ResumeError, st)
   328  	errorIfNil(t, err)
   329  	errorIfFalse(t, strings.Contains(err.Error(), "--failed--"), "error message must be '--failed--'")
   330  	st, err, values = L.Resume(co, fn)
   331  	errorIfNotEqual(t, ResumeError, st)
   332  	errorIfNil(t, err)
   333  	errorIfFalse(t, strings.Contains(err.Error(), "can not resume a dead thread"), "can not resume a dead thread")
   334  
   335  }