github.com/suixinio/gopher-lua@v0.0.0-20230314172526-3c6bff009a9a/channellib_test.go (about)

     1  package lua
     2  
     3  import (
     4  	"context"
     5  	"reflect"
     6  	"sync"
     7  	"testing"
     8  	"time"
     9  )
    10  
    11  func TestChannelMake(t *testing.T) {
    12  	L := NewState()
    13  	defer L.Close()
    14  	errorIfScriptFail(t, L, `
    15      ch = channel.make()
    16      `)
    17  	obj := L.GetGlobal("ch")
    18  	ch, ok := obj.(LChannel)
    19  	errorIfFalse(t, ok, "channel expected")
    20  	errorIfNotEqual(t, 0, reflect.ValueOf(ch).Cap())
    21  	close(ch)
    22  
    23  	errorIfScriptFail(t, L, `
    24      ch = channel.make(10)
    25      `)
    26  	obj = L.GetGlobal("ch")
    27  	ch, _ = obj.(LChannel)
    28  	errorIfNotEqual(t, 10, reflect.ValueOf(ch).Cap())
    29  	close(ch)
    30  }
    31  
    32  func TestChannelSelectError(t *testing.T) {
    33  	L := NewState()
    34  	defer L.Close()
    35  	errorIfScriptFail(t, L, `ch = channel.make()`)
    36  	errorIfScriptNotFail(t, L, `channel.select({1,2,3})`, "invalid select case")
    37  	errorIfScriptNotFail(t, L, `channel.select({"<-|", 1, 3})`, "invalid select case")
    38  	errorIfScriptNotFail(t, L, `channel.select({"<-|", ch, function() end})`, "can not send a function")
    39  	errorIfScriptNotFail(t, L, `channel.select({"|<-", 1, 3})`, "invalid select case")
    40  	errorIfScriptNotFail(t, L, `channel.select({"<-->", 1, 3})`, "invalid channel direction")
    41  	errorIfScriptFail(t, L, `ch:close()`)
    42  }
    43  
    44  func TestChannelSelect1(t *testing.T) {
    45  	var result LValue
    46  	var wg sync.WaitGroup
    47  	receiver := func(ch, quit chan LValue) {
    48  		defer wg.Done()
    49  		L := NewState()
    50  		defer L.Close()
    51  		L.SetGlobal("ch", LChannel(ch))
    52  		L.SetGlobal("quit", LChannel(quit))
    53  		if err := L.DoString(`
    54      buf = ""
    55      local exit = false
    56      while not exit do
    57        channel.select(
    58          {"|<-", ch, function(ok, v)
    59            if not ok then
    60              buf = buf .. "channel closed"
    61              exit = true
    62            else
    63              buf = buf .. "received:" .. v
    64            end
    65          end},
    66          {"|<-", quit, function(ok, v)
    67              buf = buf .. "quit"
    68          end}
    69        )
    70      end
    71    `); err != nil {
    72  			panic(err)
    73  		}
    74  		result = L.GetGlobal("buf")
    75  	}
    76  
    77  	sender := func(ch, quit chan LValue) {
    78  		defer wg.Done()
    79  		L := NewState()
    80  		defer L.Close()
    81  		L.SetGlobal("ch", LChannel(ch))
    82  		L.SetGlobal("quit", LChannel(quit))
    83  		if err := L.DoString(`
    84      ch:send("1")
    85      ch:send("2")
    86    `); err != nil {
    87  			panic(err)
    88  		}
    89  		ch <- LString("3")
    90  		quit <- LTrue
    91  		time.Sleep(1 * time.Second)
    92  		close(ch)
    93  	}
    94  
    95  	ch := make(chan LValue)
    96  	quit := make(chan LValue)
    97  	wg.Add(2)
    98  	go receiver(ch, quit)
    99  	go sender(ch, quit)
   100  	wg.Wait()
   101  	lstr, ok := result.(LString)
   102  	errorIfFalse(t, ok, "must be string")
   103  	str := string(lstr)
   104  	errorIfNotEqual(t, "received:1received:2received:3quitchannel closed", str)
   105  
   106  }
   107  
   108  func TestChannelSelect2(t *testing.T) {
   109  	var wg sync.WaitGroup
   110  	receiver := func(ch, quit chan LValue) {
   111  		defer wg.Done()
   112  		L := NewState()
   113  		defer L.Close()
   114  		L.SetGlobal("ch", LChannel(ch))
   115  		L.SetGlobal("quit", LChannel(quit))
   116  		errorIfScriptFail(t, L, `
   117             idx, rcv, ok = channel.select(
   118                 {"|<-", ch},
   119                 {"|<-", quit}
   120             )
   121             assert(idx == 1)
   122             assert(rcv == "1")
   123             assert(ok)
   124             idx, rcv, ok = channel.select(
   125                 {"|<-", ch},
   126                 {"|<-", quit}
   127             )
   128             assert(idx == 1)
   129             assert(rcv == nil)
   130             assert(not ok)
   131         `)
   132  	}
   133  
   134  	sender := func(ch, quit chan LValue) {
   135  		defer wg.Done()
   136  		L := NewState()
   137  		defer L.Close()
   138  		L.SetGlobal("ch", LChannel(ch))
   139  		L.SetGlobal("quit", LChannel(quit))
   140  		errorIfScriptFail(t, L, `ch:send("1")`)
   141  		errorIfScriptFail(t, L, `ch:close()`)
   142  	}
   143  
   144  	ch := make(chan LValue)
   145  	quit := make(chan LValue)
   146  	wg.Add(2)
   147  	go receiver(ch, quit)
   148  	go sender(ch, quit)
   149  	wg.Wait()
   150  }
   151  
   152  func TestChannelSelect3(t *testing.T) {
   153  	var wg sync.WaitGroup
   154  	receiver := func(ch chan LValue) {
   155  		defer wg.Done()
   156  		L := NewState()
   157  		defer L.Close()
   158  		L.SetGlobal("ch", LChannel(ch))
   159  		errorIfScriptFail(t, L, `
   160             ok = true
   161             while ok do
   162               idx, rcv, ok = channel.select(
   163                   {"|<-", ch}
   164               )
   165             end
   166         `)
   167  	}
   168  
   169  	sender := func(ch chan LValue) {
   170  		defer wg.Done()
   171  		L := NewState()
   172  		defer L.Close()
   173  		L.SetGlobal("ch", LChannel(ch))
   174  		errorIfScriptFail(t, L, `
   175             ok = false
   176             channel.select(
   177                 {"<-|", ch, "1", function(v)
   178                   ok = true
   179                 end}
   180             )
   181             assert(ok)
   182             idx, rcv, ok = channel.select(
   183                 {"<-|", ch, "1"}
   184             )
   185             assert(idx == 1)
   186             ch:close()
   187         `)
   188  	}
   189  
   190  	ch := make(chan LValue)
   191  	wg.Add(2)
   192  	go receiver(ch)
   193  	time.Sleep(1)
   194  	go sender(ch)
   195  	wg.Wait()
   196  }
   197  
   198  func TestChannelSelect4(t *testing.T) {
   199  	var wg sync.WaitGroup
   200  	receiver := func(ch chan LValue) {
   201  		defer wg.Done()
   202  		L := NewState()
   203  		defer L.Close()
   204  		L.SetGlobal("ch", LChannel(ch))
   205  		errorIfScriptFail(t, L, `
   206             idx, rcv, ok = channel.select(
   207                   {"|<-", ch},
   208                   {"default"}
   209             )
   210             assert(idx == 2)
   211             called = false
   212             idx, rcv, ok = channel.select(
   213                   {"|<-", ch},
   214                   {"default", function()
   215                      called = true
   216                   end}
   217             )
   218             assert(called)
   219             ch:close()
   220         `)
   221  	}
   222  
   223  	ch := make(chan LValue)
   224  	wg.Add(1)
   225  	go receiver(ch)
   226  	wg.Wait()
   227  }
   228  
   229  func TestChannelSendReceive1(t *testing.T) {
   230  	var wg sync.WaitGroup
   231  	receiver := func(ch chan LValue) {
   232  		defer wg.Done()
   233  		L := NewState()
   234  		defer L.Close()
   235  		L.SetGlobal("ch", LChannel(ch))
   236  		errorIfScriptFail(t, L, `
   237            local ok, v = ch:receive()
   238            assert(ok)
   239            assert(v == "1")
   240          `)
   241  		time.Sleep(1 * time.Second)
   242  		errorIfScriptFail(t, L, `
   243            local ok, v = ch:receive()
   244            assert(not ok)
   245            assert(v == nil)
   246          `)
   247  	}
   248  	sender := func(ch chan LValue) {
   249  		defer wg.Done()
   250  		L := NewState()
   251  		defer L.Close()
   252  		L.SetGlobal("ch", LChannel(ch))
   253  		errorIfScriptFail(t, L, `ch:send("1")`)
   254  		errorIfScriptNotFail(t, L, `ch:send(function() end)`, "can not send a function")
   255  		errorIfScriptFail(t, L, `ch:close()`)
   256  	}
   257  	ch := make(chan LValue)
   258  	wg.Add(2)
   259  	go receiver(ch)
   260  	go sender(ch)
   261  	wg.Wait()
   262  }
   263  
   264  func TestCancelChannelReceive(t *testing.T) {
   265  	done := make(chan struct{})
   266  	ctx, cancel := context.WithCancel(context.Background())
   267  	go func() {
   268  		defer close(done)
   269  		L := NewState()
   270  		L.SetContext(ctx)
   271  		defer L.Close()
   272  		L.SetGlobal("ch", LChannel(make(chan LValue)))
   273  		errorIfScriptNotFail(t, L, `ch:receive()`, context.Canceled.Error())
   274  	}()
   275  	time.Sleep(time.Second)
   276  	cancel()
   277  	<-done
   278  }
   279  
   280  func TestCancelChannelReceive2(t *testing.T) {
   281  	done := make(chan struct{})
   282  	ctx, cancel := context.WithCancel(context.Background())
   283  	go func() {
   284  		defer close(done)
   285  		L := NewState()
   286  		L.SetContext(ctx)
   287  		defer L.Close()
   288  		L.SetGlobal("ch", LChannel(make(chan LValue)))
   289  		errorIfScriptNotFail(t, L, `channel.select({"|<-", ch})`, context.Canceled.Error())
   290  	}()
   291  	time.Sleep(time.Second)
   292  	cancel()
   293  	<-done
   294  }