123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- package lua
- import (
- "context"
- "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()
- }
- func TestCancelChannelReceive(t *testing.T) {
- done := make(chan struct{})
- ctx, cancel := context.WithCancel(context.Background())
- go func() {
- defer close(done)
- L := NewState()
- L.SetContext(ctx)
- defer L.Close()
- L.SetGlobal("ch", LChannel(make(chan LValue)))
- errorIfScriptNotFail(t, L, `ch:receive()`, context.Canceled.Error())
- }()
- time.Sleep(time.Second)
- cancel()
- <-done
- }
- func TestCancelChannelReceive2(t *testing.T) {
- done := make(chan struct{})
- ctx, cancel := context.WithCancel(context.Background())
- go func() {
- defer close(done)
- L := NewState()
- L.SetContext(ctx)
- defer L.Close()
- L.SetGlobal("ch", LChannel(make(chan LValue)))
- errorIfScriptNotFail(t, L, `channel.select({"|<-", ch})`, context.Canceled.Error())
- }()
- time.Sleep(time.Second)
- cancel()
- <-done
- }
|