diff --git a/README.md b/README.md index c213187..fc00dd6 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Stacktrace adds compact, contextual call-site information to Go errors. -> [!NOTE] +> [!IMPORTANT] > This repository is an actively maintained fork of > [palantir/stacktrace](https://github.com/palantir/stacktrace), which has been > inactive for many years. The fork preserves the original Apache-2.0-licensed @@ -77,7 +77,7 @@ func WriteAll(baseDir string, entities []Entity) error { path := filepath.Join(baseDir, fileNameForEntity(ent)) err = Write(path, ent) if err != nil { - return stacktrace.Propagate(err, "Failed to write %v to %s", ent, path) + return stacktrace.Propagatef(err, "Failed to write %v to %s", ent, path) } } return nil @@ -86,20 +86,21 @@ func WriteAll(baseDir string, entities []Entity) error { ## Functions -#### `stacktrace.Propagate(err error, format string, args ...any) error` +#### `stacktrace.Propagatef(err error, format string, args ...any) error` -Propagate wraps an error to include line number information. This is going to be -your most common stacktrace call. +Propagatef wraps an error with a formatted message and line number +information. Use `Propagate` when the message has no formatting arguments. +Both functions return `nil` when `err` is nil. -As in all of these functions, the `format` and `args` work like `fmt.Errorf`. +The `format` and `args` work like `fmt.Sprintf`. -The message passed to Propagate should describe the action that failed, +The message passed to Propagatef should describe the action that failed, resulting in `err`. The canonical call looks like this: ```go result, err := process(arg) if err != nil { - return nil, stacktrace.Propagate(err, "Failed to process %v", arg) + return nil, stacktrace.Propagatef(err, "Failed to process %v", arg) } ``` @@ -132,14 +133,23 @@ little guilty every time you do this. This example also illustrates the behavior of Propagate when `err` is nil – it returns nil as well. There is no need to check `if err != nil`. -#### `stacktrace.NewError(format string, args ...any) error` +#### `stacktrace.NewErrorf(format string, args ...any) error` + +NewErrorf creates an error with a formatted message and line number information. +Use `NewError` when the message has no formatting arguments. -NewError is a drop-in replacement for `fmt.Errorf` that includes line number -information. The canonical call looks like this: +The `*f` helpers format their messages like `fmt.Sprintf`. Their counterparts +without `f` remain supported for compatibility. + +> [!NOTE] +> Unlike `fmt.Errorf`, `%w` is not supported; use `Propagate` or `Propagatef` to +> wrap a cause. + +The canonical call looks like this: ```go if !IsOkay(arg) { - return stacktrace.NewError("Expected %v to be okay", arg) + return stacktrace.NewErrorf("Expected %v to be okay", arg) } ``` @@ -165,12 +175,18 @@ using that. NoCode is the error code of errors with no code explicitly attached. An ordinary `stacktrace.Propagate` preserves the error code of an error. -#### `stacktrace.PropagateWithCode(err error, code ErrorCode, format string, args ...any) error` +#### `stacktrace.PropagateWithCodef(err error, code ErrorCode, format string, args ...any) error` + +#### `stacktrace.NewErrorWithCodef(code ErrorCode, format string, args ...any) error` -#### `stacktrace.NewErrorWithCode(code ErrorCode, format string, args ...any) error` +#### `stacktrace.NewMessageWithCodef(code ErrorCode, format string, args ...any) error` -PropagateWithCode and NewErrorWithCode are analogous to Propagate and NewError -but also attach an error code. +PropagateWithCodef, NewErrorWithCodef, and NewMessageWithCodef are analogous to +Propagatef, NewErrorf, and NewMessageWithCode respectively, but also attach an +error code. Propagate and Propagatef inherit existing codes, while +PropagateWithCode and PropagateWithCodef override them with the supplied code. +Their non-`f` counterparts remain supported for compatibility. PropagateWithCodef +retains nil propagation. ```go _, err := os.Stat(manifestPath) @@ -179,11 +195,9 @@ if os.IsNotExist(err) { } ``` -#### `stacktrace.NewMessageWithCode(code ErrorCode, format string, args ...any) error` - The error code mechanism can be useful by itself even where stack traces with -line numbers are not required. NewMessageWithCode returns an error that prints -just like `fmt.Errorf` with no line number, but including a code. +line numbers are not required. `NewMessageWithCodef` returns an error that +formats its message like `fmt.Sprintf`, but including a code. ```go ttl := req.URL.Query().Get("ttl") @@ -204,7 +218,7 @@ for i := 0; i < attempts; i++ { } // try a few more times } -return stacktrace.NewError("timed out after %d attempts", attempts) +return stacktrace.NewErrorf("timed out after %d attempts", attempts) ``` GetCode returns the special value `stacktrace.NoCode` if `err` is nil or if diff --git a/docs/superpowers/plans/2026-07-19-formatting-helper-api.md b/docs/superpowers/plans/2026-07-19-formatting-helper-api.md new file mode 100644 index 0000000..9f4495d --- /dev/null +++ b/docs/superpowers/plans/2026-07-19-formatting-helper-api.md @@ -0,0 +1,327 @@ +# Formatting Helper API Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add `*f` formatting helpers that GoLand recognizes while preserving the existing API and exact stacktrace behavior. + +**Architecture:** Add five public sibling functions beside their existing counterparts in `stacktrace.go`. Stack-capturing helpers call `create` directly to preserve `runtime.Caller(2)` attribution; tests exercise the public API and verify messages, codes, nil propagation, and caller names. + +**Tech Stack:** Go 1.18+, standard library `fmt`/`errors`, `testify/assert` + +## Global Constraints + +- Keep every existing public function and its formatting behavior backward-compatible. +- Add exactly `NewErrorf`, `Propagatef`, `NewErrorWithCodef`, `PropagateWithCodef`, and `NewMessageWithCodef`. +- Preserve direct call depth between every stack-capturing public helper and `create`. +- Preserve nil propagation and error-code inheritance/override semantics. +- Keep tests in the external `stacktrace_test` package. + +--- + +### Task 1: Add formatting helper APIs + +**Files:** +- Modify: `functions_for_test.go` +- Modify: `stacktrace_test.go` +- Modify: `stacktrace.go` + +**Interfaces:** +- Consumes: existing `create(err error, code ErrorCode, format string, args ...any) error`, `NoCode`, and private `stacktrace` +- Produces: + - `NewErrorf(format string, args ...any) error` + - `Propagatef(err error, format string, args ...any) error` + - `NewErrorWithCodef(code ErrorCode, format string, args ...any) error` + - `PropagateWithCodef(err error, code ErrorCode, format string, args ...any) error` + - `NewMessageWithCodef(code ErrorCode, format string, args ...any) error` + +- [ ] **Step 1: Add public call-site fixtures** + +Append these fixtures to `functions_for_test.go` so existing exact line assertions do not move: + +```go +func newErrorfAtCallSite() error { + return stacktrace.NewErrorf("new %d", 7) +} + +func propagatefAtCallSite(err error) error { + return stacktrace.Propagatef(err, "propagate %d", 7) +} + +func newErrorWithCodefAtCallSite() error { + return stacktrace.NewErrorWithCodef(EcodeInvalidVillain, "coded %d", 7) +} + +func propagateWithCodefAtCallSite(err error) error { + return stacktrace.PropagateWithCodef(err, EcodeNotFastEnough, "coded propagate %d", 7) +} +``` + +- [ ] **Step 2: Write failing behavior tests** + +Append these tests to `stacktrace_test.go`: + +```go +func TestFormattingHelpers(t *testing.T) { + root := errors.New("root") + + tests := []struct { + name string + err error + expected string + code stacktrace.ErrorCode + }{ + { + name: "new error", + err: stacktrace.NewErrorf("new %d", 7), + expected: "new 7", + code: stacktrace.NoCode, + }, + { + name: "propagate", + err: stacktrace.Propagatef(root, "propagate %d", 7), + expected: "propagate 7: root", + code: stacktrace.NoCode, + }, + { + name: "new error with code", + err: stacktrace.NewErrorWithCodef(EcodeInvalidVillain, "coded %d", 7), + expected: "coded 7", + code: EcodeInvalidVillain, + }, + { + name: "propagate with code", + err: stacktrace.PropagateWithCodef(root, EcodeNotFastEnough, "coded propagate %d", 7), + expected: "coded propagate 7: root", + code: EcodeNotFastEnough, + }, + { + name: "new message with code", + err: stacktrace.NewMessageWithCodef(EcodeInvalidVillain, "message %d", 7), + expected: "message 7", + code: EcodeInvalidVillain, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + assert.Equal(t, test.expected, fmt.Sprintf("%#s", test.err)) + assert.Equal(t, test.code, stacktrace.GetCode(test.err)) + }) + } +} + +func TestFormattingHelpersPreserveCode(t *testing.T) { + err := stacktrace.NewErrorWithCodef(EcodeInvalidVillain, "inner %d", 7) + err = stacktrace.Propagatef(err, "outer %d", 8) + + assert.Equal(t, EcodeInvalidVillain, stacktrace.GetCode(err)) + assert.Equal(t, "outer 8: inner 7", fmt.Sprintf("%#s", err)) +} + +func TestFormattingPropagationNil(t *testing.T) { + assert.Nil(t, stacktrace.Propagatef(nil, "propagate %d", 7)) + assert.Nil(t, stacktrace.PropagateWithCodef(nil, EcodeInvalidVillain, "propagate %d", 7)) +} + +func TestFormattingHelpersCaptureCaller(t *testing.T) { + useFixturePaths(t) + root := errors.New("root") + + tests := []struct { + name string + err error + function string + }{ + {name: "new error", err: newErrorfAtCallSite(), function: "newErrorfAtCallSite"}, + {name: "propagate", err: propagatefAtCallSite(root), function: "propagatefAtCallSite"}, + {name: "new error with code", err: newErrorWithCodefAtCallSite(), function: "newErrorWithCodefAtCallSite"}, + {name: "propagate with code", err: propagateWithCodefAtCallSite(root), function: "propagateWithCodefAtCallSite"}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + trace := fmt.Sprintf("%+s", test.err) + assert.Contains(t, trace, fixturePath("functions_for_test.go")) + assert.Contains(t, trace, "("+test.function+")") + }) + } +} +``` + +- [ ] **Step 3: Run the targeted tests and verify they fail** + +Run: + +```bash +go test -run '^TestFormatting' . +``` + +Expected: build failure reporting undefined `stacktrace.NewErrorf`, `stacktrace.Propagatef`, `stacktrace.NewErrorWithCodef`, `stacktrace.PropagateWithCodef`, and `stacktrace.NewMessageWithCodef`. + +- [ ] **Step 4: Implement direct formatting siblings** + +Add each function immediately after its existing counterpart in `stacktrace.go`: + +```go +// NewErrorf is the formatting variant of NewError. +func NewErrorf(format string, args ...any) error { + return create(nil, NoCode, format, args...) +} + +// Propagatef is the formatting variant of Propagate. +func Propagatef(err error, format string, args ...any) error { + if err == nil { + return nil + } + return create(err, NoCode, format, args...) +} + +// NewErrorWithCodef is the formatting variant of NewErrorWithCode. +func NewErrorWithCodef(code ErrorCode, format string, args ...any) error { + return create(nil, code, format, args...) +} + +// PropagateWithCodef is the formatting variant of PropagateWithCode. +func PropagateWithCodef(err error, code ErrorCode, format string, args ...any) error { + if err == nil { + return nil + } + return create(err, code, format, args...) +} + +// NewMessageWithCodef is the formatting variant of NewMessageWithCode. +func NewMessageWithCodef(code ErrorCode, format string, args ...any) error { + return &stacktrace{ + message: fmt.Sprintf(format, args...), + code: code, + } +} +``` + +- [ ] **Step 5: Format and run targeted tests** + +Run: + +```bash +gofmt -w stacktrace.go stacktrace_test.go functions_for_test.go +go test -run '^TestFormatting' . +``` + +Expected: all `TestFormatting*` tests pass. + +- [ ] **Step 6: Run package regression tests** + +Run: + +```bash +go test -race -cover ./... +``` + +Expected: all packages pass under the race detector. + +- [ ] **Step 7: Commit the API and tests** + +```bash +git add stacktrace.go stacktrace_test.go functions_for_test.go +git commit -m "feat: add formatting helper APIs" \ + -m "Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>" \ + -m "Copilot-Session: 1601a53e-b461-4419-af08-50a1839599b5" +``` + +### Task 2: Document formatting helper usage + +**Files:** +- Modify: `README.md` + +**Interfaces:** +- Consumes: the five `*f` functions added in Task 1 +- Produces: user guidance that distinguishes formatting calls from static-message calls + +- [ ] **Step 1: Update interpolated README examples** + +Change calls with interpolation arguments to their formatting variants: + +```go +return stacktrace.Propagatef(err, "Failed to write %v to %s", ent, path) +``` + +```go +return nil, stacktrace.Propagatef(err, "Failed to process %v", arg) +``` + +```go +return stacktrace.NewErrorf("Expected %v to be okay", arg) +``` + +```go +return stacktrace.NewErrorf("timed out after %d attempts", attempts) +``` + +Keep static-message calls such as `Propagate(err, "")` and +`Propagate(err, "Failed to create base directory")` unchanged. + +- [ ] **Step 2: Document all five signatures** + +Change the primary formatted signatures and code variants to: + +```markdown +#### `stacktrace.Propagatef(err error, format string, args ...any) error` + +`Propagatef` wraps an error with a formatted message and line number +information. Use `Propagate` when the message has no formatting arguments. +Both functions return `nil` when `err` is nil. +``` + +```markdown +#### `stacktrace.NewErrorf(format string, args ...any) error` + +`NewErrorf` is a drop-in replacement for `fmt.Errorf` that includes line +number information. Use `NewError` when the message has no formatting +arguments. +``` + +```markdown +#### `stacktrace.PropagateWithCodef(err error, code ErrorCode, format string, args ...any) error` + +#### `stacktrace.NewErrorWithCodef(code ErrorCode, format string, args ...any) error` + +#### `stacktrace.NewMessageWithCodef(code ErrorCode, format string, args ...any) error` +``` + +State that the `*f` code variants format their messages like `fmt.Sprintf`, +that their counterparts without `f` remain supported for compatibility, and +that `PropagateWithCodef` retains nil propagation. + +- [ ] **Step 3: Verify README API names and fences** + +Run: + +```bash +rg -n 'Propagatef|NewErrorf|WithCodef' README.md +pre-commit run --all-files +``` + +Expected: every interpolated stacktrace example uses a `*f` function, all five +new names appear in the function documentation, and all pre-commit hooks pass. + +- [ ] **Step 4: Run the final quality gate** + +Run: + +```bash +go test -race -cover ./... +go vet ./... +golangci-lint fmt --diff +golangci-lint run +``` + +Expected: every command exits successfully with no findings. + +- [ ] **Step 5: Commit the documentation** + +```bash +git add README.md +git commit -m "docs: explain formatting helper APIs" \ + -m "Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>" \ + -m "Copilot-Session: 1601a53e-b461-4419-af08-50a1839599b5" +``` diff --git a/docs/superpowers/specs/2026-07-19-formatting-helper-api-design.md b/docs/superpowers/specs/2026-07-19-formatting-helper-api-design.md new file mode 100644 index 0000000..a111cf4 --- /dev/null +++ b/docs/superpowers/specs/2026-07-19-formatting-helper-api-design.md @@ -0,0 +1,54 @@ +# Formatting Helper API Design + +## Goal + +Add GoLand-recognizable formatting APIs without changing the behavior of the +existing public API or the stack frame recorded for callers. + +## Public API + +Add these functions: + +```go +func NewErrorf(format string, args ...any) error +func Propagatef(err error, format string, args ...any) error +func NewErrorWithCodef(code ErrorCode, format string, args ...any) error +func PropagateWithCodef(err error, code ErrorCode, format string, args ...any) error +func NewMessageWithCodef(code ErrorCode, format string, args ...any) error +``` + +Each function has the same semantics as its existing counterpart. Existing +functions remain unchanged and continue to accept formatting arguments for +backward compatibility. + +## Implementation + +The four stack-capturing functions call `create` directly. They must not +delegate through another public function because `create` uses +`runtime.Caller(2)`, and an extra wrapper frame would change the recorded file, +function, and line. + +`Propagatef` and `PropagateWithCodef` return `nil` for a nil cause. +`Propagatef` inherits an existing stacktrace code, while +`PropagateWithCodef` applies the supplied code. `NewMessageWithCodef` creates a +message-only coded error without caller information. + +## Documentation + +Add Go doc comments for all new exported functions. Update README signatures +and interpolated examples to use the `*f` variants, while documenting that the +original APIs remain supported. + +## Tests + +Add black-box coverage for: + +1. String interpolation in all five new functions. +2. Nil behavior for both propagation functions. +3. Code inheritance and explicit code assignment. +4. Accurate caller attribution for stack-capturing functions. + +## Compatibility + +This is additive. No existing symbol, signature, formatting behavior, error +chain behavior, or error-code behavior changes. diff --git a/functions_for_test.go b/functions_for_test.go index aa4a794..45d4a97 100644 --- a/functions_for_test.go +++ b/functions_for_test.go @@ -51,3 +51,19 @@ func doClosure(err error) error { return stacktrace.Propagate(err, "so closed") }() } + +func newErrorfAtCallSite() error { + return stacktrace.NewErrorf("new %d", 7) +} + +func propagatefAtCallSite(err error) error { + return stacktrace.Propagatef(err, "propagate %d", 7) +} + +func newErrorWithCodefAtCallSite() error { + return stacktrace.NewErrorWithCodef(EcodeInvalidVillain, "coded %d", 7) +} + +func propagateWithCodefAtCallSite(err error) error { + return stacktrace.PropagateWithCodef(err, EcodeNotFastEnough, "coded propagate %d", 7) +} diff --git a/stacktrace.go b/stacktrace.go index 1032f8e..397b097 100644 --- a/stacktrace.go +++ b/stacktrace.go @@ -39,8 +39,8 @@ stacktraces, use something like: var CleanPath = cleanpath.RemoveGoPath /* -NewError is a drop-in replacement for fmt.Errorf that includes line number -information. The canonical call looks like this: +NewError creates an error with a formatted message and line number information. +The canonical call looks like this: if !IsOkay(arg) { return stacktrace.NewError("Expected %v to be okay", arg) @@ -51,8 +51,15 @@ func NewError(format string, args ...any) error { } /* -Propagate wraps an error to include line number information. The msg and vals -arguments work like the ones for fmt.Errorf. +NewErrorf is the formatting variant of NewError. +*/ +func NewErrorf(format string, args ...any) error { + return create(nil, NoCode, format, args...) +} + +/* +Propagate wraps an error to include line number information. The format and args +arguments work like the ones for fmt.Sprintf. The message passed to Propagate should describe the action that failed, resulting in the cause. The canonical call looks like this: @@ -83,7 +90,18 @@ nil" checks. */ func Propagate(err error, format string, args ...any) error { if err == nil { - // Allow calling Propagate without checking whether there is error + // Allow calling Propagate without checking whether there is an error + return nil + } + return create(err, NoCode, format, args...) +} + +/* +Propagatef is the formatting variant of Propagate. +*/ +func Propagatef(err error, format string, args ...any) error { + if err == nil { + // Allow calling Propagatef without checking whether there is an error return nil } return create(err, NoCode, format, args...) @@ -121,6 +139,13 @@ func NewErrorWithCode(code ErrorCode, format string, args ...any) error { return create(nil, code, format, args...) } +/* +NewErrorWithCodef is the formatting variant of NewErrorWithCode. +*/ +func NewErrorWithCodef(code ErrorCode, format string, args ...any) error { + return create(nil, code, format, args...) +} + /* PropagateWithCode is similar to Propagate but also attaches an error code. @@ -131,16 +156,27 @@ PropagateWithCode is similar to Propagate but also attaches an error code. */ func PropagateWithCode(err error, code ErrorCode, format string, args ...any) error { if err == nil { - // Allow calling PropagateWithCode without checking whether there is error + // Allow calling PropagateWithCode without checking whether there is an error + return nil + } + return create(err, code, format, args...) +} + +/* +PropagateWithCodef is the formatting variant of PropagateWithCode. +*/ +func PropagateWithCodef(err error, code ErrorCode, format string, args ...any) error { + if err == nil { + // Allow calling PropagateWithCodef without checking whether there is an error return nil } return create(err, code, format, args...) } /* -NewMessageWithCode returns an error that prints just like fmt.Errorf with no -line number, but including a code. The error code mechanism can be useful by -itself even where stack traces with line numbers are not warranted. +NewMessageWithCode returns an error whose message is formatted like fmt.Sprintf +with no line number, but including a code. The error code mechanism can be +useful by itself even where stack traces with line numbers are not warranted. ttl := req.URL.Query().Get("ttl") if ttl == "" { @@ -154,6 +190,16 @@ func NewMessageWithCode(code ErrorCode, format string, args ...any) error { } } +/* +NewMessageWithCodef is the formatting variant of NewMessageWithCode. +*/ +func NewMessageWithCodef(code ErrorCode, format string, args ...any) error { + return &stacktrace{ + message: fmt.Sprintf(format, args...), + code: code, + } +} + /* GetCode extracts the error code from an error. diff --git a/stacktrace_test.go b/stacktrace_test.go index 6c91056..c52e42d 100644 --- a/stacktrace_test.go +++ b/stacktrace_test.go @@ -153,3 +153,89 @@ func TestExitCode(t *testing.T) { }) } } + +func TestFormattingHelpers(t *testing.T) { + root := errors.New("root") + + tests := []struct { + name string + err error + expected string + code stacktrace.ErrorCode + }{ + { + name: "new error", + err: stacktrace.NewErrorf("new %d", 7), + expected: "new 7", + code: stacktrace.NoCode, + }, + { + name: "propagate", + err: stacktrace.Propagatef(root, "propagate %d", 7), + expected: "propagate 7: root", + code: stacktrace.NoCode, + }, + { + name: "new error with code", + err: stacktrace.NewErrorWithCodef(EcodeInvalidVillain, "coded %d", 7), + expected: "coded 7", + code: EcodeInvalidVillain, + }, + { + name: "propagate with code", + err: stacktrace.PropagateWithCodef(root, EcodeNotFastEnough, "coded propagate %d", 7), + expected: "coded propagate 7: root", + code: EcodeNotFastEnough, + }, + { + name: "new message with code", + err: stacktrace.NewMessageWithCodef(EcodeInvalidVillain, "message %d", 7), + expected: "message 7", + code: EcodeInvalidVillain, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + assert.Equal(t, test.expected, fmt.Sprintf("%#s", test.err)) + assert.Equal(t, test.code, stacktrace.GetCode(test.err)) + }) + } +} + +func TestFormattingHelpersPreserveCode(t *testing.T) { + err := stacktrace.NewErrorWithCodef(EcodeInvalidVillain, "inner %d", 7) + err = stacktrace.Propagatef(err, "outer %d", 8) + + assert.Equal(t, EcodeInvalidVillain, stacktrace.GetCode(err)) + assert.Equal(t, "outer 8: inner 7", fmt.Sprintf("%#s", err)) +} + +func TestFormattingPropagationNil(t *testing.T) { + assert.Nil(t, stacktrace.Propagatef(nil, "propagate %d", 7)) + assert.Nil(t, stacktrace.PropagateWithCodef(nil, EcodeInvalidVillain, "propagate %d", 7)) +} + +func TestFormattingHelpersCaptureCaller(t *testing.T) { + useFixturePaths(t) + root := errors.New("root") + + tests := []struct { + name string + err error + function string + }{ + {name: "new error", err: newErrorfAtCallSite(), function: "newErrorfAtCallSite"}, + {name: "propagate", err: propagatefAtCallSite(root), function: "propagatefAtCallSite"}, + {name: "new error with code", err: newErrorWithCodefAtCallSite(), function: "newErrorWithCodefAtCallSite"}, + {name: "propagate with code", err: propagateWithCodefAtCallSite(root), function: "propagateWithCodefAtCallSite"}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + trace := fmt.Sprintf("%+s", test.err) + assert.Contains(t, trace, fixturePath("functions_for_test.go")) + assert.Contains(t, trace, "("+test.function+")") + }) + } +}