mirror of https://github.com/tidwall/tile38.git
262 lines
5.9 KiB
Go
262 lines
5.9 KiB
Go
|
package lua
|
||
|
|
||
|
import (
|
||
|
"reflect"
|
||
|
"sync"
|
||
|
"testing"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
func TestChannelMake(t *testing.T) {
|
||
|
L := NewState()
|
||
|
defer L.Close()
|
||
|
errorIfScriptFail(t, L, `
|
||
|
ch = channel.make()
|
||
|
`)
|
||
|
obj := L.GetGlobal("ch")
|
||
|
ch, ok := obj.(LChannel)
|
||
|
errorIfFalse(t, ok, "channel expected")
|
||
|
errorIfNotEqual(t, 0, reflect.ValueOf(ch).Cap())
|
||
|
close(ch)
|
||
|
|
||
|
errorIfScriptFail(t, L, `
|
||
|
ch = channel.make(10)
|
||
|
`)
|
||
|
obj = L.GetGlobal("ch")
|
||
|
ch, _ = obj.(LChannel)
|
||
|
errorIfNotEqual(t, 10, reflect.ValueOf(ch).Cap())
|
||
|
close(ch)
|
||
|
}
|
||
|
|
||
|
func TestChannelSelectError(t *testing.T) {
|
||
|
L := NewState()
|
||
|
defer L.Close()
|
||
|
errorIfScriptFail(t, L, `ch = channel.make()`)
|
||
|
errorIfScriptNotFail(t, L, `channel.select({1,2,3})`, "invalid select case")
|
||
|
errorIfScriptNotFail(t, L, `channel.select({"<-|", 1, 3})`, "invalid select case")
|
||
|
errorIfScriptNotFail(t, L, `channel.select({"<-|", ch, function() end})`, "can not send a function")
|
||
|
errorIfScriptNotFail(t, L, `channel.select({"|<-", 1, 3})`, "invalid select case")
|
||
|
errorIfScriptNotFail(t, L, `channel.select({"<-->", 1, 3})`, "invalid channel direction")
|
||
|
errorIfScriptFail(t, L, `ch:close()`)
|
||
|
}
|
||
|
|
||
|
func TestChannelSelect1(t *testing.T) {
|
||
|
var result LValue
|
||
|
var wg sync.WaitGroup
|
||
|
receiver := func(ch, quit chan LValue) {
|
||
|
defer wg.Done()
|
||
|
L := NewState()
|
||
|
defer L.Close()
|
||
|
L.SetGlobal("ch", LChannel(ch))
|
||
|
L.SetGlobal("quit", LChannel(quit))
|
||
|
if err := L.DoString(`
|
||
|
buf = ""
|
||
|
local exit = false
|
||
|
while not exit do
|
||
|
channel.select(
|
||
|
{"|<-", ch, function(ok, v)
|
||
|
if not ok then
|
||
|
buf = buf .. "channel closed"
|
||
|
exit = true
|
||
|
else
|
||
|
buf = buf .. "received:" .. v
|
||
|
end
|
||
|
end},
|
||
|
{"|<-", quit, function(ok, v)
|
||
|
buf = buf .. "quit"
|
||
|
end}
|
||
|
)
|
||
|
end
|
||
|
`); err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
result = L.GetGlobal("buf")
|
||
|
}
|
||
|
|
||
|
sender := func(ch, quit chan LValue) {
|
||
|
defer wg.Done()
|
||
|
L := NewState()
|
||
|
defer L.Close()
|
||
|
L.SetGlobal("ch", LChannel(ch))
|
||
|
L.SetGlobal("quit", LChannel(quit))
|
||
|
if err := L.DoString(`
|
||
|
ch:send("1")
|
||
|
ch:send("2")
|
||
|
`); err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
ch <- LString("3")
|
||
|
quit <- LTrue
|
||
|
time.Sleep(1 * time.Second)
|
||
|
close(ch)
|
||
|
}
|
||
|
|
||
|
ch := make(chan LValue)
|
||
|
quit := make(chan LValue)
|
||
|
wg.Add(2)
|
||
|
go receiver(ch, quit)
|
||
|
go sender(ch, quit)
|
||
|
wg.Wait()
|
||
|
lstr, ok := result.(LString)
|
||
|
errorIfFalse(t, ok, "must be string")
|
||
|
str := string(lstr)
|
||
|
errorIfNotEqual(t, "received:1received:2received:3quitchannel closed", str)
|
||
|
|
||
|
}
|
||
|
|
||
|
func TestChannelSelect2(t *testing.T) {
|
||
|
var wg sync.WaitGroup
|
||
|
receiver := func(ch, quit chan LValue) {
|
||
|
defer wg.Done()
|
||
|
L := NewState()
|
||
|
defer L.Close()
|
||
|
L.SetGlobal("ch", LChannel(ch))
|
||
|
L.SetGlobal("quit", LChannel(quit))
|
||
|
errorIfScriptFail(t, L, `
|
||
|
idx, rcv, ok = channel.select(
|
||
|
{"|<-", ch},
|
||
|
{"|<-", quit}
|
||
|
)
|
||
|
assert(idx == 1)
|
||
|
assert(rcv == "1")
|
||
|
assert(ok)
|
||
|
idx, rcv, ok = channel.select(
|
||
|
{"|<-", ch},
|
||
|
{"|<-", quit}
|
||
|
)
|
||
|
assert(idx == 1)
|
||
|
assert(rcv == nil)
|
||
|
assert(not ok)
|
||
|
`)
|
||
|
}
|
||
|
|
||
|
sender := func(ch, quit chan LValue) {
|
||
|
defer wg.Done()
|
||
|
L := NewState()
|
||
|
defer L.Close()
|
||
|
L.SetGlobal("ch", LChannel(ch))
|
||
|
L.SetGlobal("quit", LChannel(quit))
|
||
|
errorIfScriptFail(t, L, `ch:send("1")`)
|
||
|
errorIfScriptFail(t, L, `ch:close()`)
|
||
|
}
|
||
|
|
||
|
ch := make(chan LValue)
|
||
|
quit := make(chan LValue)
|
||
|
wg.Add(2)
|
||
|
go receiver(ch, quit)
|
||
|
go sender(ch, quit)
|
||
|
wg.Wait()
|
||
|
}
|
||
|
|
||
|
func TestChannelSelect3(t *testing.T) {
|
||
|
var wg sync.WaitGroup
|
||
|
receiver := func(ch chan LValue) {
|
||
|
defer wg.Done()
|
||
|
L := NewState()
|
||
|
defer L.Close()
|
||
|
L.SetGlobal("ch", LChannel(ch))
|
||
|
errorIfScriptFail(t, L, `
|
||
|
ok = true
|
||
|
while ok do
|
||
|
idx, rcv, ok = channel.select(
|
||
|
{"|<-", ch}
|
||
|
)
|
||
|
end
|
||
|
`)
|
||
|
}
|
||
|
|
||
|
sender := func(ch chan LValue) {
|
||
|
defer wg.Done()
|
||
|
L := NewState()
|
||
|
defer L.Close()
|
||
|
L.SetGlobal("ch", LChannel(ch))
|
||
|
errorIfScriptFail(t, L, `
|
||
|
ok = false
|
||
|
channel.select(
|
||
|
{"<-|", ch, "1", function(v)
|
||
|
ok = true
|
||
|
end}
|
||
|
)
|
||
|
assert(ok)
|
||
|
idx, rcv, ok = channel.select(
|
||
|
{"<-|", ch, "1"}
|
||
|
)
|
||
|
assert(idx == 1)
|
||
|
ch:close()
|
||
|
`)
|
||
|
}
|
||
|
|
||
|
ch := make(chan LValue)
|
||
|
wg.Add(2)
|
||
|
go receiver(ch)
|
||
|
time.Sleep(1)
|
||
|
go sender(ch)
|
||
|
wg.Wait()
|
||
|
}
|
||
|
|
||
|
func TestChannelSelect4(t *testing.T) {
|
||
|
var wg sync.WaitGroup
|
||
|
receiver := func(ch chan LValue) {
|
||
|
defer wg.Done()
|
||
|
L := NewState()
|
||
|
defer L.Close()
|
||
|
L.SetGlobal("ch", LChannel(ch))
|
||
|
errorIfScriptFail(t, L, `
|
||
|
idx, rcv, ok = channel.select(
|
||
|
{"|<-", ch},
|
||
|
{"default"}
|
||
|
)
|
||
|
assert(idx == 2)
|
||
|
called = false
|
||
|
idx, rcv, ok = channel.select(
|
||
|
{"|<-", ch},
|
||
|
{"default", function()
|
||
|
called = true
|
||
|
end}
|
||
|
)
|
||
|
assert(called)
|
||
|
ch:close()
|
||
|
`)
|
||
|
}
|
||
|
|
||
|
ch := make(chan LValue)
|
||
|
wg.Add(1)
|
||
|
go receiver(ch)
|
||
|
wg.Wait()
|
||
|
}
|
||
|
|
||
|
func TestChannelSendReceive1(t *testing.T) {
|
||
|
var wg sync.WaitGroup
|
||
|
receiver := func(ch chan LValue) {
|
||
|
defer wg.Done()
|
||
|
L := NewState()
|
||
|
defer L.Close()
|
||
|
L.SetGlobal("ch", LChannel(ch))
|
||
|
errorIfScriptFail(t, L, `
|
||
|
local ok, v = ch:receive()
|
||
|
assert(ok)
|
||
|
assert(v == "1")
|
||
|
`)
|
||
|
time.Sleep(1 * time.Second)
|
||
|
errorIfScriptFail(t, L, `
|
||
|
local ok, v = ch:receive()
|
||
|
assert(not ok)
|
||
|
assert(v == nil)
|
||
|
`)
|
||
|
}
|
||
|
sender := func(ch chan LValue) {
|
||
|
defer wg.Done()
|
||
|
L := NewState()
|
||
|
defer L.Close()
|
||
|
L.SetGlobal("ch", LChannel(ch))
|
||
|
errorIfScriptFail(t, L, `ch:send("1")`)
|
||
|
errorIfScriptNotFail(t, L, `ch:send(function() end)`, "can not send a function")
|
||
|
errorIfScriptFail(t, L, `ch:close()`)
|
||
|
}
|
||
|
ch := make(chan LValue)
|
||
|
wg.Add(2)
|
||
|
go receiver(ch)
|
||
|
go sender(ch)
|
||
|
wg.Wait()
|
||
|
}
|