gitee.com/yfmps/gopher-lua@v0.0.3/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 }