216 lines
7.8 KiB
Go
216 lines
7.8 KiB
Go
package errs
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"backend/pkg/library/errors/code"
|
|
"google.golang.org/grpc/codes"
|
|
)
|
|
|
|
func TestNew(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
scope uint32
|
|
category uint32
|
|
detail uint32
|
|
displayMsg string
|
|
wantScope uint32
|
|
wantCategory uint32
|
|
wantDetail uint32
|
|
wantMsg string
|
|
}{
|
|
{"basic", 10, 201, 123, "test", 10, 201, 123, "test"},
|
|
{"clamp category", 10, 1000, 0, "clamp cat", 10, 999, 0, "clamp cat"},
|
|
{"clamp detail", 10, 101, 1000, "clamp det", 10, 101, 999, "clamp det"},
|
|
{"zero values", 0, 0, 0, "", 0, 0, 0, ""},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
e := New(tt.scope, tt.category, tt.detail, tt.displayMsg)
|
|
if e.Scope() != tt.wantScope || e.Category() != tt.wantCategory || e.Detail() != tt.wantDetail || e.msg != tt.wantMsg {
|
|
t.Errorf("New() = %+v, want scope=%d cat=%d det=%d msg=%q", e, tt.wantScope, tt.wantCategory, tt.wantDetail, tt.wantMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestErrorMethods(t *testing.T) {
|
|
e := New(10, 201, 123, "test error")
|
|
tests := []struct {
|
|
name string
|
|
err *Error
|
|
wantErr string
|
|
wantScope uint32
|
|
wantCat uint32
|
|
wantDet uint32
|
|
}{
|
|
{"non-nil", e, "test error", 10, 201, 123},
|
|
{"nil", nil, "", uint32(code.Unset), uint32(code.DefaultCategory), uint32(code.DefaultDetail)}, // Adjust if Default* not defined; use 0
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := tt.err.Error(); got != tt.wantErr {
|
|
t.Errorf("Error() = %q, want %q", got, tt.wantErr)
|
|
}
|
|
if got := tt.err.Scope(); got != tt.wantScope {
|
|
t.Errorf("Scope() = %d, want %d", got, tt.wantScope)
|
|
}
|
|
if got := tt.err.Category(); got != tt.wantCat {
|
|
t.Errorf("Category() = %d, want %d", got, tt.wantCat)
|
|
}
|
|
if got := tt.err.Detail(); got != tt.wantDet {
|
|
t.Errorf("Detail() = %d, want %d", got, tt.wantDet)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCodes(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
err *Error
|
|
wantSubCode uint32
|
|
wantCode uint32
|
|
wantDisplay string
|
|
}{
|
|
{"basic", New(10, 201, 123, ""), 201123, 10201123, "10201123"},
|
|
{"nil", nil, code.OK, code.NonCode, "00000000"},
|
|
{"max clamp", New(99, 999, 999, ""), 999999, 99999999, "99999999"},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := tt.err.SubCode(); got != tt.wantSubCode {
|
|
t.Errorf("SubCode() = %d, want %d", got, tt.wantSubCode)
|
|
}
|
|
if got := tt.err.Code(); got != tt.wantCode {
|
|
t.Errorf("Code() = %d, want %d", got, tt.wantCode)
|
|
}
|
|
if got := tt.err.DisplayCode(); got != tt.wantDisplay {
|
|
t.Errorf("DisplayCode() = %q, want %q", got, tt.wantDisplay)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIs(t *testing.T) {
|
|
e1 := New(10, 201, 123, "")
|
|
e2 := New(10, 201, 123, "") // same subcode
|
|
e3 := New(10, 202, 123, "") // different category
|
|
stdErr := errors.New("std")
|
|
tests := []struct {
|
|
name string
|
|
err error
|
|
target error
|
|
want bool
|
|
}{
|
|
{"match", e1, e2, true},
|
|
{"mismatch", e1, e3, false},
|
|
{"not Error type", e1, stdErr, false},
|
|
{"nil err", nil, e2, false},
|
|
{"nil target", e1, nil, false},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := errors.Is(tt.err, tt.target); got != tt.want {
|
|
t.Errorf("Is() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestWrapUnwrap(t *testing.T) {
|
|
internal := errors.New("internal")
|
|
tests := []struct {
|
|
name string
|
|
err *Error
|
|
wrapErr error
|
|
wantUnwrap error
|
|
}{
|
|
{"wrap non-nil", New(10, 201, 0, ""), internal, internal},
|
|
{"wrap nil", nil, internal, nil}, // Wrap on nil does nothing
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := tt.err.Wrap(tt.wrapErr)
|
|
if unwrapped := got.Unwrap(); unwrapped != tt.wantUnwrap {
|
|
t.Errorf("Unwrap() = %v, want %v", unwrapped, tt.wantUnwrap)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGRPCStatus(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
err *Error
|
|
wantCode codes.Code
|
|
wantMsg string
|
|
}{
|
|
{"non-nil", New(10, 201, 123, "grpc err"), codes.Code(10201123), "grpc err"},
|
|
{"nil", nil, codes.OK, ""},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
s := tt.err.GRPCStatus()
|
|
if s.Code() != tt.wantCode || s.Message() != tt.wantMsg {
|
|
t.Errorf("GRPCStatus() = code=%v msg=%q, want code=%v msg=%q", s.Code(), s.Message(), tt.wantCode, tt.wantMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestHTTPStatus(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
err *Error
|
|
want int
|
|
}{
|
|
{"nil", nil, http.StatusOK},
|
|
{"OK subcode", New(10, 0, 0, ""), http.StatusOK},
|
|
{"InputInvalidFormat", New(10, uint32(code.InputInvalidFormat), 0, ""), http.StatusBadRequest},
|
|
{"InputNotValidImplementation", New(10, uint32(code.InputNotValidImplementation), 0, ""), http.StatusUnprocessableEntity},
|
|
{"DBError", New(10, uint32(code.DBError), 0, ""), http.StatusInternalServerError},
|
|
{"ResNotFound", New(10, uint32(code.ResNotFound), 0, ""), http.StatusNotFound},
|
|
// Add all other categories to cover switch branches
|
|
{"InputInvalidRange", New(10, uint32(code.InputInvalidRange), 0, ""), http.StatusUnprocessableEntity},
|
|
{"DBDataConvert", New(10, uint32(code.DBDataConvert), 0, ""), http.StatusUnprocessableEntity},
|
|
{"DBDuplicate", New(10, uint32(code.DBDuplicate), 0, ""), http.StatusConflict},
|
|
{"ResInvalidFormat", New(10, uint32(code.ResInvalidFormat), 0, ""), http.StatusUnprocessableEntity},
|
|
{"ResAlreadyExist", New(10, uint32(code.ResAlreadyExist), 0, ""), http.StatusConflict},
|
|
{"ResInsufficient", New(10, uint32(code.ResInsufficient), 0, ""), http.StatusBadRequest},
|
|
{"ResInsufficientPerm", New(10, uint32(code.ResInsufficientPerm), 0, ""), http.StatusForbidden},
|
|
{"ResInvalidMeasureID", New(10, uint32(code.ResInvalidMeasureID), 0, ""), http.StatusBadRequest},
|
|
{"ResExpired", New(10, uint32(code.ResExpired), 0, ""), http.StatusGone},
|
|
{"ResMigrated", New(10, uint32(code.ResMigrated), 0, ""), http.StatusGone},
|
|
{"ResInvalidState", New(10, uint32(code.ResInvalidState), 0, ""), http.StatusConflict},
|
|
{"ResInsufficientQuota", New(10, uint32(code.ResInsufficientQuota), 0, ""), http.StatusTooManyRequests},
|
|
{"ResMultiOwner", New(10, uint32(code.ResMultiOwner), 0, ""), http.StatusConflict},
|
|
{"AuthUnauthorized", New(10, uint32(code.AuthUnauthorized), 0, ""), http.StatusUnauthorized},
|
|
{"AuthExpired", New(10, uint32(code.AuthExpired), 0, ""), http.StatusUnauthorized},
|
|
{"AuthInvalidPosixTime", New(10, uint32(code.AuthInvalidPosixTime), 0, ""), http.StatusUnauthorized},
|
|
{"AuthSigPayloadMismatch", New(10, uint32(code.AuthSigPayloadMismatch), 0, ""), http.StatusUnauthorized},
|
|
{"AuthForbidden", New(10, uint32(code.AuthForbidden), 0, ""), http.StatusForbidden},
|
|
{"SysTooManyRequest", New(10, uint32(code.SysTooManyRequest), 0, ""), http.StatusTooManyRequests},
|
|
{"SysInternal", New(10, uint32(code.SysInternal), 0, ""), http.StatusInternalServerError},
|
|
{"SysMaintain", New(10, uint32(code.SysMaintain), 0, ""), http.StatusServiceUnavailable},
|
|
{"SysTimeout", New(10, uint32(code.SysTimeout), 0, ""), http.StatusGatewayTimeout},
|
|
{"PSuPublish", New(10, uint32(code.PSuPublish), 0, ""), http.StatusBadGateway},
|
|
{"PSuConsume", New(10, uint32(code.PSuConsume), 0, ""), http.StatusBadGateway},
|
|
{"PSuTooLarge", New(10, uint32(code.PSuTooLarge), 0, ""), http.StatusRequestEntityTooLarge},
|
|
{"SvcMaintenance", New(10, uint32(code.SvcMaintenance), 0, ""), http.StatusServiceUnavailable},
|
|
{"SvcInternal", New(10, uint32(code.SvcInternal), 0, ""), http.StatusInternalServerError},
|
|
{"SvcThirdParty", New(10, uint32(code.SvcThirdParty), 0, ""), http.StatusBadGateway},
|
|
{"SvcHTTP400", New(10, uint32(code.SvcHTTP400), 0, ""), http.StatusBadRequest},
|
|
{"fallback unknown", New(10, 999, 0, ""), http.StatusInternalServerError},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := tt.err.HTTPStatus(); got != tt.want {
|
|
t.Errorf("HTTPStatus() = %d, want %d", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|