package errs import ( "errors" "fmt" "testing" "backend/pkg/library/errors/code" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func TestNewBuiltinGRPCErr(t *testing.T) { tests := []struct { name string scope uint32 detail uint32 msg string wantCat uint32 wantScope uint32 wantDet uint32 wantMsg string }{ {"basic", 10, 3, "test", uint32(code.CatGRPC), 10, 3, "test"}, {"zero", 0, 0, "", uint32(code.CatGRPC), 0, 0, ""}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { e := newBuiltinGRPCErr(tt.scope, tt.detail, tt.msg) if e.Category() != tt.wantCat || e.Scope() != tt.wantScope || e.Detail() != tt.wantDet || e.Error() != tt.wantMsg { t.Errorf("newBuiltinGRPCErr = cat=%d scope=%d det=%d msg=%q, want %d %d %d %q", e.Category(), e.Scope(), e.Detail(), e.Error(), tt.wantCat, tt.wantScope, tt.wantDet, tt.wantMsg) } }) } } func TestFromError(t *testing.T) { base := New(10, uint32(code.DBError), 0, "base") // but actually use fmt.Errorf("%w", base) for proper wrapping tests := []struct { name string in error want *Error }{ {"nil", nil, nil}, {"not Error", errors.New("std"), nil}, {"direct Error", base, base}, {"wrapped Error", fmt.Errorf("wrap: %w", base), base}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := FromError(tt.in) if (got == nil) != (tt.want == nil) { t.Errorf("FromError = %v, want nil=%v", got, tt.want == nil) } if got != nil && (got.Category() != tt.want.Category() || got.Detail() != tt.want.Detail()) { t.Errorf("FromError = cat=%d det=%d, want %d %d", got.Category(), got.Detail(), tt.want.Category(), tt.want.Detail()) } }) } } func TestFromCode(t *testing.T) { tests := []struct { name string code uint32 wantScope uint32 wantCat uint32 wantDet uint32 }{ {"basic", 10201123, 10, 201, 123}, {"zero", 0, 0, 0, 0}, {"max", 99999999, 99, 999, 999}, {"overflow code", 100000000, 100, 0, 0}, // Parses as scope=100, but uint32 limits } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { e := FromCode(tt.code) if e.Scope() != tt.wantScope || e.Category() != tt.wantCat || e.Detail() != tt.wantDet { t.Errorf("FromCode = scope=%d cat=%d det=%d, want %d %d %d", e.Scope(), e.Category(), e.Detail(), tt.wantScope, tt.wantCat, tt.wantDet) } }) } } func TestFromGRPCError(t *testing.T) { Scope = code.Gateway tests := []struct { name string in error wantScope uint32 wantCat uint32 wantDet uint32 wantMsg string }{ {"nil", nil, 0, 0, 0, ""}, {"builtin OK", status.New(codes.OK, "").Err(), 0, 0, 0, ""}, {"builtin InvalidArgument", status.New(codes.InvalidArgument, "bad").Err(), uint32(code.Gateway), uint32(code.CatGRPC), uint32(codes.InvalidArgument), "bad"}, {"custom code", status.New(codes.Code(10201123), "custom").Err(), 10, 201, 123, "custom"}, {"unset scope with builtin", status.New(codes.NotFound, "not found").Err(), uint32(code.Gateway), uint32(code.CatGRPC), uint32(codes.NotFound), "not found"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { e := FromGRPCError(tt.in) if e == nil && (tt.wantScope != 0 || tt.wantCat != 0 || tt.wantDet != 0) { t.Errorf("got nil, want non-nil") } if e != nil && (e.Scope() != tt.wantScope || e.Category() != tt.wantCat || e.Detail() != tt.wantDet || e.Error() != tt.wantMsg) { t.Errorf("FromGRPCError = scope=%d cat=%d det=%d msg=%q, want %d %d %d %q", e.Scope(), e.Category(), e.Detail(), e.Error(), tt.wantScope, tt.wantCat, tt.wantDet, tt.wantMsg) } }) } }