blob: 5a4b6ae633c0b5f4a2e2f4b385a1d41529b7f5b5 [file]
// Copyright 2020 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 (
"slices"
"strings"
"testing"
"time"
)
// Test that panics print out the underlying value
// when the underlying kind is directly printable.
// Issue: https://golang.org/issues/37531
func TestPanicWithDirectlyPrintableCustomTypes(t *testing.T) {
tests := []struct {
name string
wantPanicPrefix string
}{
{"panicCustomBool", `panic: main.MyBool(true)`},
{"panicCustomComplex128", `panic: main.MyComplex128(32.1+10i)`},
{"panicCustomComplex64", `panic: main.MyComplex64(0.11+3i)`},
{"panicCustomFloat32", `panic: main.MyFloat32(-93.7)`},
{"panicCustomFloat64", `panic: main.MyFloat64(-93.7)`},
{"panicCustomInt", `panic: main.MyInt(93)`},
{"panicCustomInt8", `panic: main.MyInt8(93)`},
{"panicCustomInt16", `panic: main.MyInt16(93)`},
{"panicCustomInt32", `panic: main.MyInt32(93)`},
{"panicCustomInt64", `panic: main.MyInt64(93)`},
{"panicCustomString", `panic: main.MyString("Panic` + "\n\t" + `line two")`},
{"panicCustomUint", `panic: main.MyUint(93)`},
{"panicCustomUint8", `panic: main.MyUint8(93)`},
{"panicCustomUint16", `panic: main.MyUint16(93)`},
{"panicCustomUint32", `panic: main.MyUint32(93)`},
{"panicCustomUint64", `panic: main.MyUint64(93)`},
{"panicCustomUintptr", `panic: main.MyUintptr(93)`},
{"panicDeferFatal", "panic: runtime.errorString(\"invalid memory address or nil pointer dereference\")\n\tfatal error: sync: unlock of unlocked mutex"},
{"panicDoublieDeferFatal", "panic: runtime.errorString(\"invalid memory address or nil pointer dereference\") [recovered, repanicked]\n\tfatal error: sync: unlock of unlocked mutex"},
}
for _, tt := range tests {
t := t
t.Run(tt.name, func(t *testing.T) {
output := runTestProg(t, "testprog", tt.name)
if !strings.HasPrefix(output, tt.wantPanicPrefix) {
t.Fatalf("%q\nis not present in\n%s", tt.wantPanicPrefix, output)
}
})
}
}
func TestPanicRecoverSpeed(t *testing.T) {
// For issue 77062.
t.Skip("This test is too flaky at the moment. But it does normally pass. Suggestions for making it less flaky are welcome.")
// Recursive function that does defer/recover/repanic.
var f func(int)
f = func(n int) {
if n == 0 {
panic("done")
}
defer func() {
err := recover()
panic(err)
}()
f(n - 1)
}
time := func(f func()) time.Duration {
var times []time.Duration
for range 10 {
start := time.Now()
f()
times = append(times, time.Since(start))
}
slices.Sort(times)
times = times[1 : len(times)-1] // skip high and low, to reduce noise
var avg time.Duration
for _, v := range times {
avg += v / time.Duration(len(times))
}
return avg
}
a := time(func() {
defer func() { recover() }()
f(1024)
})
b := time(func() {
defer func() { recover() }()
f(2048)
})
m := b.Seconds() / a.Seconds()
t.Logf("a: %v, b: %v, m: %v", a, b, m)
if m > 3.5 {
t.Errorf("more than 2x time increase: %v", m)
}
}