library-go/errors/easy_func_test.go

1070 lines
28 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package errors
import (
"context"
"errors"
"fmt"
"reflect"
"strconv"
"testing"
"code.30cm.net/digimon/library-go/errors/code"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func TestFromGRPCError_GivenStatusWithCodeAndMessage_ShouldReturnErr(t *testing.T) {
// setup
s := status.Error(codes.Code(102399), "FAKE ERROR")
// act
e := FromGRPCError(s)
// assert
assert.Equal(t, uint32(10), e.Scope())
assert.Equal(t, uint32(2300), e.Category())
assert.Equal(t, uint32(2399), e.Code())
assert.Equal(t, "FAKE ERROR", e.Error())
}
func TestFromGRPCError_GivenNilError_ShouldReturnErr_Scope0_Cat0_Detail0(t *testing.T) {
// setup
var nilError error = nil
// act
e := FromGRPCError(nilError)
// 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 TestFromGRPCError_GivenGRPCNativeError_ShouldReturnErr_Scope0_CatGRPC_DetailGRPCUnavailable(t *testing.T) {
// setup
msg := "GRPC Unavailable ERROR"
s := status.Error(codes.Code(codes.Unavailable), msg)
// act
e := FromGRPCError(s)
// assert
assert.Equal(t, code.Unset, e.Scope())
assert.Equal(t, code.CatGRPC, e.Category())
assert.Equal(t, uint32(codes.Unavailable), e.Code())
assert.Equal(t, msg, e.Error())
}
func TestFromGRPCError_GivenGeneralError_ShouldReturnErr_Scope0_CatGRPC_DetailGRPCUnknown(t *testing.T) {
// setup
generalErr := errors.New("general error")
// act
e := FromGRPCError(generalErr)
// assert
assert.Equal(t, code.Unset, e.Scope())
assert.Equal(t, code.CatGRPC, e.Category())
assert.Equal(t, uint32(codes.Unknown), e.Code())
}
func TestToGRPCError_GivenErr_StatusShouldHave_Code112233(t *testing.T) {
// setup
e := LibError{scope: 11, code: 2233, msg: "FAKE MSG"}
// act
err := ToGRPCError(&e)
s, _ := status.FromError(err)
// assert
assert.Equal(t, 112233, int(s.Code()))
assert.Equal(t, "FAKE MSG", s.Message())
}
func TestInvalidFormat_WithStrings_ShouldHasCatInputAndDetailCode(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := InvalidFormat("field A", "Error description")
// assert
assert.Equal(t, code.CatInput, e.Category())
assert.Equal(t, code.InvalidFormat, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Equal(t, e.Error(), "invalid format: field A Error description")
}
func TestInvalidFormatL_WithStrings_ShouldHasCatInputAndDetailCode(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.Background()
// act
e := InvalidFormatL(logx.WithContext(ctx), "field A", "Error description")
// assert
assert.Equal(t, code.CatInput, e.Category())
assert.Equal(t, code.InvalidFormat, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestInvalidRange_WithStrings_ShouldHasCatInputAndDetailCode(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := InvalidRange("field A", "Error description")
// assert
assert.Equal(t, code.CatInput, e.Category())
assert.Equal(t, code.InvalidRange, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Equal(t, e.Error(), "invalid range: field A Error description")
}
func TestInvalidRangeL_WithStrings_ShouldHasCatInputAndDetailCode(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.Background()
// act
e := InvalidRangeL(logx.WithContext(ctx), "field A", "Error description")
// assert
assert.Equal(t, code.CatInput, e.Category())
assert.Equal(t, code.InvalidRange, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestNotValidImplementation_WithStrings_ShouldHasCatInputAndDetailCode(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := NotValidImplementation("field A", "Error description")
// assert
assert.Equal(t, code.CatInput, e.Category())
assert.Equal(t, code.NotValidImplementation, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Equal(t, e.Error(), "not valid implementation: field A Error description")
}
func TestNotValidImplementationL_WithStrings_ShouldHasCatInputAndDetailCode(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := logx.WithContext(context.Background())
// act
e := NotValidImplementationL(l, "field A", "Error description")
// assert
assert.Equal(t, code.CatInput, e.Category())
assert.Equal(t, code.NotValidImplementation, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestDBError_WithStrings_ShouldHasCatDBAndDetailCodeDBError(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := DBError("field A", "Error description")
// assert
assert.Equal(t, code.CatDB, e.Category())
assert.Equal(t, code.DBError, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestDBDataConvert_WithStrings_ShouldHasCatDBAndDetailCodeDBDataConvert(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := DBDataConvert("field A", "Error description")
// assert
assert.Equal(t, code.CatDB, e.Category())
assert.Equal(t, code.DBDataConvert, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestResourceNotFound_WithStrings_ShouldHasCatResource_DetailCodeResourceNotFound(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := ResourceNotFound("field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.ResourceNotFound, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestInvalidResourceFormat_WithStrings_ShouldHasCatResource_DetailCodeInvalidResourceFormat(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := InvalidResourceFormat("field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.InvalidResourceFormat, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestInvalidResourceState_OK(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := InvalidResourceState("field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.InvalidResourceState, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.EqualError(t, e, "invalid resource state: field A Error description")
}
func TestInvalidResourceStateL_LogError(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := logx.WithContext(context.Background())
// act
e := InvalidResourceStateL(l, "field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.InvalidResourceState, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.EqualError(t, e, "invalid resource state: field A Error description")
}
func TestAuthExpired_OK(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := AuthExpired("field A", "Error description")
// assert
assert.Equal(t, code.CatAuth, e.Category())
assert.Equal(t, code.AuthExpired, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestUnauthorized_WithStrings_ShouldHasCatAuth_DetailCodeUnauthorized(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := Unauthorized("field A", "Error description")
// assert
assert.Equal(t, code.CatAuth, e.Category())
assert.Equal(t, code.Unauthorized, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestInvalidPosixTime_WithStrings_ShouldHasCatAuth_DetailCodeInvalidPosixTime(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := InvalidPosixTime("field A", "Error description")
// assert
assert.Equal(t, code.CatAuth, e.Category())
assert.Equal(t, code.InvalidPosixTime, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestSigAndPayloadNotMatched_WithStrings_ShouldHasCatAuth_DetailCodeSigAndPayloadNotMatched(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := SigAndPayloadNotMatched("field A", "Error description")
// assert
assert.Equal(t, code.CatAuth, e.Category())
assert.Equal(t, code.SigAndPayloadNotMatched, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestForbidden_WithStrings_ShouldHasCatAuth_DetailCodeForbidden(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := Forbidden("field A", "Error description")
// assert
assert.Equal(t, code.CatAuth, e.Category())
assert.Equal(t, code.Forbidden, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestXBCInternal_WithStrings_ShouldHasCatResource_DetailCodeXBCInternal(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := ArkInternal("field A", "Error description")
// assert
assert.Equal(t, code.CatArk, e.Category())
assert.Equal(t, code.ArkInternal, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestGeneralInternalError_WithStrings_DetailInternalError(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := SystemInternalError("field A", "Error description")
// assert
assert.Equal(t, code.CatSystem, e.Category())
assert.Equal(t, code.SystemInternalError, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestGeneralInternalErrorL_WithStrings_DetailInternalError(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := logx.WithContext(context.Background())
// act
e := SystemInternalErrorL(l, "field A", "Error description")
// assert
assert.Equal(t, code.CatSystem, e.Category())
assert.Equal(t, code.SystemInternalError, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestSystemMaintainError_WithStrings_DetailSystemMaintainError(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := logx.WithContext(context.Background())
// act
e := SystemMaintainErrorL(l, "field A", "Error description")
// assert
assert.Equal(t, code.CatSystem, e.Category())
assert.Equal(t, code.SystemMaintainError, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestResourceAlreadyExist_WithStrings_DetailInternalError(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := ResourceAlreadyExist("field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.ResourceAlreadyExist, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestResourceAlreadyExistL_WithStrings_DetailInternalError(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := logx.WithContext(context.Background())
// act
e := ResourceAlreadyExistL(l, "field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.ResourceAlreadyExist, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestResourceInsufficient_WithStrings_DetailInternalError(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := ResourceInsufficient("field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.ResourceInsufficient, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestResourceInsufficientL_WithStrings_DetailInternalError(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := logx.WithContext(context.Background())
// act
e := ResourceInsufficientL(l, "field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.ResourceInsufficient, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestInsufficientPermission_WithStrings_DetailInternalError(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := InsufficientPermission("field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.InsufficientPermission, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestInsufficientPermissionL_WithStrings_DetailInternalError(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := logx.WithContext(context.Background())
// act
e := InsufficientPermissionL(l, "field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.InsufficientPermission, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestInvalidMeasurementID_WithErrorStrings_ShouldReturnCorrectCodeAndErrorString(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := InvalidMeasurementID("field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.InvalidMeasurementID, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestInvalidMeasurementIDL_WithErrorStrings_ShouldReturnCorrectCodeAndErrorStringAndCallLogger(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := logx.WithContext(context.Background())
// act
e := InvalidMeasurementIDL(l, "field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.InvalidMeasurementID, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestResourceExpired_OK(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := ResourceExpired("field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.ResourceExpired, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestResourceExpiredL_LogError(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := logx.WithContext(context.Background())
// act
e := ResourceExpiredL(l, "field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.ResourceExpired, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestResourceMigrated_OK(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := ResourceMigrated("field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.ResourceMigrated, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestResourceMigratedL_LogError(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := logx.WithContext(context.Background())
// act
e := ResourceMigratedL(l, "field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.ResourceMigrated, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestInsufficientQuota_OK(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := InsufficientQuota("field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.InsufficientQuota, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestInsufficientQuotaL_LogError(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := logx.WithContext(context.Background())
// act
e := InsufficientQuotaL(l, "field A", "Error description")
// assert
assert.Equal(t, code.CatResource, e.Category())
assert.Equal(t, code.InsufficientQuota, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestPublish_WithErrorStrings_ShouldReturnCorrectCodeAndErrorString(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := Publish("field A", "Error description")
// assert
assert.Equal(t, code.CatPubSub, e.Category())
assert.Equal(t, code.Publish, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestPublishL_WithErrorStrings_ShouldReturnCorrectCodeAndErrorStringAndCallLogger(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := logx.WithContext(context.Background())
// act
e := PublishL(l, "field A", "Error description")
// assert
assert.Equal(t, code.CatPubSub, e.Category())
assert.Equal(t, code.Publish, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "field A")
assert.Contains(t, e.Error(), "Error description")
}
func TestMsgSizeTooLarge_WithErrorStrings_ShouldReturnCorrectCodeAndErrorString(t *testing.T) {
// setup
Scope = 99
defer func() {
Scope = code.Unset
}()
// act
e := MsgSizeTooLarge("Error description")
// assert
assert.Equal(t, code.CatPubSub, e.Category())
assert.Equal(t, code.MsgSizeTooLarge, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "kafka error: Error description")
}
func TestMsgSizeTooLargeL_WithErrorStrings_ShouldReturnCorrectCodeAndErrorStringAndCallLogger(t *testing.T) {
// setup
Scope = 99
defer func() { Scope = code.Unset }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := logx.WithContext(context.Background())
// act
e := MsgSizeTooLargeL(l, "Error description")
// assert
assert.Equal(t, code.CatPubSub, e.Category())
assert.Equal(t, code.MsgSizeTooLarge, e.Code())
assert.Equal(t, uint32(99), e.Scope())
assert.Contains(t, e.Error(), "kafka error: Error description")
}
// func TestStructErr_WithInternalErr_ShouldIsFuncReportCorrectly(t *testing.T) {
// // setup
// Scope = 99
// defer func() { Scope = code.Unset }()
// // arrange 2 layers err
// layer1Err := fmt.Errorf("layer 1 error")
// layer2Err := fmt.Errorf("layer 2: %w", layer1Err)
//
// // act with error chain: InvalidFormat -> layer 2 err -> layer 1 err
// e := InvalidFormat("field A", "Error description")
// err := e.Wrap(layer2Err)
// if err != nil {
// t.Fatalf("Failed to wrap error: %v", err)
// }
//
// // assert
// assert.Equal(t, code.CatInput, e.Category())
// assert.Equal(t, code.InvalidFormat, e.Code())
// assert.Equal(t, uint32(99), e.Scope())
// assert.Contains(t, e.Error(), "field A")
// assert.Contains(t, e.Error(), "Error description")
//
// // errors.Is should report correctly
// assert.True(t, errors.Is(e, layer1Err))
// assert.True(t, errors.Is(e, layer2Err))
// }
// func TestStructErr_WithInternalErr_ShouldErrorOutputChainErrMessage(t *testing.T) {
// // setup
// Scope = 99
// defer func() { Scope = code.Unset }()
//
// // arrange 2 layers err
// layer1Err := fmt.Errorf("layer 1 error")
// // act with error chain: InvalidFormat -> layer 1 err
// e := InvalidFormat("field A", "Error description")
// err := e.Wrap(layer1Err)
// if err != nil {
// t.Fatalf("Failed to wrap error: %v", err)
// }
//
// // assert
// assert.Equal(t, "invalid format: field A Error description: layer 1 error", e.Error())
// }
// arrange a specific err type just for UT
type testErr struct {
code int
}
func (e *testErr) Error() string {
return strconv.Itoa(e.code)
}
// func TestStructErr_WithInternalErr_ShouldAsFuncReportCorrectly(t *testing.T) {
// // setup
// Scope = 99
// defer func() { Scope = code.Unset }()
//
// testE := &testErr{code: 123}
// layer2Err := fmt.Errorf("layer 2: %w", testE)
//
// // act with error chain: InvalidFormat -> layer 2 err -> testErr
// e := InvalidFormat("field A", "Error description")
// err := e.Wrap(layer2Err)
// if err != nil {
// t.Fatalf("Failed to wrap error: %v", err)
// }
//
// // assert
// assert.Equal(t, code.CatInput, e.Category())
// assert.Equal(t, code.InvalidFormat, e.Code())
// assert.Equal(t, uint32(99), e.Scope())
// assert.Contains(t, e.Error(), "field A")
// assert.Contains(t, e.Error(), "Error description")
//
// // errors.As should report correctly
// var internalErr *testErr
// assert.True(t, errors.As(e, &internalErr))
// assert.Equal(t, testE, internalErr)
// }
/*
benchmark run for 1 second:
Benchmark_ErrorsIs_OneLayerError-4 148281332 8.68 ns/op 0 B/op 0 allocs/op
Benchmark_ErrorsIs_TwoLayerError-4 35048202 32.4 ns/op 0 B/op 0 allocs/op
Benchmark_ErrorsIs_FourLayerError-4 15309349 81.7 ns/op 0 B/op 0 allocs/op
Benchmark_ErrorsAs_OneLayerError-4 16893205 70.4 ns/op 0 B/op 0 allocs/op
Benchmark_ErrorsAs_TwoLayerError-4 10568083 112 ns/op 0 B/op 0 allocs/op
Benchmark_ErrorsAs_FourLayerError-4 6307729 188 ns/op 0 B/op 0 allocs/op
*/
func Benchmark_ErrorsIs_OneLayerError(b *testing.B) {
layer1Err := &testErr{code: 123}
var err error = layer1Err
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
errors.Is(err, layer1Err)
}
}
func Benchmark_ErrorsIs_TwoLayerError(b *testing.B) {
layer1Err := &testErr{code: 123}
// act with error chain: InvalidFormat(layer 2) -> testErr(layer 1)
layer2Err := InvalidFormat("field A", "Error description")
err := layer2Err.Wrap(layer1Err)
if err != nil {
b.Fatalf("Failed to wrap error: %v", err)
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
errors.Is(layer2Err, layer1Err)
}
}
func Benchmark_ErrorsIs_FourLayerError(b *testing.B) {
layer1Err := &testErr{code: 123}
layer2Err := fmt.Errorf("layer 2: %w", layer1Err)
layer3Err := fmt.Errorf("layer 3: %w", layer2Err)
// act with error chain: InvalidFormat(layer 4) -> Error(layer 3) -> Error(layer 2) -> testErr(layer 1)
layer4Err := InvalidFormat("field A", "Error description")
err := layer4Err.Wrap(layer3Err)
if err != nil {
b.Fatalf("Failed to wrap error: %v", err)
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
errors.Is(layer4Err, layer1Err)
}
}
func Benchmark_ErrorsAs_OneLayerError(b *testing.B) {
layer1Err := &testErr{code: 123}
var err error = layer1Err
b.ReportAllocs()
b.ResetTimer()
var internalErr *testErr
for i := 0; i < b.N; i++ {
errors.As(err, &internalErr)
}
}
func Benchmark_ErrorsAs_TwoLayerError(b *testing.B) {
layer1Err := &testErr{code: 123}
// act with error chain: InvalidFormat(layer 2) -> testErr(layer 1)
layer2Err := InvalidFormat("field A", "Error description")
err := layer2Err.Wrap(layer1Err)
if err != nil {
b.Fatalf("Failed to wrap error: %v", err)
}
b.ReportAllocs()
b.ResetTimer()
var internalErr *testErr
for i := 0; i < b.N; i++ {
errors.As(layer2Err, &internalErr)
}
}
func Benchmark_ErrorsAs_FourLayerError(b *testing.B) {
layer1Err := &testErr{code: 123}
layer2Err := fmt.Errorf("layer 2: %w", layer1Err)
layer3Err := fmt.Errorf("layer 3: %w", layer2Err)
// act with error chain: InvalidFormat(layer 4) -> Error(layer 3) -> Error(layer 2) -> testErr(layer 1)
layer4Err := InvalidFormat("field A", "Error description")
err := layer4Err.Wrap(layer3Err)
if err != nil {
b.Fatalf("Failed to wrap error: %v", err)
}
b.ReportAllocs()
b.ResetTimer()
var internalErr *testErr
for i := 0; i < b.N; i++ {
errors.As(layer4Err, &internalErr)
}
}
func TestFromError(t *testing.T) {
tests := []struct {
name string
givenError error
want *LibError
}{
{
"given nil error should return nil",
nil,
nil,
},
{
"given normal error should return nil",
errors.New("normal error"),
nil,
},
{
"given Err should return Err",
ResourceNotFound("fake error"),
ResourceNotFound("fake error"),
},
{
"given error wraps Err should return Err",
fmt.Errorf("outter error wraps %w", ResourceNotFound("fake error")),
ResourceNotFound("fake error"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := FromError(tt.givenError); !reflect.DeepEqual(got, tt.want) {
t.Errorf("FromError() = %v, want %v", got, tt.want)
}
})
}
}
func Test_newErr(t *testing.T) {
type args struct {
scope uint32
detail uint32
msg string
}
tests := []struct {
name string
args args
}{
{
name: "ok",
args: args{
scope: code.CloudEPMember,
detail: code.InvalidFormat,
msg: "gg88g88",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
er := newErr(tt.args.scope, tt.args.detail, tt.args.msg)
// er.CodeStr() 會補滿6碼業務邏輯要回應這個
// 105,060 前面兩位會乘一萬做計算中間兩位乘100 來做計算最後用補的
fmt.Println(er.Scope(), er.Category(), er.Code(), er.FullCode(), er.CodeStr())
fmt.Println(er.Error()) // 建立十原始錯誤 -> 業務邏輯,給客人看 gg88g88
er2 := fmt.Errorf("test origin err")
er = er.Wrap(er2) // 包裝錯誤
fmt.Println(er.Error()) // gg88g88: test origin err
err := er.Unwrap()
if err != nil {
return
}
})
}
}