Conversation
|
Testcase run |
|
Testing the failure scenario code flow by locally updating the main.go |
|
Hi @lazysegtree! First of all, I appreciate your contribution and I agree with your changes. I got curious about the problem to deterministically test this behavior. Locally, I came up with the following changes which, unless I don't fully understand the problem you're describing, allow me to deterministically test this. First, I added a private, global variable which allows us to change the amount of frames to be skipped. This will be the value that's set to
// skipFrames is the number of stack frames to skip when getting the source context. By default, we skip 2 frames:
// 1. The assert() function itself
// 2. The Assert()/Debug() function that called assert()
//
// The purpose of this variable is to enable deterministic testing of the source context as described here:
// - https://github.com/nikoksr/assert-go/issues/2
//
//nolint:gochecknoglobals // required for testing, otherwise read-only
var skipFrames = 2I then altered the
// assert panics if the condition is false. Configurable via SetConfig.
func assert(condition bool, msg string, values ...any) {
if condition {
return // Assertion met
}
// Skip stack frames
_, file, line, ok := runtime.Caller(skipFrames)
// Could not get Caller info
if !ok {
panic(AssertionError{
Message: msg,
})
}
// ...
}And finally added a test case to // ...
func TestAssertCallerFailure(t *testing.T) {
// Capture the original skip value
oldSkipFrames := skipFrames
// Set skip to a value that will definitely exceed call stack depth
skipFrames = 1000
// Restore the original value after test
defer func() { skipFrames = oldSkipFrames }()
// 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 == "" {
t.Error("Expected non-empty message")
}
}()
Assert(false, "This should fail to get caller info")
}What are your thoughts on this? If you agree with my suggestions, would you like to apply them? Otherwise I can push my changes. Cheers. |
|
Thanks for your suggestion. I feel that having a global variable and then modifying it in test cases, and defering the rollback of modification is a bit too hacky. Check the latest commit if it looks good. |
|
I agree that there is a minor increased overhead due to passing one more parameter. But this is a trade-off between micro-optimization vs cleaner and more maintainable codebase. |
|
test run |
I appreciate that feedback. I'm fine merging your implementation after the review.
I don't agree with this. I'm rather certain there'd be virtually no overhead due to compiler optimizations. It will most probably be inlined by the compiler. I have not verified this though as I'm fine with it either way. The actual overhead of |
|
@nikoksr Applied the changes about moving comments. |
…iate place Co-authored-by: Niko Köser <nikoksr@proton.me>
|
@nikoksr Sorry. I didn't see that. I have fixed it now. |
|
@lazysegtree thanks again for your thorough contribution ✌🏻 |
|
Closed #2 |
Issue - #2