go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/starlark/builtins/stacktrace_test.go (about) 1 // Copyright 2018 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package builtins 16 17 import ( 18 "fmt" 19 "testing" 20 21 "go.starlark.net/starlark" 22 23 . "github.com/smartystreets/goconvey/convey" 24 . "go.chromium.org/luci/common/testing/assertions" 25 ) 26 27 func TestStacktrace(t *testing.T) { 28 t.Parallel() 29 30 runScript := func(code string) (string, error) { 31 out, err := starlark.ExecFile(&starlark.Thread{}, "main", code, starlark.StringDict{ 32 "stacktrace": Stacktrace, 33 }) 34 if err != nil { 35 return "", err 36 } 37 if s, ok := out["out"].(starlark.String); ok { 38 return NormalizeStacktrace(s.GoString()), nil 39 } 40 return "", fmt.Errorf("not a string: %s", out["out"]) 41 } 42 43 Convey("Works", t, func() { 44 out, err := runScript(` 45 def func1(): 46 return func2() 47 48 def func2(): 49 return stacktrace() 50 51 s = func1() 52 53 out = str(s) 54 `) 55 So(err, ShouldBeNil) 56 So(out, ShouldEqual, `Traceback (most recent call last): 57 main: in <toplevel> 58 main: in func1 59 main: in func2 60 <builtin>: in stacktrace 61 `) 62 }) 63 64 Convey("Skips frames", t, func() { 65 out, err := runScript(` 66 def func1(): 67 return func2() 68 69 def func2(): 70 return stacktrace(skip=2) 71 72 out = str(func1()) 73 `) 74 So(err, ShouldBeNil) 75 So(out, ShouldEqual, `Traceback (most recent call last): 76 main: in <toplevel> 77 main: in func1 78 `) 79 }) 80 81 Convey("Fails if asked to skip too much", t, func() { 82 _, err := runScript(` 83 def func1(): 84 return func2() 85 86 def func2(): 87 return stacktrace(skip=5) 88 89 out = str(func1()) 90 `) 91 So(err, ShouldErrLike, "stacktrace: the stack is not deep enough to skip 5 levels, has only 4 frames") 92 }) 93 94 Convey("Fails on negative skip", t, func() { 95 _, err := runScript(`stacktrace(-1)`) 96 So(err, ShouldErrLike, "stacktrace: bad 'skip' value -1") 97 }) 98 99 Convey("Fails on wrong type", t, func() { 100 _, err := runScript(`stacktrace('zzz')`) 101 So(err, ShouldErrLike, "stacktrace: for parameter skip: got string, want int") 102 }) 103 } 104 105 func TestNormalizeStacktrace(t *testing.T) { 106 t.Parallel() 107 108 Convey("Works", t, func() { 109 in := `Traceback (most recent call last): 110 main:8:1: in <toplevel> 111 main:3:2: in func1 112 main:6:3: in func2 113 <builtin>: in stacktrace 114 115 skipped line 116 ` 117 out := `Traceback (most recent call last): 118 main: in <toplevel> 119 main: in func1 120 main: in func2 121 <builtin>: in stacktrace 122 123 skipped line 124 ` 125 So(NormalizeStacktrace(in), ShouldEqual, out) 126 }) 127 }