channellib_test.go 6.7 KB

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