1// Copyright 2009 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package runtime_test 6 7import ( 8 "runtime" 9 "strings" 10 "testing" 11) 12 13var _ = runtime.Caller 14var _ = strings.HasSuffix 15 16type _ testing.T 17 18func TestCaller(t *testing.T) { 19 procs := runtime.GOMAXPROCS(-1) 20 c := make(chan bool, procs) 21 for p := 0; p < procs; p++ { 22 go func() { 23 for i := 0; i < 1000; i++ { 24 testCallerFoo(t) 25 } 26 c <- true 27 }() 28 defer func() { 29 <-c 30 }() 31 } 32} 33 34// These are marked noinline so that we can use FuncForPC 35// in testCallerBar. 36//go:noinline 37func testCallerFoo(t *testing.T) { 38 testCallerBar(t) 39} 40 41//go:noinline 42func testCallerBar(t *testing.T) { 43 for i := 0; i < 2; i++ { 44 pc, file, line, ok := runtime.Caller(i) 45 f := runtime.FuncForPC(pc) 46 if !ok || 47 !strings.HasSuffix(file, "symtab_test.go") || 48 // FuncForPC doesn't work gccgo, because of inlining. 49 // (i == 0 && !strings.HasSuffix(f.Name(), "testCallerBar")) || 50 // (i == 1 && !strings.HasSuffix(f.Name(), "testCallerFoo")) || 51 line < 5 || line > 1000 || 52 f.Entry() >= pc { 53 t.Errorf("incorrect symbol info %d: %t %d %d %s %s %d", 54 i, ok, f.Entry(), pc, f.Name(), file, line) 55 } 56 } 57} 58 59func lineNumber() int { 60 _, _, line, _ := runtime.Caller(1) 61 return line // return 0 for error 62} 63 64// Do not add/remove lines in this block without updating the line numbers. 65var firstLine = lineNumber() // 0 66var ( // 1 67 lineVar1 = lineNumber() // 2 68 lineVar2a, lineVar2b = lineNumber(), lineNumber() // 3 69) // 4 70var compLit = []struct { // 5 71 lineA, lineB int // 6 72}{ // 7 73 { // 8 74 lineNumber(), lineNumber(), // 9 75 }, // 10 76 { // 11 77 lineNumber(), // 12 78 lineNumber(), // 13 79 }, // 14 80 { // 15 81 lineB: lineNumber(), // 16 82 lineA: lineNumber(), // 17 83 }, // 18 84} // 19 85var arrayLit = [...]int{lineNumber(), // 20 86 lineNumber(), lineNumber(), // 21 87 lineNumber(), // 22 88} // 23 89var sliceLit = []int{lineNumber(), // 24 90 lineNumber(), lineNumber(), // 25 91 lineNumber(), // 26 92} // 27 93var mapLit = map[int]int{ // 28 94 29: lineNumber(), // 29 95 30: lineNumber(), // 30 96 lineNumber(): 31, // 31 97 lineNumber(): 32, // 32 98} // 33 99var intLit = lineNumber() + // 34 100 lineNumber() + // 35 101 lineNumber() // 36 102func trythis() { // 37 103 recordLines(lineNumber(), // 38 104 lineNumber(), // 39 105 lineNumber()) // 40 106} 107 108// Modifications below this line are okay. 109 110var l38, l39, l40 int 111 112func recordLines(a, b, c int) { 113 l38 = a 114 l39 = b 115 l40 = c 116} 117 118func TestLineNumber(t *testing.T) { 119 trythis() 120 for _, test := range []struct { 121 name string 122 val int 123 want int 124 }{ 125 {"firstLine", firstLine, 0}, 126 {"lineVar1", lineVar1, 2}, 127 {"lineVar2a", lineVar2a, 3}, 128 {"lineVar2b", lineVar2b, 3}, 129 {"compLit[0].lineA", compLit[0].lineA, 9}, 130 {"compLit[0].lineB", compLit[0].lineB, 9}, 131 {"compLit[1].lineA", compLit[1].lineA, 12}, 132 {"compLit[1].lineB", compLit[1].lineB, 13}, 133 {"compLit[2].lineA", compLit[2].lineA, 17}, 134 {"compLit[2].lineB", compLit[2].lineB, 16}, 135 136 {"arrayLit[0]", arrayLit[0], 20}, 137 {"arrayLit[1]", arrayLit[1], 21}, 138 {"arrayLit[2]", arrayLit[2], 21}, 139 {"arrayLit[3]", arrayLit[3], 22}, 140 141 {"sliceLit[0]", sliceLit[0], 24}, 142 {"sliceLit[1]", sliceLit[1], 25}, 143 {"sliceLit[2]", sliceLit[2], 25}, 144 {"sliceLit[3]", sliceLit[3], 26}, 145 146 {"mapLit[29]", mapLit[29], 29}, 147 {"mapLit[30]", mapLit[30], 30}, 148 {"mapLit[31]", mapLit[31+firstLine] + firstLine, 31}, // nb it's the key not the value 149 {"mapLit[32]", mapLit[32+firstLine] + firstLine, 32}, // nb it's the key not the value 150 151 {"intLit", intLit - 2*firstLine, 34 + 35 + 36}, 152 153 {"l38", l38, 38}, 154 {"l39", l39, 39}, 155 {"l40", l40, 40}, 156 } { 157 if got := test.val - firstLine; got != test.want { 158 t.Errorf("%s on firstLine+%d want firstLine+%d (firstLine=%d, val=%d)", 159 test.name, got, test.want, firstLine, test.val) 160 } 161 } 162} 163 164func TestNilName(t *testing.T) { 165 defer func() { 166 if ex := recover(); ex != nil { 167 t.Fatalf("expected no nil panic, got=%v", ex) 168 } 169 }() 170 if got := (*runtime.Func)(nil).Name(); got != "" { 171 t.Errorf("Name() = %q, want %q", got, "") 172 } 173} 174