// Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package runtime_test import ( "runtime" "strings" "testing" ) func f1(pan bool) []uintptr { return f2(pan) // line 14 } func f2(pan bool) []uintptr { return f3(pan) // line 18 } func f3(pan bool) []uintptr { if pan { panic("f3") // line 23 } ret := make([]uintptr, 20) return ret[:runtime.Callers(0, ret)] // line 26 } func testCallers(t *testing.T, pcs []uintptr, pan bool) { m := make(map[string]int, len(pcs)) frames := runtime.CallersFrames(pcs) for { frame, more := frames.Next() if frame.Function != "" { m[frame.Function] = frame.Line } if !more { break } } var seen []string for k := range m { seen = append(seen, k) } t.Logf("functions seen: %s", strings.Join(seen, " ")) var f3Line int if pan { f3Line = 23 } else { f3Line = 26 } want := []struct { name string line int }{ {"f1", 14}, {"f2", 18}, {"f3", f3Line}, } for _, w := range want { if got := m["runtime_test."+w.name]; got != w.line { t.Errorf("%s is line %d, want %d", w.name, got, w.line) } } } func TestCallers(t *testing.T) { testCallers(t, f1(false), false) } func TestCallersPanic(t *testing.T) { defer func() { if r := recover(); r == nil { t.Fatal("did not panic") } pcs := make([]uintptr, 20) pcs = pcs[:runtime.Callers(0, pcs)] testCallers(t, pcs, true) }() f1(true) }