Source file src/runtime/panic_test.go

     1  // Copyright 2020 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  
     5  package runtime_test
     6  
     7  import (
     8  	"slices"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  )
    13  
    14  // Test that panics print out the underlying value
    15  // when the underlying kind is directly printable.
    16  // Issue: https://golang.org/issues/37531
    17  func TestPanicWithDirectlyPrintableCustomTypes(t *testing.T) {
    18  	tests := []struct {
    19  		name            string
    20  		wantPanicPrefix string
    21  	}{
    22  		{"panicCustomBool", `panic: main.MyBool(true)`},
    23  		{"panicCustomComplex128", `panic: main.MyComplex128(32.1+10i)`},
    24  		{"panicCustomComplex64", `panic: main.MyComplex64(0.11+3i)`},
    25  		{"panicCustomFloat32", `panic: main.MyFloat32(-93.7)`},
    26  		{"panicCustomFloat64", `panic: main.MyFloat64(-93.7)`},
    27  		{"panicCustomInt", `panic: main.MyInt(93)`},
    28  		{"panicCustomInt8", `panic: main.MyInt8(93)`},
    29  		{"panicCustomInt16", `panic: main.MyInt16(93)`},
    30  		{"panicCustomInt32", `panic: main.MyInt32(93)`},
    31  		{"panicCustomInt64", `panic: main.MyInt64(93)`},
    32  		{"panicCustomString", `panic: main.MyString("Panic` + "\n\t" + `line two")`},
    33  		{"panicCustomUint", `panic: main.MyUint(93)`},
    34  		{"panicCustomUint8", `panic: main.MyUint8(93)`},
    35  		{"panicCustomUint16", `panic: main.MyUint16(93)`},
    36  		{"panicCustomUint32", `panic: main.MyUint32(93)`},
    37  		{"panicCustomUint64", `panic: main.MyUint64(93)`},
    38  		{"panicCustomUintptr", `panic: main.MyUintptr(93)`},
    39  		{"panicDeferFatal", "panic: runtime.errorString(\"invalid memory address or nil pointer dereference\")\n\tfatal error: sync: unlock of unlocked mutex"},
    40  		{"panicDoublieDeferFatal", "panic: runtime.errorString(\"invalid memory address or nil pointer dereference\") [recovered, repanicked]\n\tfatal error: sync: unlock of unlocked mutex"},
    41  	}
    42  
    43  	for _, tt := range tests {
    44  		t := t
    45  		t.Run(tt.name, func(t *testing.T) {
    46  			output := runTestProg(t, "testprog", tt.name)
    47  			if !strings.HasPrefix(output, tt.wantPanicPrefix) {
    48  				t.Fatalf("%q\nis not present in\n%s", tt.wantPanicPrefix, output)
    49  			}
    50  		})
    51  	}
    52  }
    53  
    54  func TestPanicRecoverSpeed(t *testing.T) {
    55  	// For issue 77062.
    56  	t.Skip("This test is too flaky at the moment. But it does normally pass. Suggestions for making it less flaky are welcome.")
    57  
    58  	// Recursive function that does defer/recover/repanic.
    59  	var f func(int)
    60  	f = func(n int) {
    61  		if n == 0 {
    62  			panic("done")
    63  		}
    64  		defer func() {
    65  			err := recover()
    66  			panic(err)
    67  		}()
    68  		f(n - 1)
    69  	}
    70  
    71  	time := func(f func()) time.Duration {
    72  		var times []time.Duration
    73  		for range 10 {
    74  			start := time.Now()
    75  			f()
    76  			times = append(times, time.Since(start))
    77  		}
    78  		slices.Sort(times)
    79  		times = times[1 : len(times)-1] // skip high and low, to reduce noise
    80  		var avg time.Duration
    81  		for _, v := range times {
    82  			avg += v / time.Duration(len(times))
    83  		}
    84  		return avg
    85  	}
    86  
    87  	a := time(func() {
    88  		defer func() { recover() }()
    89  		f(1024)
    90  	})
    91  	b := time(func() {
    92  		defer func() { recover() }()
    93  		f(2048)
    94  	})
    95  	m := b.Seconds() / a.Seconds()
    96  	t.Logf("a: %v, b: %v, m: %v", a, b, m)
    97  	if m > 3.5 {
    98  		t.Errorf("more than 2x time increase: %v", m)
    99  	}
   100  }
   101  

View as plain text