-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcoroutine_test.go
More file actions
155 lines (142 loc) · 3.91 KB
/
Copy pathcoroutine_test.go
File metadata and controls
155 lines (142 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Coroutine end-to-end tests (08 route B acceptance).
package wangshu_test
import (
"strings"
"testing"
"github.com/Liam0205/wangshu"
)
func runMulti(t *testing.T, src string) []wangshu.Value {
t.Helper()
prog, err := wangshu.Compile([]byte(src), "cotest")
if err != nil {
t.Fatalf("compile: %v", err)
}
st := wangshu.NewState(wangshu.Options{})
results, err := prog.Run(st)
if err != nil {
t.Fatalf("run: %v", err)
}
return results
}
func TestCo_BasicYieldResume(t *testing.T) {
r := runMulti(t, `
local co = coroutine.create(function(a, b)
local c = coroutine.yield(a + b)
return c * 2
end)
local ok1, sum = coroutine.resume(co, 3, 4)
local ok2, double = coroutine.resume(co, 10)
return tostring(ok1), sum, tostring(ok2), double, coroutine.status(co)`)
want := []string{"true", "7", "true", "20", "dead"}
for i, w := range want {
if r[i].Display() != w {
t.Errorf("r[%d] = %q, want %q", i, r[i].Display(), w)
}
}
}
func TestCo_MultiYieldLoop(t *testing.T) {
r := runMulti(t, `
local co = coroutine.create(function()
for i = 1, 3 do coroutine.yield(i) end
return "done"
end)
local out = ""
for i = 1, 4 do
local ok, v = coroutine.resume(co)
out = out .. tostring(v) .. ";"
end
return out, coroutine.status(co)`)
if r[0].Str() != "1;2;3;done;" || r[1].Str() != "dead" {
t.Errorf("got %q %q", r[0].Display(), r[1].Display())
}
}
func TestCo_Wrap(t *testing.T) {
r := runMulti(t, `
local gen = coroutine.wrap(function()
coroutine.yield(1)
coroutine.yield(2)
return 3
end)
return gen() + gen() + gen()`)
if r[0].Number() != 6 {
t.Errorf("got %v, want 6", r[0].Display())
}
}
func TestCo_ErrorInsideBecomesFalse(t *testing.T) {
r := runMulti(t, `
local co = coroutine.create(function() error("inside") end)
local ok, err = coroutine.resume(co)
return tostring(ok), err, coroutine.status(co)`)
// error(string) automatically adds the chunkname:line: prefix (5.1)
if r[0].Str() != "false" || !strings.HasSuffix(r[1].Str(), ": inside") || r[2].Str() != "dead" {
t.Errorf("got %q %q %q", r[0].Display(), r[1].Display(), r[2].Display())
}
}
func TestCo_ResumeDead(t *testing.T) {
r := runMulti(t, `
local co = coroutine.create(function() return 1 end)
coroutine.resume(co)
local ok, err = coroutine.resume(co)
return tostring(ok), err`)
if r[0].Str() != "false" {
t.Errorf("ok = %q, want false", r[0].Display())
}
}
func TestCo_TypeIsThread(t *testing.T) {
r := runMulti(t, `
local co = coroutine.create(function() end)
return type(co)`)
if r[0].Str() != "thread" {
t.Errorf("type = %q, want thread", r[0].Display())
}
}
func TestCo_NestedCallYield(t *testing.T) {
r := runMulti(t, `
local function inner() coroutine.yield("deep") end
local co = coroutine.create(function() inner(); return "after" end)
local ok1, v1 = coroutine.resume(co)
local ok2, v2 = coroutine.resume(co)
return v1, v2`)
if r[0].Str() != "deep" || r[1].Str() != "after" {
t.Errorf("got %q %q", r[0].Display(), r[1].Display())
}
}
func TestCo_CrossThreadUpvalue(t *testing.T) {
r := runMulti(t, `
local x = 100
local co = coroutine.create(function()
x = x + 1
coroutine.yield(x)
x = x + 1
return x
end)
local _, a = coroutine.resume(co)
local _, b = coroutine.resume(co)
return a, b, x`)
if r[0].Number() != 101 || r[1].Number() != 102 || r[2].Number() != 102 {
t.Errorf("got %v %v %v", r[0].Display(), r[1].Display(), r[2].Display())
}
}
func TestCo_YieldOutsideCoroutine(t *testing.T) {
prog, err := wangshu.Compile([]byte(`coroutine.yield(1)`), "bad")
if err != nil {
t.Fatalf("compile: %v", err)
}
st := wangshu.NewState(wangshu.Options{})
_, err = prog.Run(st)
if err == nil {
t.Fatalf("expected error for yield outside coroutine")
}
}
func TestCo_StatusRunningInside(t *testing.T) {
r := runMulti(t, `
local co
co = coroutine.create(function()
return coroutine.status(co)
end)
local _, s = coroutine.resume(co)
return s`)
if r[0].Str() != "running" {
t.Errorf("status inside = %q, want running", r[0].Display())
}
}