go/pkg/errors/errors_test.go
Snider 629141e279 feat(pkg): add standalone log and errors packages
Extract logging to pkg/log for use outside CLI:
- Logger with Debug/Info/Warn/Error levels
- Key-value pairs for structured logging
- Customisable styling and output
- Optional Core framework integration via Service

Enhance pkg/errors with:
- Wrap() and WrapCode() helpers
- Code() for error codes
- Op(), ErrCode(), Message(), Root() extractors
- Standard library wrappers (Is, As, New, Join)

Update pkg/cli/log.go to use pkg/log with CLI styling.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:02:40 +00:00

182 lines
3.8 KiB
Go

package errors
import (
"io"
"testing"
)
func TestE(t *testing.T) {
err := E("user.Create", "validation failed", nil)
if err.Error() != "user.Create: validation failed" {
t.Errorf("unexpected error message: %s", err.Error())
}
}
func TestE_WithUnderlying(t *testing.T) {
underlying := New("database connection failed")
err := E("user.Create", "failed to save", underlying)
if err.Error() != "user.Create: failed to save: database connection failed" {
t.Errorf("unexpected error message: %s", err.Error())
}
}
func TestWrap(t *testing.T) {
// Wrap nil returns nil
if Wrap(nil, "op", "msg") != nil {
t.Error("expected Wrap(nil) to return nil")
}
// Wrap error
underlying := New("original")
err := Wrap(underlying, "user.Get", "failed")
if !Is(err, underlying) {
t.Error("expected wrapped error to match underlying")
}
}
func TestWrapCode(t *testing.T) {
underlying := New("not found")
err := WrapCode(underlying, "ERR_NOT_FOUND", "user.Get", "user not found")
var e *Error
if !As(err, &e) {
t.Fatal("expected error to be *Error")
}
if e.Code != "ERR_NOT_FOUND" {
t.Errorf("expected code ERR_NOT_FOUND, got %s", e.Code)
}
}
func TestCode(t *testing.T) {
err := Code("ERR_VALIDATION", "invalid email")
var e *Error
if !As(err, &e) {
t.Fatal("expected error to be *Error")
}
if e.Code != "ERR_VALIDATION" {
t.Errorf("expected code ERR_VALIDATION, got %s", e.Code)
}
if e.Msg != "invalid email" {
t.Errorf("expected msg 'invalid email', got %s", e.Msg)
}
}
func TestIs(t *testing.T) {
err := Wrap(io.EOF, "read", "failed")
if !Is(err, io.EOF) {
t.Error("expected Is to find io.EOF in chain")
}
if Is(err, io.ErrClosedPipe) {
t.Error("expected Is to not find io.ErrClosedPipe")
}
}
func TestAs(t *testing.T) {
err := E("test.Op", "test message", nil)
var e *Error
if !As(err, &e) {
t.Fatal("expected As to find *Error")
}
if e.Op != "test.Op" {
t.Errorf("expected Op 'test.Op', got %s", e.Op)
}
}
func TestOp(t *testing.T) {
err := E("user.Create", "failed", nil)
if Op(err) != "user.Create" {
t.Errorf("expected Op 'user.Create', got %s", Op(err))
}
// Non-Error returns empty string
if Op(New("plain error")) != "" {
t.Error("expected empty Op for non-Error")
}
}
func TestErrCode(t *testing.T) {
err := Code("ERR_TEST", "test")
if ErrCode(err) != "ERR_TEST" {
t.Errorf("expected code ERR_TEST, got %s", ErrCode(err))
}
// Non-Error returns empty string
if ErrCode(New("plain error")) != "" {
t.Error("expected empty code for non-Error")
}
}
func TestMessage(t *testing.T) {
err := E("op", "the message", nil)
if Message(err) != "the message" {
t.Errorf("expected 'the message', got %s", Message(err))
}
// Plain error returns full error string
plain := New("plain error")
if Message(plain) != "plain error" {
t.Errorf("expected 'plain error', got %s", Message(plain))
}
// Nil returns empty string
if Message(nil) != "" {
t.Error("expected empty string for nil")
}
}
func TestRoot(t *testing.T) {
root := New("root cause")
mid := Wrap(root, "mid", "middle")
top := Wrap(mid, "top", "top level")
if Root(top) != root {
t.Error("expected Root to return deepest error")
}
// Single error returns itself
single := New("single")
if Root(single) != single {
t.Error("expected Root of single error to return itself")
}
}
func TestError_Unwrap(t *testing.T) {
underlying := New("underlying")
err := E("op", "msg", underlying)
var e *Error
if !As(err, &e) {
t.Fatal("expected *Error")
}
if e.Unwrap() != underlying {
t.Error("expected Unwrap to return underlying error")
}
}
func TestJoin(t *testing.T) {
err1 := New("error 1")
err2 := New("error 2")
joined := Join(err1, err2)
if !Is(joined, err1) {
t.Error("expected joined error to contain err1")
}
if !Is(joined, err2) {
t.Error("expected joined error to contain err2")
}
}