library-go/pkg/errors/errors_test.go

298 lines
7.8 KiB
Go
Raw Normal View History

2024-08-06 09:38:33 +00:00
package error
import (
"code.30cm.net/wanderland/library-go/pkg/errors/code"
"errors"
"fmt"
"net/http"
"testing"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func TestCode_GivenNilReceiver_CodeReturnOK_CodeStrReturns00000(t *testing.T) {
// setup
var e *Err = nil
// act & assert
assert.Equal(t, code.OK, e.Code())
assert.Equal(t, "00000", e.CodeStr())
assert.Equal(t, "", e.Error())
}
func TestCode_GivenScope99DetailCode6687_ShouldReturn996687(t *testing.T) {
// setup
e := Err{scope: 99, code: 6687}
// act & assert
assert.Equal(t, uint32(6687), e.Code())
assert.Equal(t, "996687", e.CodeStr())
}
func TestCode_GivenScope0DetailCode87_ShouldReturn87(t *testing.T) {
// setup
e := Err{scope: 0, code: 87}
// act & assert
assert.Equal(t, uint32(87), e.Code())
assert.Equal(t, "00087", e.CodeStr())
}
func TestFromCode_Given870005_ShouldHasScope87_Cat0_Detail5(t *testing.T) {
// setup
e := FromCode(870005)
// assert
assert.Equal(t, uint32(87), e.Scope())
assert.Equal(t, uint32(0), e.Category())
assert.Equal(t, uint32(5), e.Code())
assert.Equal(t, "", e.Error())
}
func TestFromCode_Given0_ShouldHasScope0_Cat0_Detail0(t *testing.T) {
// setup
e := FromCode(0)
// assert
assert.Equal(t, uint32(0), e.Scope())
assert.Equal(t, uint32(0), e.Category())
assert.Equal(t, uint32(0), e.Code())
assert.Equal(t, "", e.Error())
}
func TestFromCode_Given9105_ShouldHasScope0_Cat9100_Detail9105(t *testing.T) {
// setup
e := FromCode(9105)
// assert
assert.Equal(t, uint32(0), e.Scope())
assert.Equal(t, uint32(9100), e.Category())
assert.Equal(t, uint32(9105), e.Code())
assert.Equal(t, "", e.Error())
}
func TestErr_ShouldImplementErrorFunction(t *testing.T) {
// setup a func return error
f := func() error { return InvalidFormat("fake field") }
// act
err := f()
// assert
assert.NotNil(t, err)
assert.Contains(t, fmt.Sprint(err), "fake field") // can be printed
}
func TestGeneralError_GivenNilErr_ShouldReturnEmptyString(t *testing.T) {
// setup
var e *Err = nil
// act & assert
assert.Equal(t, "", e.GeneralError())
}
func TestGeneralError_GivenNotExistCat_ShouldReturnEmptyString(t *testing.T) {
// setup
e := Err{category: 123456}
// act & assert
assert.Equal(t, "", e.GeneralError())
}
func TestGeneralError_GivenCatDB_ShouldReturnDBError(t *testing.T) {
// setup
e := Err{category: code.CatDB}
catErrStr := code.CatToStr[code.CatDB]
// act & assert
assert.Equal(t, catErrStr, e.GeneralError())
}
func TestError_GivenEmptyMsg_ShouldReturnCatGeneralErrorMessage(t *testing.T) {
// setup
e := Err{category: code.CatDB, msg: ""}
// act
errMsg := e.Error()
// assert
assert.Equal(t, code.CatToStr[code.CatDB], errMsg)
}
func TestError_GivenMsg_ShouldReturnGiveMsg(t *testing.T) {
// setup
e := Err{msg: "FAKE"}
// act
errMsg := e.Error()
// assert
assert.Equal(t, "FAKE", errMsg)
}
func TestIs_GivenNilErr_ShouldReturnFalse(t *testing.T) {
var nilErrs *Err
// act
result := errors.Is(nilErrs, DBError())
result2 := errors.Is(DBError(), nilErrs)
// assert
assert.False(t, result)
assert.False(t, result2)
}
func TestIs_GivenNil_ShouldReturnFalse(t *testing.T) {
// act
result := errors.Is(nil, DBError())
result2 := errors.Is(DBError(), nil)
// assert
assert.False(t, result)
assert.False(t, result2)
}
func TestIs_GivenNilReceiver_ShouldReturnCorrectResult(t *testing.T) {
var nilErr *Err = nil
// test 1: nilErr != DBError
var dbErr error = DBError("fake db error")
assert.False(t, nilErr.Is(dbErr))
// test 2: nilErr != nil error
var nilError error
assert.False(t, nilErr.Is(nilError))
// test 3: nilErr == another nilErr
var nilErr2 *Err = nil
assert.True(t, nilErr.Is(nilErr2))
}
func TestIs_GivenDBError_ShouldReturnTrue(t *testing.T) {
// setup
dbErr := DBError("fake db error")
// act
result := errors.Is(dbErr, DBError("not care"))
result2 := errors.Is(DBError(), dbErr)
// assert
assert.True(t, result)
assert.True(t, result2)
}
func TestIs_GivenDBErrorAssignToErrorType_ShouldReturnTrue(t *testing.T) {
// setup
var dbErr error = DBError("fake db error")
// act
result := errors.Is(dbErr, DBError("not care"))
result2 := errors.Is(DBError(), dbErr)
// assert
assert.True(t, result)
assert.True(t, result2)
}
func TestWrap_GivenNilErr_ShouldNoPanic(t *testing.T) {
// act & assert
assert.NotPanics(t, func() {
var e *Err = nil
_ = e.Wrap(fmt.Errorf("test"))
})
}
func TestWrap_GivenErrorToWrap_ShouldReturnErrorWithWrappedError(t *testing.T) {
// act & assert
wrappedErr := fmt.Errorf("test")
wrappingErr := SystemInternalError("WrappingError").Wrap(wrappedErr)
unWrappedErr := wrappingErr.Unwrap()
assert.Equal(t, wrappedErr, unWrappedErr)
}
func TestUnwrap_GivenNilErr_ShouldReturnNil(t *testing.T) {
var e *Err = nil
internalErr := e.Unwrap()
assert.Nil(t, internalErr)
}
func TestErrorsIs_GivenNilErr_ShouldReturnFalse(t *testing.T) {
var e *Err = nil
assert.False(t, errors.Is(e, fmt.Errorf("test")))
}
func TestErrorsAs_GivenNilErr_ShouldReturnFalse(t *testing.T) {
var internalErr *testErr
var e *Err = nil
assert.False(t, errors.As(e, &internalErr))
}
func TestGRPCStatus(t *testing.T) {
// setup table driven tests
tests := []struct {
name string
given *Err
expect *status.Status
expectConvert error
}{
{
"nil errs.Err",
nil,
status.New(codes.OK, ""),
nil,
},
{
"InvalidFormat Err",
InvalidFormat("fake"),
status.New(codes.Code(101), "invalid format: fake"),
status.New(codes.Code(101), "invalid format: fake").Err(),
},
}
// act & assert
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
s := test.given.GRPCStatus()
assert.Equal(t, test.expect.Code(), s.Code())
assert.Equal(t, test.expect.Message(), s.Message())
assert.Equal(t, test.expectConvert, status.Convert(test.given).Err())
})
}
}
func TestErr_HTTPStatus(t *testing.T) {
tests := []struct {
name string
err *Err
want int
}{
{name: "nil error", err: nil, want: http.StatusOK},
{name: "invalid measurement id", err: &Err{category: code.CatResource, code: code.InvalidMeasurementID}, want: http.StatusInternalServerError},
{name: "resource already exists", err: &Err{category: code.CatResource, code: code.ResourceAlreadyExist}, want: http.StatusConflict},
{name: "invalid resource state", err: &Err{category: code.CatResource, code: code.InvalidResourceState}, want: http.StatusConflict},
{name: "invalid posix time", err: &Err{category: code.CatAuth, code: code.InvalidPosixTime}, want: http.StatusForbidden},
{name: "unauthorized", err: &Err{category: code.CatAuth, code: code.Unauthorized}, want: http.StatusUnauthorized},
{name: "db error", err: &Err{category: code.CatDB, code: code.DBError}, want: http.StatusInternalServerError},
{name: "insufficient permission", err: &Err{category: code.CatResource, code: code.InsufficientPermission}, want: http.StatusUnauthorized},
{name: "resource insufficient", err: &Err{category: code.CatResource, code: code.ResourceInsufficient}, want: http.StatusBadRequest},
{name: "invalid format", err: &Err{category: code.CatInput, code: code.InvalidFormat}, want: http.StatusBadRequest},
{name: "resource not found", err: &Err{code: code.ResourceNotFound}, want: http.StatusNotFound},
{name: "ok", err: &Err{code: code.OK}, want: http.StatusOK},
{name: "not valid implementation", err: &Err{category: code.CatInput, code: code.NotValidImplementation}, want: http.StatusNotImplemented},
{name: "forbidden", err: &Err{category: code.CatAuth, code: code.Forbidden}, want: http.StatusForbidden},
{name: "insufficient quota", err: &Err{category: code.CatResource, code: code.InsufficientQuota}, want: http.StatusPaymentRequired},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// act
got := tt.err.HTTPStatus()
// assert
assert.Equal(t, tt.want, got)
})
}
}