Source file
src/runtime/traceback_test.go
1
2
3
4
5 package runtime_test
6
7 import (
8 "bytes"
9 "fmt"
10 "internal/abi"
11 "internal/testenv"
12 "regexp"
13 "runtime"
14 "runtime/debug"
15 "strconv"
16 "strings"
17 "sync"
18 "testing"
19 _ "unsafe"
20 )
21
22
23 func TestTracebackInlined(t *testing.T) {
24 testenv.SkipIfOptimizationOff(t)
25 check := func(t *testing.T, r *ttiResult, funcs ...string) {
26 t.Helper()
27
28
29 frames := parseTraceback1(t, r.printed).frames
30 t.Log(r.printed)
31
32 for len(frames) > 0 && frames[0].funcName != "runtime_test.ttiLeaf" {
33 frames = frames[1:]
34 }
35 if len(frames) == 0 {
36 t.Errorf("missing runtime_test.ttiLeaf")
37 return
38 }
39 frames = frames[1:]
40
41 for i, want := range funcs {
42 got := "<end>"
43 if i < len(frames) {
44 got = frames[i].funcName
45 if strings.HasSuffix(want, ")") {
46 got += "(" + frames[i].args + ")"
47 }
48 }
49 if got != want {
50 t.Errorf("got %s, want %s", got, want)
51 return
52 }
53 }
54 }
55
56 t.Run("simple", func(t *testing.T) {
57
58 r := ttiSimple1()
59 check(t, r, "runtime_test.ttiSimple3(...)", "runtime_test.ttiSimple2(...)", "runtime_test.ttiSimple1()")
60 })
61
62 t.Run("sigpanic", func(t *testing.T) {
63
64 r := ttiSigpanic1()
65 check(t, r, "runtime_test.ttiSigpanic1.func1()", "panic", "runtime_test.ttiSigpanic3(...)", "runtime_test.ttiSigpanic2(...)", "runtime_test.ttiSigpanic1()")
66 })
67
68 t.Run("wrapper", func(t *testing.T) {
69
70 r := ttiWrapper1()
71 check(t, r, "runtime_test.ttiWrapper.m1(...)", "runtime_test.ttiWrapper1()")
72 })
73
74 t.Run("excluded", func(t *testing.T) {
75
76
77 r := ttiExcluded1()
78 check(t, r, "runtime_test.ttiExcluded3(...)", "runtime_test.ttiExcluded1()")
79 })
80 }
81
82 type ttiResult struct {
83 printed string
84 }
85
86
87 func ttiLeaf() *ttiResult {
88
89 printed := string(debug.Stack())
90 return &ttiResult{printed}
91 }
92
93
94 func ttiSimple1() *ttiResult {
95 return ttiSimple2()
96 }
97 func ttiSimple2() *ttiResult {
98 return ttiSimple3()
99 }
100 func ttiSimple3() *ttiResult {
101 return ttiLeaf()
102 }
103
104
105 func ttiSigpanic1() (res *ttiResult) {
106 defer func() {
107 res = ttiLeaf()
108 recover()
109 }()
110 ttiSigpanic2()
111 panic("did not panic")
112 }
113 func ttiSigpanic2() {
114 ttiSigpanic3()
115 }
116 func ttiSigpanic3() {
117 var p *int
118 *p = 3
119 }
120
121
122 func ttiWrapper1() *ttiResult {
123 var w ttiWrapper
124 m := (*ttiWrapper).m1
125 return m(&w)
126 }
127
128 type ttiWrapper struct{}
129
130 func (w ttiWrapper) m1() *ttiResult {
131 return ttiLeaf()
132 }
133
134
135 func ttiExcluded1() *ttiResult {
136 return ttiExcluded2()
137 }
138
139
140
141
142
143
144
145
146 func ttiExcluded2() *ttiResult {
147 return ttiExcluded3()
148 }
149 func ttiExcluded3() *ttiResult {
150 return ttiLeaf()
151 }
152
153 var testTracebackArgsBuf [1000]byte
154
155 func TestTracebackElision(t *testing.T) {
156
157
158
159
160 for _, elided := range []int{0, 1, 10} {
161 t.Run(fmt.Sprintf("elided=%d", elided), func(t *testing.T) {
162 n := elided + runtime.TracebackInnerFrames + runtime.TracebackOuterFrames
163
164
165 stackChan := make(chan string)
166 go tteStack(n, stackChan)
167 stack := <-stackChan
168 tb := parseTraceback1(t, stack)
169
170
171 i := 0
172 for i < n {
173 if len(tb.frames) == 0 {
174 t.Errorf("traceback ended early")
175 break
176 }
177 fr := tb.frames[0]
178 if i == runtime.TracebackInnerFrames && elided > 0 {
179
180 if fr.elided != elided {
181 t.Errorf("want %d frames elided", elided)
182 break
183 }
184 i += fr.elided
185 } else {
186 want := fmt.Sprintf("runtime_test.tte%d", (i+1)%5)
187 if i == 0 {
188 want = "runtime/debug.Stack"
189 } else if i == n-1 {
190 want = "runtime_test.tteStack"
191 }
192 if fr.funcName != want {
193 t.Errorf("want %s, got %s", want, fr.funcName)
194 break
195 }
196 i++
197 }
198 tb.frames = tb.frames[1:]
199 }
200 if !t.Failed() && len(tb.frames) > 0 {
201 t.Errorf("got %d more frames than expected", len(tb.frames))
202 }
203 if t.Failed() {
204 t.Logf("traceback diverged at frame %d", i)
205 off := len(stack)
206 if len(tb.frames) > 0 {
207 off = tb.frames[0].off
208 }
209 t.Logf("traceback before error:\n%s", stack[:off])
210 t.Logf("traceback after error:\n%s", stack[off:])
211 }
212 })
213 }
214 }
215
216
217
218
219 func tteStack(n int, stack chan<- string) {
220 n--
221
222
223 switch n % 5 {
224 case 0:
225 stack <- tte0(n)
226 case 1:
227 stack <- tte1(n)
228 case 2:
229 stack <- tte2(n)
230 case 3:
231 stack <- tte3(n)
232 case 4:
233 stack <- tte4(n)
234 default:
235 panic("unreachable")
236 }
237 }
238 func tte0(n int) string {
239 return tte4(n - 1)
240 }
241 func tte1(n int) string {
242 return tte0(n - 1)
243 }
244 func tte2(n int) string {
245
246
247 if n < 2 {
248 panic("bad n")
249 }
250 if n == 2 {
251 return string(debug.Stack())
252 }
253 return tte1(n - 1)
254 }
255 func tte3(n int) string {
256 return tte2(n - 1)
257 }
258 func tte4(n int) string {
259 return tte3(n - 1)
260 }
261
262 func TestTracebackArgs(t *testing.T) {
263 if *flagQuick {
264 t.Skip("-quick")
265 }
266 optimized := !testenv.OptimizationOff()
267 abiSel := func(x, y string) string {
268
269
270 if optimized && abi.IntArgRegs > 0 {
271 return x
272 }
273 return y
274 }
275
276 tests := []struct {
277 fn func() int
278 expect string
279 }{
280
281 {
282 func() int { return testTracebackArgs1(1, 2, 3, 4, 5) },
283 "testTracebackArgs1(0x1, 0x2, 0x3, 0x4, 0x5)",
284 },
285
286 {
287 func() int {
288 return testTracebackArgs2(false, struct {
289 a, b, c int
290 x [2]int
291 }{1, 2, 3, [2]int{4, 5}}, [0]int{}, [3]byte{6, 7, 8})
292 },
293 "testTracebackArgs2(0x0, {0x1, 0x2, 0x3, {0x4, 0x5}}, {}, {0x6, 0x7, 0x8})",
294 },
295 {
296 func() int { return testTracebackArgs3([3]byte{1, 2, 3}, 4, 5, 6, [3]byte{7, 8, 9}) },
297 "testTracebackArgs3({0x1, 0x2, 0x3}, 0x4, 0x5, 0x6, {0x7, 0x8, 0x9})",
298 },
299
300 {
301 func() int { return testTracebackArgs4(false, [1][1][1][1][1][1][1][1][1][1]int{}) },
302 "testTracebackArgs4(0x0, {{{{{...}}}}})",
303 },
304
305 {
306 func() int {
307 z := [0]int{}
308 return testTracebackArgs5(false, struct {
309 x int
310 y [0]int
311 z [2][0]int
312 }{1, z, [2][0]int{}}, z, z, z, z, z, z, z, z, z, z, z, z)
313 },
314 "testTracebackArgs5(0x0, {0x1, {}, {{}, {}}}, {}, {}, {}, {}, {}, ...)",
315 },
316
317
318
319 {
320 func() int { return testTracebackArgs6a(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) },
321 "testTracebackArgs6a(0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa)",
322 },
323
324 {
325 func() int { return testTracebackArgs6b(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) },
326 "testTracebackArgs6b(0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, ...)",
327 },
328
329 {
330 func() int { return testTracebackArgs7a([10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) },
331 "testTracebackArgs7a({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa})",
332 },
333
334 {
335 func() int { return testTracebackArgs7b([11]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}) },
336 "testTracebackArgs7b({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, ...})",
337 },
338
339 {
340 func() int { return testTracebackArgs7c([10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 11) },
341 "testTracebackArgs7c({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa}, ...)",
342 },
343
344 {
345 func() int { return testTracebackArgs7d([11]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 12) },
346 "testTracebackArgs7d({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, ...}, ...)",
347 },
348
349 {
350 func() int { return testTracebackArgs8a(testArgsType8a{1, 2, 3, 4, 5, 6, 7, 8, [2]int{9, 10}}) },
351 "testTracebackArgs8a({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa}})",
352 },
353
354 {
355 func() int { return testTracebackArgs8b(testArgsType8b{1, 2, 3, 4, 5, 6, 7, 8, [3]int{9, 10, 11}}) },
356 "testTracebackArgs8b({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa, ...}})",
357 },
358
359 {
360 func() int { return testTracebackArgs8c(testArgsType8c{1, 2, 3, 4, 5, 6, 7, 8, [2]int{9, 10}, 11}) },
361 "testTracebackArgs8c({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa}, ...})",
362 },
363
364 {
365 func() int { return testTracebackArgs8d(testArgsType8d{1, 2, 3, 4, 5, 6, 7, 8, [3]int{9, 10, 11}, 12}) },
366 "testTracebackArgs8d({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa, ...}, ...})",
367 },
368
369
370
371
372 {
373 func() int {
374 poisonStack()
375 return testTracebackArgs9(1, 2, 3, 4, [2]int{5, 6}, 7)
376 },
377 abiSel(
378 "testTracebackArgs9(0x1, 0xffffffff?, 0x3, 0xff?, {0x5, 0x6}, 0x7)",
379 "testTracebackArgs9(0x1, 0x2, 0x3, 0x4, {0x5, 0x6}, 0x7)"),
380 },
381
382
383 {
384 func() int {
385 poisonStack()
386 return testTracebackArgs10(1, 2, 3, 4, 5)
387 },
388 abiSel(
389 "testTracebackArgs10(0xffffffff?, 0xffffffff?, 0xffffffff?, 0xffffffff?, 0xffffffff?)",
390 "testTracebackArgs10(0x1, 0x2, 0x3, 0x4, 0x5)"),
391 },
392
393
394 {
395 func() int {
396 poisonStack()
397 return testTracebackArgs11a(1, 2, 3)
398 },
399 abiSel(
400 "testTracebackArgs11a(0xffffffff?, 0xffffffff?, 0xffffffff?)",
401 "testTracebackArgs11a(0x1, 0x2, 0x3)"),
402 },
403
404
405 {
406 func() int {
407 poisonStack()
408 return testTracebackArgs11b(1, 2, 3, 4)
409 },
410 abiSel(
411 "testTracebackArgs11b(0xffffffff?, 0xffffffff?, 0x3?, 0x4)",
412 "testTracebackArgs11b(0x1, 0x2, 0x3, 0x4)"),
413 },
414 }
415 for _, test := range tests {
416 n := test.fn()
417 got := testTracebackArgsBuf[:n]
418 if !bytes.Contains(got, []byte(test.expect)) {
419 t.Errorf("traceback does not contain expected string: want %q, got\n%s", test.expect, got)
420 }
421 }
422 }
423
424
425 func testTracebackArgs1(a, b, c, d, e int) int {
426 n := runtime.Stack(testTracebackArgsBuf[:], false)
427 if a < 0 {
428
429 return a + b + c + d + e
430 }
431 return n
432 }
433
434
435 func testTracebackArgs2(a bool, b struct {
436 a, b, c int
437 x [2]int
438 }, _ [0]int, d [3]byte) int {
439 n := runtime.Stack(testTracebackArgsBuf[:], false)
440 if a {
441
442 return b.a + b.b + b.c + b.x[0] + b.x[1] + int(d[0]) + int(d[1]) + int(d[2])
443 }
444 return n
445
446 }
447
448
449
450 func testTracebackArgs3(x [3]byte, a, b, c int, y [3]byte) int {
451 n := runtime.Stack(testTracebackArgsBuf[:], false)
452 if a < 0 {
453
454 return int(x[0]) + int(x[1]) + int(x[2]) + a + b + c + int(y[0]) + int(y[1]) + int(y[2])
455 }
456 return n
457 }
458
459
460 func testTracebackArgs4(a bool, x [1][1][1][1][1][1][1][1][1][1]int) int {
461 n := runtime.Stack(testTracebackArgsBuf[:], false)
462 if a {
463 panic(x)
464 }
465 return n
466 }
467
468
469 func testTracebackArgs5(a bool, x struct {
470 x int
471 y [0]int
472 z [2][0]int
473 }, _, _, _, _, _, _, _, _, _, _, _, _ [0]int) int {
474 n := runtime.Stack(testTracebackArgsBuf[:], false)
475 if a {
476 panic(x)
477 }
478 return n
479 }
480
481
482 func testTracebackArgs6a(a, b, c, d, e, f, g, h, i, j int) int {
483 n := runtime.Stack(testTracebackArgsBuf[:], false)
484 if a < 0 {
485
486 return a + b + c + d + e + f + g + h + i + j
487 }
488 return n
489 }
490
491
492 func testTracebackArgs6b(a, b, c, d, e, f, g, h, i, j, k int) int {
493 n := runtime.Stack(testTracebackArgsBuf[:], false)
494 if a < 0 {
495
496 return a + b + c + d + e + f + g + h + i + j + k
497 }
498 return n
499 }
500
501
502 func testTracebackArgs7a(a [10]int) int {
503 n := runtime.Stack(testTracebackArgsBuf[:], false)
504 if a[0] < 0 {
505
506 return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9]
507 }
508 return n
509 }
510
511
512 func testTracebackArgs7b(a [11]int) int {
513 n := runtime.Stack(testTracebackArgsBuf[:], false)
514 if a[0] < 0 {
515
516 return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + a[10]
517 }
518 return n
519 }
520
521
522 func testTracebackArgs7c(a [10]int, b int) int {
523 n := runtime.Stack(testTracebackArgsBuf[:], false)
524 if a[0] < 0 {
525
526 return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + b
527 }
528 return n
529 }
530
531
532 func testTracebackArgs7d(a [11]int, b int) int {
533 n := runtime.Stack(testTracebackArgsBuf[:], false)
534 if a[0] < 0 {
535
536 return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + a[10] + b
537 }
538 return n
539 }
540
541 type testArgsType8a struct {
542 a, b, c, d, e, f, g, h int
543 i [2]int
544 }
545 type testArgsType8b struct {
546 a, b, c, d, e, f, g, h int
547 i [3]int
548 }
549 type testArgsType8c struct {
550 a, b, c, d, e, f, g, h int
551 i [2]int
552 j int
553 }
554 type testArgsType8d struct {
555 a, b, c, d, e, f, g, h int
556 i [3]int
557 j int
558 }
559
560
561 func testTracebackArgs8a(a testArgsType8a) int {
562 n := runtime.Stack(testTracebackArgsBuf[:], false)
563 if a.a < 0 {
564
565 return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1]
566 }
567 return n
568 }
569
570
571 func testTracebackArgs8b(a testArgsType8b) int {
572 n := runtime.Stack(testTracebackArgsBuf[:], false)
573 if a.a < 0 {
574
575 return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1] + a.i[2]
576 }
577 return n
578 }
579
580
581 func testTracebackArgs8c(a testArgsType8c) int {
582 n := runtime.Stack(testTracebackArgsBuf[:], false)
583 if a.a < 0 {
584
585 return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1] + a.j
586 }
587 return n
588 }
589
590
591 func testTracebackArgs8d(a testArgsType8d) int {
592 n := runtime.Stack(testTracebackArgsBuf[:], false)
593 if a.a < 0 {
594
595 return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1] + a.i[2] + a.j
596 }
597 return n
598 }
599
600
601
602
603
604 func testTracebackArgs9(a int64, b int32, c int16, d int8, x [2]int, y int) int {
605 if a < 0 {
606 println(&y)
607 }
608 n := runtime.Stack(testTracebackArgsBuf[:], false)
609 if a < 0 {
610
611 return int(a) + int(c)
612 }
613 return n
614 }
615
616
617
618
619
620 func testTracebackArgs10(a, b, c, d, e int32) int {
621
622 return runtime.Stack(testTracebackArgsBuf[:], false)
623 }
624
625
626
627
628
629
630
631 func testTracebackArgs11a(a, b, c int32) int {
632 if a < 0 {
633 println(a, b, c)
634 }
635 if b < 0 {
636 return int(a + b + c)
637 }
638 return runtime.Stack(testTracebackArgsBuf[:], false)
639 }
640
641
642
643
644
645
646
647 func testTracebackArgs11b(a, b, c, d int32) int {
648 var x int32
649 if a < 0 {
650 print()
651 x = b
652 } else {
653 print()
654 x = c
655 }
656 if d < 0 {
657 return int(x + d)
658 }
659 return runtime.Stack(testTracebackArgsBuf[:], false)
660 }
661
662
663
664
665 func poisonStack() [20]int {
666 return [20]int{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
667 }
668
669 func TestTracebackParentChildGoroutines(t *testing.T) {
670 parent := fmt.Sprintf("goroutine %d", runtime.Goid())
671 var wg sync.WaitGroup
672 wg.Add(1)
673 go func() {
674 defer wg.Done()
675 buf := make([]byte, 1<<10)
676
677
678
679
680 stack := string(buf[:runtime.Stack(buf, false)])
681 child := fmt.Sprintf("goroutine %d", runtime.Goid())
682 if !strings.Contains(stack, parent) || !strings.Contains(stack, child) {
683 t.Errorf("did not see parent (%s) and child (%s) IDs in stack, got %s", parent, child, stack)
684 }
685 }()
686 wg.Wait()
687 }
688
689 type traceback struct {
690 frames []*tbFrame
691 createdBy *tbFrame
692 }
693
694 type tbFrame struct {
695 funcName string
696 args string
697 inlined bool
698
699
700
701 elided int
702
703 off int
704 }
705
706
707
708 func parseTraceback(t *testing.T, tb string) []*traceback {
709
710
711 off := 0
712 lineNo := 0
713 fatal := func(f string, args ...any) {
714 msg := fmt.Sprintf(f, args...)
715 t.Fatalf("%s (line %d):\n%s", msg, lineNo, tb)
716 }
717 parseFrame := func(funcName, args string) *tbFrame {
718
719 if !strings.HasPrefix(tb, "\t") {
720 fatal("missing source line")
721 }
722 _, tb, _ = strings.Cut(tb, "\n")
723 lineNo++
724 inlined := args == "..."
725 return &tbFrame{funcName: funcName, args: args, inlined: inlined, off: off}
726 }
727 var elidedRe = regexp.MustCompile(`^\.\.\.([0-9]+) frames elided\.\.\.$`)
728 var tbs []*traceback
729 var cur *traceback
730 tbLen := len(tb)
731 for len(tb) > 0 {
732 var line string
733 off = tbLen - len(tb)
734 line, tb, _ = strings.Cut(tb, "\n")
735 lineNo++
736 switch {
737 case strings.HasPrefix(line, "goroutine "):
738 cur = &traceback{}
739 tbs = append(tbs, cur)
740 case line == "":
741
742 cur = nil
743 case line[0] == '\t':
744 fatal("unexpected indent")
745 case strings.HasPrefix(line, "created by "):
746 funcName := line[len("created by "):]
747 cur.createdBy = parseFrame(funcName, "")
748 case strings.HasSuffix(line, ")"):
749 line = line[:len(line)-1]
750 funcName, args, found := strings.Cut(line, "(")
751 if !found {
752 fatal("missing (")
753 }
754 frame := parseFrame(funcName, args)
755 cur.frames = append(cur.frames, frame)
756 case elidedRe.MatchString(line):
757
758 nStr := elidedRe.FindStringSubmatch(line)
759 n, _ := strconv.Atoi(nStr[1])
760 frame := &tbFrame{elided: n}
761 cur.frames = append(cur.frames, frame)
762 }
763 }
764 return tbs
765 }
766
767
768
769 func parseTraceback1(t *testing.T, tb string) *traceback {
770 tbs := parseTraceback(t, tb)
771 if len(tbs) != 1 {
772 t.Fatalf("want 1 goroutine, got %d:\n%s", len(tbs), tb)
773 }
774 return tbs[0]
775 }
776
777
778 func testTracebackGenericFn[T any](buf []byte) int {
779 return runtime.Stack(buf[:], false)
780 }
781
782 func testTracebackGenericFnInlined[T any](buf []byte) int {
783 return runtime.Stack(buf[:], false)
784 }
785
786 type testTracebackGenericTyp[P any] struct{ x P }
787
788
789 func (t testTracebackGenericTyp[P]) M(buf []byte) int {
790 return runtime.Stack(buf[:], false)
791 }
792
793 func (t testTracebackGenericTyp[P]) Inlined(buf []byte) int {
794 return runtime.Stack(buf[:], false)
795 }
796
797 func TestTracebackGeneric(t *testing.T) {
798 if *flagQuick {
799 t.Skip("-quick")
800 }
801 var x testTracebackGenericTyp[int]
802 tests := []struct {
803 fn func([]byte) int
804 expect string
805 }{
806
807 {
808 testTracebackGenericFn[int],
809 "testTracebackGenericFn[...](",
810 },
811
812 {
813 func(buf []byte) int { return testTracebackGenericFnInlined[int](buf) },
814 "testTracebackGenericFnInlined[...](",
815 },
816
817 {
818 x.M,
819 "testTracebackGenericTyp[...].M(",
820 },
821
822 {
823 func(buf []byte) int { return x.Inlined(buf) },
824 "testTracebackGenericTyp[...].Inlined(",
825 },
826 }
827 var buf [1000]byte
828 for _, test := range tests {
829 n := test.fn(buf[:])
830 got := buf[:n]
831 if !bytes.Contains(got, []byte(test.expect)) {
832 t.Errorf("traceback does not contain expected string: want %q, got\n%s", test.expect, got)
833 }
834 if bytes.Contains(got, []byte("shape")) {
835 t.Errorf("traceback contains shape name: got\n%s", got)
836 }
837 }
838 }
839
View as plain text