Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(568)

Delta Between Two Patch Sets: src/pkg/reflect/all_test.go

Issue 6498078: code review 6498078: reflect: add Select (Closed)
Left Patch Set: Created 11 years, 7 months ago
Right Patch Set: diff -r 6cfab3a0935e https://go.googlecode.com/hg/ Created 11 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | src/pkg/reflect/type.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 // Copyright 2009 The Go Authors. All rights reserved. 1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package reflect_test 5 package reflect_test
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "encoding/base64" 9 "encoding/base64"
10 "fmt" 10 "fmt"
11 "io" 11 "io"
12 "math/rand"
12 "os" 13 "os"
13 . "reflect" 14 . "reflect"
14 "runtime" 15 "runtime"
16 "sync"
15 "testing" 17 "testing"
18 "time"
16 "unsafe" 19 "unsafe"
17 ) 20 )
18 21
19 func TestBool(t *testing.T) { 22 func TestBool(t *testing.T) {
20 v := ValueOf(true) 23 v := ValueOf(true)
21 if v.Bool() != true { 24 if v.Bool() != true {
22 t.Fatal("ValueOf(true).Bool() = false") 25 t.Fatal("ValueOf(true).Bool() = false")
23 } 26 }
24 } 27 }
25 28
(...skipping 1022 matching lines...) Expand 10 before | Expand all | Expand 10 after
1048 cv = MakeChan(TypeOf(c), 10) 1051 cv = MakeChan(TypeOf(c), 10)
1049 c = cv.Interface().(chan int) 1052 c = cv.Interface().(chan int)
1050 for i := 0; i < 3; i++ { 1053 for i := 0; i < 3; i++ {
1051 c <- i 1054 c <- i
1052 } 1055 }
1053 if l, m := cv.Len(), cv.Cap(); l != len(c) || m != cap(c) { 1056 if l, m := cv.Len(), cv.Cap(); l != len(c) || m != cap(c) {
1054 t.Errorf("Len/Cap = %d/%d want %d/%d", l, m, len(c), cap(c)) 1057 t.Errorf("Len/Cap = %d/%d want %d/%d", l, m, len(c), cap(c))
1055 } 1058 }
1056 } 1059 }
1057 1060
1061 // caseInfo describes a single case in a select test.
1062 type caseInfo struct {
1063 desc string
1064 canSelect bool
1065 recv Value
1066 closed bool
1067 helper func()
1068 panic bool
1069 }
1070
1071 func TestSelect(t *testing.T) {
1072 selectWatch.once.Do(func() { go selectWatcher() })
1073
1074 var x exhaustive
1075 nch := 0
1076 newop := func(n int, cap int) (ch, val Value) {
1077 nch++
1078 if nch%101%2 == 1 {
1079 c := make(chan int, cap)
1080 ch = ValueOf(c)
1081 val = ValueOf(n)
1082 } else {
1083 c := make(chan string, cap)
1084 ch = ValueOf(c)
1085 val = ValueOf(fmt.Sprint(n))
1086 }
1087 return
1088 }
1089
1090 for n := 0; x.Next(); n++ {
1091 if testing.Short() && n >= 1000 {
1092 break
1093 }
1094 if n%100000 == 0 && testing.Verbose() {
1095 println("TestSelect", n)
1096 }
1097 var cases []SelectCase
1098 var info []caseInfo
1099
1100 // Ready send.
1101 if x.Maybe() {
1102 ch, val := newop(len(cases), 1)
1103 cases = append(cases, SelectCase{
1104 Dir: SelectSend,
1105 Chan: ch,
1106 Send: val,
1107 })
1108 info = append(info, caseInfo{desc: "ready send", canSele ct: true})
1109 }
1110
1111 // Ready recv.
1112 if x.Maybe() {
1113 ch, val := newop(len(cases), 1)
1114 ch.Send(val)
1115 cases = append(cases, SelectCase{
1116 Dir: SelectRecv,
1117 Chan: ch,
1118 })
1119 info = append(info, caseInfo{desc: "ready recv", canSele ct: true, recv: val})
1120 }
1121
1122 // Blocking send.
1123 if x.Maybe() {
1124 ch, val := newop(len(cases), 0)
1125 cases = append(cases, SelectCase{
1126 Dir: SelectSend,
1127 Chan: ch,
1128 Send: val,
1129 })
1130 // Let it execute?
1131 if x.Maybe() {
1132 f := func() { ch.Recv() }
1133 info = append(info, caseInfo{desc: "blocking sen d", helper: f})
1134 } else {
1135 info = append(info, caseInfo{desc: "blocking sen d"})
1136 }
1137 }
1138
1139 // Blocking recv.
1140 if x.Maybe() {
1141 ch, val := newop(len(cases), 0)
1142 cases = append(cases, SelectCase{
1143 Dir: SelectRecv,
1144 Chan: ch,
1145 })
1146 // Let it execute?
1147 if x.Maybe() {
1148 f := func() { ch.Send(val) }
1149 info = append(info, caseInfo{desc: "blocking rec v", recv: val, helper: f})
1150 } else {
1151 info = append(info, caseInfo{desc: "blocking rec v"})
1152 }
1153 }
1154
1155 // Zero Chan send.
1156 if x.Maybe() {
1157 // Maybe include value to send.
1158 var val Value
1159 if x.Maybe() {
1160 val = ValueOf(100)
1161 }
1162 cases = append(cases, SelectCase{
1163 Dir: SelectSend,
1164 Send: val,
1165 })
1166 info = append(info, caseInfo{desc: "zero Chan send"})
1167 }
1168
1169 // Zero Chan receive.
1170 if x.Maybe() {
1171 cases = append(cases, SelectCase{
1172 Dir: SelectRecv,
1173 })
1174 info = append(info, caseInfo{desc: "zero Chan recv"})
1175 }
1176
1177 // nil Chan send.
1178 if x.Maybe() {
1179 cases = append(cases, SelectCase{
1180 Dir: SelectSend,
1181 Chan: ValueOf((chan int)(nil)),
1182 Send: ValueOf(101),
1183 })
1184 info = append(info, caseInfo{desc: "nil Chan send"})
1185 }
1186
1187 // nil Chan recv.
1188 if x.Maybe() {
1189 cases = append(cases, SelectCase{
1190 Dir: SelectRecv,
1191 Chan: ValueOf((chan int)(nil)),
1192 })
1193 info = append(info, caseInfo{desc: "nil Chan recv"})
1194 }
1195
1196 // closed Chan send.
1197 if x.Maybe() {
1198 ch := make(chan int)
1199 close(ch)
1200 cases = append(cases, SelectCase{
1201 Dir: SelectSend,
1202 Chan: ValueOf(ch),
1203 Send: ValueOf(101),
1204 })
1205 info = append(info, caseInfo{desc: "closed Chan send", c anSelect: true, panic: true})
1206 }
1207
1208 // closed Chan recv.
1209 if x.Maybe() {
1210 ch, val := newop(len(cases), 0)
1211 ch.Close()
1212 val = Zero(val.Type())
1213 cases = append(cases, SelectCase{
1214 Dir: SelectRecv,
1215 Chan: ch,
1216 })
1217 info = append(info, caseInfo{desc: "closed Chan recv", c anSelect: true, closed: true, recv: val})
1218 }
1219
1220 var helper func() // goroutine to help the select complete
1221
1222 // Add default? Must be last case here, but will permute.
1223 // Add the default if the select would otherwise
1224 // block forever, and maybe add it anyway.
1225 numCanSelect := 0
1226 canProceed := false
1227 canBlock := true
1228 canPanic := false
1229 helpers := []int{}
1230 for i, c := range info {
1231 if c.canSelect {
1232 canProceed = true
1233 canBlock = false
1234 numCanSelect++
1235 if c.panic {
1236 canPanic = true
1237 }
1238 } else if c.helper != nil {
1239 canProceed = true
1240 helpers = append(helpers, i)
1241 }
1242 }
1243 if !canProceed || x.Maybe() {
1244 cases = append(cases, SelectCase{
1245 Dir: SelectDefault,
1246 })
1247 info = append(info, caseInfo{desc: "default", canSelect: canBlock})
1248 numCanSelect++
1249 } else if canBlock {
1250 // Select needs to communicate with another goroutine.
1251 cas := &info[helpers[x.Choose(len(helpers))]]
1252 helper = cas.helper
1253 cas.canSelect = true
1254 numCanSelect++
1255 }
1256
1257 // Permute cases and case info.
1258 // Doing too much here makes the exhaustive loop
1259 // too exhausting, so just do two swaps.
1260 for loop := 0; loop < 2; loop++ {
1261 i := x.Choose(len(cases))
1262 j := x.Choose(len(cases))
1263 cases[i], cases[j] = cases[j], cases[i]
1264 info[i], info[j] = info[j], info[i]
1265 }
1266
1267 if helper != nil {
1268 // We wait before kicking off a goroutine to satisfy a b locked select.
1269 // The pause needs to be big enough to let the select bl ock before
1270 // we run the helper, but if we lose that race once in a while it's okay: the
1271 // select will just proceed immediately. Not a big deal.
1272 // For short tests we can grow [sic] the timeout a bit w ithout fear of taking too long
1273 pause := 10 * time.Microsecond
1274 if testing.Short() {
1275 pause = 100 * time.Microsecond
1276 }
1277 time.AfterFunc(pause, helper)
1278 }
1279
1280 // Run select.
1281 i, recv, recvOK, panicErr := runSelect(cases, info)
1282 if panicErr != nil && !canPanic {
1283 t.Fatalf("%s\npanicked unexpectedly: %v", fmtSelect(info ), panicErr)
1284 }
1285 if panicErr == nil && canPanic && numCanSelect == 1 {
1286 t.Fatalf("%s\nselected #%d incorrectly (should panic)", fmtSelect(info), i)
1287 }
1288 if panicErr != nil {
1289 continue
1290 }
1291
1292 cas := info[i]
1293 if !cas.canSelect {
1294 recvStr := ""
1295 if recv.IsValid() {
1296 recvStr = fmt.Sprintf(", received %v, %v", recv. Interface(), recvOK)
1297 }
1298 t.Fatalf("%s\nselected #%d incorrectly%s", fmtSelect(inf o), i, recvStr)
1299 continue
1300 }
1301 if cas.panic {
1302 t.Fatalf("%s\nselected #%d incorrectly (case should pani c)", fmtSelect(info), i)
1303 continue
1304 }
1305
1306 if cases[i].Dir == SelectRecv {
1307 if !recv.IsValid() {
1308 t.Fatalf("%s\nselected #%d but got %v, %v, want %v, %v", fmtSelect(info), i, recv, recvOK, cas.recv.Interface(), !cas.closed)
1309 }
1310 if !cas.recv.IsValid() {
1311 t.Fatalf("%s\nselected #%d but internal error: m issing recv value", fmtSelect(info), i)
1312 }
1313 if recv.Interface() != cas.recv.Interface() || recvOK != !cas.closed {
1314 if recv.Interface() == cas.recv.Interface() && r ecvOK == !cas.closed {
1315 t.Fatalf("%s\nselected #%d, got %#v, %v, and DeepEqual is broken on %T", fmtSelect(info), i, recv.Interface(), recvOK, r ecv.Interface())
1316 }
1317 t.Fatalf("%s\nselected #%d but got %#v, %v, want %#v, %v", fmtSelect(info), i, recv.Interface(), recvOK, cas.recv.Interface(), ! cas.closed)
1318 }
1319 } else {
1320 if recv.IsValid() || recvOK {
1321 t.Fatalf("%s\nselected #%d but got %v, %v, want %v, %v", fmtSelect(info), i, recv, recvOK, Value{}, false)
1322 }
1323 }
1324 }
1325 }
1326
1327 // selectWatch and the selectWatcher are a watchdog mechanism for running Select .
1328 // If the selectWatcher notices that the select has been blocked for >1 second, it prints
1329 // an error describing the select and panics the entire test binary.·
1330 var selectWatch struct {
1331 sync.Mutex
1332 once sync.Once
1333 now time.Time
1334 info []caseInfo
1335 }
1336
1337 func selectWatcher() {
1338 for {
1339 time.Sleep(1 * time.Second)
1340 selectWatch.Lock()
1341 if selectWatch.info != nil && time.Since(selectWatch.now) > 1*ti me.Second {
1342 fmt.Fprintf(os.Stderr, "TestSelect:\n%s blocked indefini tely\n", fmtSelect(selectWatch.info))
1343 panic("select stuck")
1344 }
1345 selectWatch.Unlock()
1346 }
1347 }
1348
1349 // runSelect runs a single select test.
1350 // It returns the values returned by Select but also returns
1351 // a panic value if the Select panics.
1352 func runSelect(cases []SelectCase, info []caseInfo) (chosen int, recv Value, rec vOK bool, panicErr interface{}) {
1353 defer func() {
1354 panicErr = recover()
1355
1356 selectWatch.Lock()
1357 selectWatch.info = nil
1358 selectWatch.Unlock()
1359 }()
1360
1361 selectWatch.Lock()
1362 selectWatch.now = time.Now()
1363 selectWatch.info = info
1364 selectWatch.Unlock()
1365
1366 chosen, recv, recvOK = Select(cases)
1367 return
1368 }
1369
1370 // fmtSelect formats the information about a single select test.
1371 func fmtSelect(info []caseInfo) string {
1372 var buf bytes.Buffer
1373 fmt.Fprintf(&buf, "\nselect {\n")
1374 for i, cas := range info {
1375 fmt.Fprintf(&buf, "%d: %s", i, cas.desc)
1376 if cas.recv.IsValid() {
1377 fmt.Fprintf(&buf, " val=%#v", cas.recv.Interface())
1378 }
1379 if cas.canSelect {
1380 fmt.Fprintf(&buf, " canselect")
1381 }
1382 if cas.panic {
1383 fmt.Fprintf(&buf, " panic")
1384 }
1385 fmt.Fprintf(&buf, "\n")
1386 }
1387 fmt.Fprintf(&buf, "}")
1388 return buf.String()
1389 }
1390
1058 // Difficult test for function call because of 1391 // Difficult test for function call because of
1059 // implicit padding between arguments. 1392 // implicit padding between arguments.
1060 func dummy(b byte, c int, d byte) (i byte, j int, k byte) { 1393 func dummy(b byte, c int, d byte) (i byte, j int, k byte) {
1061 return b, c, d 1394 return b, c, d
1062 } 1395 }
1063 1396
1064 func TestFunc(t *testing.T) { 1397 func TestFunc(t *testing.T) {
1065 ret := ValueOf(dummy).Call([]Value{ValueOf(byte(10)), ValueOf(20), Value Of(byte(30))}) 1398 ret := ValueOf(dummy).Call([]Value{ValueOf(byte(10)), ValueOf(20), Value Of(byte(30))})
1066 if len(ret) != 3 { 1399 if len(ret) != 3 {
1067 t.Fatalf("Call returned %d values, want 3", len(ret)) 1400 t.Fatalf("Call returned %d values, want 3", len(ret))
(...skipping 858 matching lines...) Expand 10 before | Expand all | Expand 10 after
1926 t.Fatalf(`FieldByName("X") should fail, returned %v`, f.Index) 2259 t.Fatalf(`FieldByName("X") should fail, returned %v`, f.Index)
1927 } 2260 }
1928 } 2261 }
1929 2262
1930 func BenchmarkFieldByName3(b *testing.B) { 2263 func BenchmarkFieldByName3(b *testing.B) {
1931 t := TypeOf(R0{}) 2264 t := TypeOf(R0{})
1932 for i := 0; i < b.N; i++ { 2265 for i := 0; i < b.N; i++ {
1933 t.FieldByName("X") 2266 t.FieldByName("X")
1934 } 2267 }
1935 } 2268 }
2269
2270 // An exhaustive is a mechanism for writing exhaustive or stochastic tests.
2271 // The basic usage is:
2272 //
2273 // for x.Next() {
2274 // ... code using x.Maybe() or x.Choice(n) to create test cases ...
2275 // }
2276 //
2277 // Each iteration of the loop returns a different set of results, until all
2278 // possible result sets have been explored. It is okay for different code paths
2279 // to make different method call sequences on x, but there must be no
2280 // other source of non-determinism in the call sequences.
2281 //
2282 // When faced with a new decision, x chooses randomly. Future explorations
2283 // of that path will choose successive values for the result. Thus, stopping
2284 // the loop after a fixed number of iterations gives somewhat stochastic
2285 // testing.
2286 //
2287 // Example:
2288 //
2289 // for x.Next() {
2290 // v := make([]bool, x.Choose(4))
2291 // for i := range v {
2292 // v[i] = x.Maybe()
2293 // }
2294 // fmt.Println(v)
2295 // }
2296 //
2297 // prints (in some order):
2298 //
2299 // []
2300 // [false]
2301 // [true]
2302 // [false false]
2303 // [false true]
2304 // ...
2305 // [true true]
2306 // [false false false]
2307 // ...
2308 // [true true true]
2309 // [false false false false]
2310 // ...
2311 // [true true true true]
2312 //
2313 type exhaustive struct {
2314 r *rand.Rand
2315 pos int
2316 last []choice
2317 }
2318
2319 type choice struct {
2320 off int
2321 n int
2322 max int
2323 }
2324
2325 func (x *exhaustive) Next() bool {
2326 if x.r == nil {
2327 x.r = rand.New(rand.NewSource(time.Now().UnixNano()))
2328 }
2329 x.pos = 0
2330 if x.last == nil {
2331 x.last = []choice{}
2332 return true
2333 }
2334 for i := len(x.last) - 1; i >= 0; i-- {
2335 c := &x.last[i]
2336 if c.n+1 < c.max {
2337 c.n++
2338 x.last = x.last[:i+1]
2339 return true
2340 }
2341 }
2342 return false
2343 }
2344
2345 func (x *exhaustive) Choose(max int) int {
2346 if x.pos >= len(x.last) {
2347 x.last = append(x.last, choice{x.r.Intn(max), 0, max})
2348 }
2349 c := &x.last[x.pos]
2350 x.pos++
2351 if c.max != max {
2352 panic("inconsistent use of exhaustive tester")
2353 }
2354 return (c.n + c.off) % max
2355 }
2356
2357 func (x *exhaustive) Maybe() bool {
2358 return x.Choose(2) == 1
2359 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b