github.com/haraldrudell/parl@v0.4.176/pruntime/invocation-id_test.go (about)

     1  /*
     2  © 2022–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package pruntime
     7  
     8  import (
     9  	"runtime/debug"
    10  	"strings"
    11  	"sync"
    12  	"testing"
    13  )
    14  
    15  type InvocationTestType struct{}
    16  
    17  func (tt *InvocationTestType) FuncName(wg *sync.WaitGroup, stack *string) {
    18  	defer wg.Done()
    19  
    20  	*stack = tt.Func2() // second-level funciton to get more levels in the stack trace
    21  }
    22  
    23  func (tt *InvocationTestType) Func2() (stack string) {
    24  	return string(debug.Stack())
    25  }
    26  
    27  func (tt *InvocationTestType) DoInvocation() (debugStack, actual string) {
    28  	var wg sync.WaitGroup
    29  	wg.Add(1)
    30  	go tt.Invocation(&wg, &debugStack, &actual)
    31  	wg.Wait()
    32  	return
    33  }
    34  
    35  func (tt *InvocationTestType) Invocation(wg *sync.WaitGroup, debugStack, actual *string) {
    36  	*debugStack = string(debug.Stack())
    37  	*actual = Invocation(0)
    38  	wg.Done()
    39  	return
    40  }
    41  
    42  /*
    43  We are generating a stack trace and want a real function name.
    44  This means the function must be in the package scope.
    45  Secondly, we want a short and predictable stack trace.
    46  This means the function must be invoked as a goroutine.
    47  */
    48  func TestInvocation(t *testing.T) {
    49  	invocationIndex := 1
    50  	debugStackIndex := 3
    51  	var tt InvocationTestType
    52  	debugStack, invocationResult := tt.DoInvocation()
    53  
    54  	// get the Invocation caller’s function name:
    55  	// github.com/haraldrudell/parl/runt.(*InvocationTestType).Invocation(0x0?, 0x0?, 0x14000104570, 0x14000104580)
    56  	actual := strings.Split(invocationResult, "\n")[invocationIndex] // github.com/haraldrudell/parl/runt.(*InvocationTestType).Invocation(0x0?, 0x0?, 0x14000104570, 0x14000104580)
    57  
    58  	// get our own debug.Stack value
    59  	expected := strings.Split(debugStack, "\n")[debugStackIndex]
    60  
    61  	if actual != expected {
    62  		t.Errorf("Invocation failed :\n%q expected:\n%q", actual, expected)
    63  	}
    64  }
    65  func TestDebugStack(t *testing.T) {
    66  	/*
    67  		var stack string
    68  		var wg sync.WaitGroup
    69  		var tt InvocationTestType
    70  		wg.Add(1)
    71  		go tt.FuncName(&wg, &stack)
    72  		wg.Wait()
    73  	*/
    74  	/*
    75  		stack string for go1.18: "
    76  		goroutine 19 [running]:\n
    77  		runtime/debug.Stack()\n
    78  		\t/opt/homebrew/Cellar/go/1.18/libexec/src/runtime/debug/stack.go:24 +0x68\n
    79  		github.com/haraldrudell/parl/runt.(*InvocationTestType).Func2(...)\n
    80  		\t/opt/sw/parl/runt/invocation_test.go:25\n
    81  		github.com/haraldrudell/parl/runt.(*InvocationTestType).FuncName(0x0?, 0x0?, 0x14000104570)\n
    82  		\t/opt/sw/parl/runt/invocation_test.go:21 +0x50
    83  		\ncreated by github.com/haraldrudell/parl/runt.TestInvocation\n
    84  		\t/opt/sw/parl/runt/invocation_test.go:37 +0xb0\n"
    85  	*/
    86  	//t.Errorf("stack string for %s:\n%s", runtime.Version(), strconv.Quote(stack))
    87  	/*
    88  		the stack trace contains multiple newline-separated lines
    89  		first line is a goroutine line
    90  		then there are a series of 2-line stack frames, second line beginning with a tab
    91  		first frame is debug.Stack
    92  		last frame is the go statement creating the goroutine
    93  		the stack trace ends with a newline
    94  	*/
    95  }