Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,28 @@ func SetConfig(config Config) {
//
// WARN: This assertion is live!
func Assert(condition bool, msg string, values ...any) {
assert(condition, msg, values...)
// We tell assert() to skip 2 frames here:
// 1. The assert() function itself
// 2. This Assert() function that calls assert()
assert(condition, msg, 2, values...) //nolint:mnd // Explained in comment
}

// Assert panics if the condition is false. Configurable via SetConfig.
func assert(condition bool, msg string, values ...any) {
// skipFrames is the number of stack frames to skip when getting the source context.
func assert(condition bool, msg string, skipFrames int, values ...any) {
if condition {
return // Assertion met
}

// Skip 2 frames:
// 1. this assert() function
// 2. the Assert() function that called us
_, file, line, _ := runtime.Caller(2) //nolint:mnd // Explained in comment

_, file, line, ok := runtime.Caller(skipFrames)

// Could not get Caller info
if !ok {
panic(AssertionError{
Message: msg,
})
}
// If values were provided for dumping
numValues := len(values)
if numValues%2 != 0 {
Expand Down
5 changes: 4 additions & 1 deletion assert_debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ package assert
//
// WARN: Under the current build configuration, this assertion is enabled.
func Debug(condition bool, msg string, values ...any) {
assert(condition, msg, values...)
// We tell assert() to skip 2 frames here:
// 1. The assert() function itself
// 2. This Debug() function that calls assert()
assert(condition, msg, 2, values...) //nolint:mnd // Explained in comment
}
35 changes: 35 additions & 0 deletions assert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,38 @@ func TestAssert_EmptyValues(t *testing.T) {
"empty_map", map[string]int{},
)
}

func TestAssertCallerFailure(t *testing.T) {
assertMessage := "This should fail to get caller info"
// Capture and verify the panic
defer func() {
r := recover()
if r == nil {
t.Fatal("Expected panic, but none occurred")
}

ae, ok := r.(AssertionError)
if !ok {
t.Fatalf("Expected AssertionError, got %T", r)
}

// Verify we got the simplified error without file/line info
if ae.File != "" {
t.Errorf("Expected empty file, got %q", ae.File)
}
if ae.Line != 0 {
t.Errorf("Expected line to be 0, got %d", ae.Line)
}
if ae.SourceContext != "" {
t.Errorf("Expected empty source context, got %q", ae.SourceContext)
}
// Message should still be included
if ae.Message != assertMessage {
t.Errorf("Expected %q as error message, got %q", assertMessage, ae.Message)
}
}()

// Using the assert function (only accessible internally) instead of Assert
// to pass a specific skipFrames value
assert(false, assertMessage, 1000)
}
6 changes: 5 additions & 1 deletion types.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ type AssertionError struct {
func (e AssertionError) Error() string {
var sb strings.Builder

sb.WriteString(fmt.Sprintf("Assertion failed at %s:%d\n", e.File, e.Line))
if e.File != "" {
Comment thread
nikoksr marked this conversation as resolved.
sb.WriteString(fmt.Sprintf("Assertion failed at %s:%d\n", e.File, e.Line))
} else {
sb.WriteString("Assertion failed (Runtime caller info is not available)\n")
}
sb.WriteString(fmt.Sprintf("Message: %s\n", e.Message))

if e.SourceContext != "" {
Expand Down