2024-08-20 15:32:06 +00:00
|
|
|
package errors
|
2024-08-19 17:15:23 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"testing"
|
|
|
|
|
2024-08-20 15:32:06 +00:00
|
|
|
code2 "code.30cm.net/digimon/library-go/errors/code"
|
|
|
|
|
2024-08-19 17:15:23 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/status"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestCode_GivenNilReceiver_CodeReturnOK_CodeStrReturns00000(t *testing.T) {
|
|
|
|
// setup
|
2024-08-20 15:32:06 +00:00
|
|
|
var e *LibError = nil
|
2024-08-19 17:15:23 +00:00
|
|
|
|
|
|
|
// act & assert
|
|
|
|
assert.Equal(t, code2.OK, e.Code())
|
|
|
|
assert.Equal(t, "00000", e.CodeStr())
|
|
|
|
assert.Equal(t, "", e.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCode_GivenScope99DetailCode6687_ShouldReturn996687(t *testing.T) {
|
|
|
|
// setup
|
2024-08-20 15:32:06 +00:00
|
|
|
e := LibError{scope: 99, code: 6687}
|
2024-08-19 17:15:23 +00:00
|
|
|
|
|
|
|
// act & assert
|
|
|
|
assert.Equal(t, uint32(6687), e.Code())
|
|
|
|
assert.Equal(t, "996687", e.CodeStr())
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCode_GivenScope0DetailCode87_ShouldReturn87(t *testing.T) {
|
|
|
|
// setup
|
2024-08-20 15:32:06 +00:00
|
|
|
e := LibError{scope: 0, code: 87}
|
2024-08-19 17:15:23 +00:00
|
|
|
|
|
|
|
// 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
|
2024-08-20 15:32:06 +00:00
|
|
|
var e *LibError = nil
|
2024-08-19 17:15:23 +00:00
|
|
|
|
|
|
|
// act & assert
|
|
|
|
assert.Equal(t, "", e.GeneralError())
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGeneralError_GivenNotExistCat_ShouldReturnEmptyString(t *testing.T) {
|
|
|
|
// setup
|
2024-08-20 15:32:06 +00:00
|
|
|
e := LibError{category: 123456}
|
2024-08-19 17:15:23 +00:00
|
|
|
|
|
|
|
// act & assert
|
|
|
|
assert.Equal(t, "", e.GeneralError())
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGeneralError_GivenCatDB_ShouldReturnDBError(t *testing.T) {
|
|
|
|
// setup
|
2024-08-20 15:32:06 +00:00
|
|
|
e := LibError{category: code2.CatDB}
|
2024-08-19 17:15:23 +00:00
|
|
|
catErrStr := code2.CatToStr[code2.CatDB]
|
|
|
|
|
|
|
|
// act & assert
|
|
|
|
assert.Equal(t, catErrStr, e.GeneralError())
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestError_GivenEmptyMsg_ShouldReturnCatGeneralErrorMessage(t *testing.T) {
|
|
|
|
// setup
|
2024-08-20 15:32:06 +00:00
|
|
|
e := LibError{category: code2.CatDB, msg: ""}
|
2024-08-19 17:15:23 +00:00
|
|
|
|
|
|
|
// act
|
|
|
|
errMsg := e.Error()
|
|
|
|
|
|
|
|
// assert
|
|
|
|
assert.Equal(t, code2.CatToStr[code2.CatDB], errMsg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestError_GivenMsg_ShouldReturnGiveMsg(t *testing.T) {
|
|
|
|
// setup
|
2024-08-20 15:32:06 +00:00
|
|
|
e := LibError{msg: "FAKE"}
|
2024-08-19 17:15:23 +00:00
|
|
|
|
|
|
|
// act
|
|
|
|
errMsg := e.Error()
|
|
|
|
|
|
|
|
// assert
|
|
|
|
assert.Equal(t, "FAKE", errMsg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestIs_GivenNilErr_ShouldReturnFalse(t *testing.T) {
|
2024-08-20 15:32:06 +00:00
|
|
|
var nilErrs *LibError
|
2024-08-19 17:15:23 +00:00
|
|
|
// 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) {
|
2024-08-20 15:32:06 +00:00
|
|
|
var nilErr *LibError = nil
|
2024-08-19 17:15:23 +00:00
|
|
|
|
|
|
|
// 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
|
2024-08-20 15:32:06 +00:00
|
|
|
var nilErr2 *LibError = nil
|
2024-08-19 17:15:23 +00:00
|
|
|
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() {
|
2024-08-20 15:32:06 +00:00
|
|
|
var e *LibError = nil
|
2024-08-19 17:15:23 +00:00
|
|
|
_ = 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) {
|
2024-08-20 15:32:06 +00:00
|
|
|
var e *LibError = nil
|
2024-08-19 17:15:23 +00:00
|
|
|
internalErr := e.Unwrap()
|
|
|
|
assert.Nil(t, internalErr)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestErrorsIs_GivenNilErr_ShouldReturnFalse(t *testing.T) {
|
2024-08-20 15:32:06 +00:00
|
|
|
var e *LibError = nil
|
2024-08-19 17:15:23 +00:00
|
|
|
assert.False(t, errors.Is(e, fmt.Errorf("test")))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestErrorsAs_GivenNilErr_ShouldReturnFalse(t *testing.T) {
|
|
|
|
var internalErr *testErr
|
2024-08-20 15:32:06 +00:00
|
|
|
var e *LibError = nil
|
2024-08-19 17:15:23 +00:00
|
|
|
assert.False(t, errors.As(e, &internalErr))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGRPCStatus(t *testing.T) {
|
|
|
|
// setup table driven tests
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
2024-08-20 15:32:06 +00:00
|
|
|
given *LibError
|
2024-08-19 17:15:23 +00:00
|
|
|
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
|
2024-08-20 15:32:06 +00:00
|
|
|
err *LibError
|
2024-08-19 17:15:23 +00:00
|
|
|
want int
|
|
|
|
}{
|
|
|
|
{name: "nil error", err: nil, want: http.StatusOK},
|
2024-08-20 15:32:06 +00:00
|
|
|
{name: "invalid measurement id", err: &LibError{category: code2.CatResource, code: code2.InvalidMeasurementID}, want: http.StatusInternalServerError},
|
|
|
|
{name: "resource already exists", err: &LibError{category: code2.CatResource, code: code2.ResourceAlreadyExist}, want: http.StatusConflict},
|
|
|
|
{name: "invalid resource state", err: &LibError{category: code2.CatResource, code: code2.InvalidResourceState}, want: http.StatusConflict},
|
|
|
|
{name: "invalid posix time", err: &LibError{category: code2.CatAuth, code: code2.InvalidPosixTime}, want: http.StatusForbidden},
|
|
|
|
{name: "unauthorized", err: &LibError{category: code2.CatAuth, code: code2.Unauthorized}, want: http.StatusUnauthorized},
|
|
|
|
{name: "db error", err: &LibError{category: code2.CatDB, code: code2.DBError}, want: http.StatusInternalServerError},
|
|
|
|
{name: "insufficient permission", err: &LibError{category: code2.CatResource, code: code2.InsufficientPermission}, want: http.StatusUnauthorized},
|
|
|
|
{name: "resource insufficient", err: &LibError{category: code2.CatResource, code: code2.ResourceInsufficient}, want: http.StatusBadRequest},
|
|
|
|
{name: "invalid format", err: &LibError{category: code2.CatInput, code: code2.InvalidFormat}, want: http.StatusBadRequest},
|
|
|
|
{name: "resource not found", err: &LibError{code: code2.ResourceNotFound}, want: http.StatusNotFound},
|
|
|
|
{name: "ok", err: &LibError{code: code2.OK}, want: http.StatusOK},
|
|
|
|
{name: "not valid implementation", err: &LibError{category: code2.CatInput, code: code2.NotValidImplementation}, want: http.StatusNotImplemented},
|
|
|
|
{name: "forbidden", err: &LibError{category: code2.CatAuth, code: code2.Forbidden}, want: http.StatusForbidden},
|
|
|
|
{name: "insufficient quota", err: &LibError{category: code2.CatResource, code: code2.InsufficientQuota}, want: http.StatusPaymentRequired},
|
2024-08-19 17:15:23 +00:00
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
|
|
|
// act
|
|
|
|
got := tt.err.HTTPStatus()
|
|
|
|
|
|
|
|
// assert
|
|
|
|
assert.Equal(t, tt.want, got)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|