package core_test import ( "testing" . "dappco.re/go/core" "github.com/stretchr/testify/assert" ) // --- Error Creation --- func TestError_E_Good(t *testing.T) { err := E("user.Save", "failed to save", nil) assert.Error(t, err) assert.Contains(t, err.Error(), "user.Save") assert.Contains(t, err.Error(), "failed to save") } func TestError_E_WithCause_Good(t *testing.T) { cause := NewError("connection refused") err := E("db.Connect", "database unavailable", cause) assert.ErrorIs(t, err, cause) } func TestError_Wrap_Good(t *testing.T) { cause := NewError("timeout") err := Wrap(cause, "api.Call", "request failed") assert.Error(t, err) assert.ErrorIs(t, err, cause) } func TestError_Wrap_Nil_Good(t *testing.T) { err := Wrap(nil, "api.Call", "request failed") assert.Nil(t, err) } func TestError_WrapCode_Good(t *testing.T) { cause := NewError("invalid email") err := WrapCode(cause, "VALIDATION_ERROR", "user.Validate", "bad input") assert.Error(t, err) assert.Equal(t, "VALIDATION_ERROR", ErrorCode(err)) } func TestError_NewCode_Good(t *testing.T) { err := NewCode("NOT_FOUND", "resource not found") assert.Error(t, err) assert.Equal(t, "NOT_FOUND", ErrorCode(err)) } // --- Error Introspection --- func TestError_Operation_Good(t *testing.T) { err := E("brain.Recall", "search failed", nil) assert.Equal(t, "brain.Recall", Operation(err)) } func TestError_Operation_Bad(t *testing.T) { err := NewError("plain error") assert.Equal(t, "", Operation(err)) } func TestError_ErrorMessage_Good(t *testing.T) { err := E("op", "the message", nil) assert.Equal(t, "the message", ErrorMessage(err)) } func TestError_ErrorMessage_Plain(t *testing.T) { err := NewError("plain") assert.Equal(t, "plain", ErrorMessage(err)) } func TestError_ErrorMessage_Nil(t *testing.T) { assert.Equal(t, "", ErrorMessage(nil)) } func TestError_Root_Good(t *testing.T) { root := NewError("root cause") wrapped := Wrap(root, "layer1", "first wrap") double := Wrap(wrapped, "layer2", "second wrap") assert.Equal(t, root, Root(double)) } func TestError_Root_Nil(t *testing.T) { assert.Nil(t, Root(nil)) } func TestError_StackTrace_Good(t *testing.T) { err := Wrap(E("inner", "cause", nil), "outer", "wrapper") stack := StackTrace(err) assert.Len(t, stack, 2) assert.Equal(t, "outer", stack[0]) assert.Equal(t, "inner", stack[1]) } func TestError_FormatStackTrace_Good(t *testing.T) { err := Wrap(E("a", "x", nil), "b", "y") formatted := FormatStackTrace(err) assert.Equal(t, "b -> a", formatted) } // --- ErrorLog --- func TestError_ErrorLog_Good(t *testing.T) { c := New() cause := NewError("boom") r := c.Log().Error(cause, "test.Operation", "something broke") assert.False(t, r.OK) assert.ErrorIs(t, r.Value.(error), cause) } func TestError_ErrorLog_Nil_Good(t *testing.T) { c := New() r := c.Log().Error(nil, "test.Operation", "no error") assert.True(t, r.OK) } func TestError_ErrorLog_Warn_Good(t *testing.T) { c := New() cause := NewError("warning") r := c.Log().Warn(cause, "test.Operation", "heads up") assert.False(t, r.OK) } func TestError_ErrorLog_Must_Ugly(t *testing.T) { c := New() assert.Panics(t, func() { c.Log().Must(NewError("fatal"), "test.Operation", "must fail") }) } func TestError_ErrorLog_Must_Nil_Good(t *testing.T) { c := New() assert.NotPanics(t, func() { c.Log().Must(nil, "test.Operation", "no error") }) } // --- ErrorPanic --- func TestError_ErrorPanic_Recover_Good(t *testing.T) { c := New() // Should not panic — Recover catches it assert.NotPanics(t, func() { defer c.Error().Recover() panic("test panic") }) } func TestError_ErrorPanic_SafeGo_Good(t *testing.T) { c := New() done := make(chan bool, 1) c.Error().SafeGo(func() { done <- true }) assert.True(t, <-done) } func TestError_ErrorPanic_SafeGo_Panic_Good(t *testing.T) { c := New() done := make(chan bool, 1) c.Error().SafeGo(func() { defer func() { done <- true }() panic("caught by SafeGo") }) // SafeGo recovers — goroutine completes without crashing the process <-done } // --- Standard Library Wrappers --- func TestError_Is_Good(t *testing.T) { target := NewError("target") wrapped := Wrap(target, "op", "msg") assert.True(t, Is(wrapped, target)) } func TestError_As_Good(t *testing.T) { err := E("op", "msg", nil) var e *Err assert.True(t, As(err, &e)) assert.Equal(t, "op", e.Operation) } func TestError_NewError_Good(t *testing.T) { err := NewError("simple error") assert.Equal(t, "simple error", err.Error()) } func TestError_ErrorJoin_Good(t *testing.T) { e1 := NewError("first") e2 := NewError("second") joined := ErrorJoin(e1, e2) assert.ErrorIs(t, joined, e1) assert.ErrorIs(t, joined, e2) } // --- ErrorPanic Crash Reports --- func TestError_ErrorPanic_Reports_Good(t *testing.T) { dir := t.TempDir() path := Path(dir, "crashes.json") // Create ErrorPanic with file output c := New() // Access internals via a crash that writes to file // Since ErrorPanic fields are unexported, we test via Recover _ = c _ = path // Crash reporting needs ErrorPanic configured with filePath — tested indirectly } // --- ErrorPanic Crash File --- func TestError_ErrorPanic_CrashFile_Good(t *testing.T) { dir := t.TempDir() path := Path(dir, "crashes.json") // Create Core, trigger a panic through SafeGo, check crash file // ErrorPanic.filePath is unexported — but we can test via the package-level // error handling that writes crash reports // For now, test that Reports handles missing file gracefully c := New() r := c.Error().Reports(5) assert.False(t, r.OK) assert.Nil(t, r.Value) _ = path } // --- Error formatting branches --- func TestError_Err_Error_WithCode_Good(t *testing.T) { err := WrapCode(NewError("bad"), "INVALID", "validate", "input failed") assert.Contains(t, err.Error(), "[INVALID]") assert.Contains(t, err.Error(), "validate") assert.Contains(t, err.Error(), "bad") } func TestError_Err_Error_CodeNoCause_Good(t *testing.T) { err := NewCode("NOT_FOUND", "resource missing") assert.Contains(t, err.Error(), "[NOT_FOUND]") assert.Contains(t, err.Error(), "resource missing") } func TestError_Err_Error_NoOp_Good(t *testing.T) { err := &Err{Message: "bare error"} assert.Equal(t, "bare error", err.Error()) } func TestError_WrapCode_NilErr_EmptyCode_Good(t *testing.T) { err := WrapCode(nil, "", "op", "msg") assert.Nil(t, err) } func TestError_Wrap_PreservesCode_Good(t *testing.T) { inner := WrapCode(NewError("root"), "AUTH_FAIL", "auth", "denied") outer := Wrap(inner, "handler", "request failed") assert.Equal(t, "AUTH_FAIL", ErrorCode(outer)) } func TestError_ErrorLog_Warn_Nil_Good(t *testing.T) { c := New() r := c.LogWarn(nil, "op", "msg") assert.True(t, r.OK) } func TestError_ErrorLog_Error_Nil_Good(t *testing.T) { c := New() r := c.LogError(nil, "op", "msg") assert.True(t, r.OK) }