feat: export dynfunc errors
This commit is contained in:
parent
b4a426adcc
commit
8c122e9ddf
|
@ -1,50 +1,52 @@
|
|||
package dynfunc
|
||||
|
||||
// cerr allows you to create constant "const" error with type boxing.
|
||||
type cerr string
|
||||
// Err allows you to create constant "const" error with type boxing.
|
||||
type Err string
|
||||
|
||||
func (err cerr) Error() string {
|
||||
func (err Err) Error() string {
|
||||
return string(err)
|
||||
}
|
||||
|
||||
// errHandlerNotFunc - handler is not a func
|
||||
const errHandlerNotFunc = cerr("handler must be a func")
|
||||
const (
|
||||
// ErrHandlerNotFunc - handler is not a func
|
||||
ErrHandlerNotFunc = Err("handler must be a func")
|
||||
|
||||
// errNoServiceForHandler - no service matching this handler
|
||||
const errNoServiceForHandler = cerr("no service found for this handler")
|
||||
// ErrNoServiceForHandler - no service matching this handler
|
||||
ErrNoServiceForHandler = Err("no service found for this handler")
|
||||
|
||||
// errMissingHandlerArgumentParam - missing params arguments for handler
|
||||
const errMissingHandlerContextArgument = cerr("missing handler first argument of type context.Context")
|
||||
// errMissingHandlerArgumentParam - missing params arguments for handler
|
||||
ErrMissingHandlerContextArgument = Err("missing handler first argument of type context.Context")
|
||||
|
||||
// errMissingHandlerInputArgument - missing params arguments for handler
|
||||
const errMissingHandlerInputArgument = cerr("missing handler argument: input struct")
|
||||
// ErrMissingHandlerInputArgument - missing params arguments for handler
|
||||
ErrMissingHandlerInputArgument = Err("missing handler argument: input struct")
|
||||
|
||||
// errUnexpectedInput - input argument is not expected
|
||||
const errUnexpectedInput = cerr("unexpected input struct")
|
||||
// ErrUnexpectedInput - input argument is not expected
|
||||
ErrUnexpectedInput = Err("unexpected input struct")
|
||||
|
||||
// errMissingHandlerOutputArgument - missing output for handler
|
||||
const errMissingHandlerOutputArgument = cerr("missing handler first output argument: output struct")
|
||||
// ErrMissingHandlerOutputArgument - missing output for handler
|
||||
ErrMissingHandlerOutputArgument = Err("missing handler first output argument: output struct")
|
||||
|
||||
// errMissingHandlerOutputError - missing error output for handler
|
||||
const errMissingHandlerOutputError = cerr("missing handler last output argument of type api.Err")
|
||||
// ErrMissingHandlerOutputError - missing error output for handler
|
||||
ErrMissingHandlerOutputError = Err("missing handler last output argument of type api.Err")
|
||||
|
||||
// errMissingRequestArgument - missing request argument for handler
|
||||
const errMissingRequestArgument = cerr("handler first argument must be of type api.Request")
|
||||
// ErrMissingRequestArgument - missing request argument for handler
|
||||
ErrMissingRequestArgument = Err("handler first argument must be of type api.Request")
|
||||
|
||||
// errMissingParamArgument - missing parameters argument for handler
|
||||
const errMissingParamArgument = cerr("handler second argument must be a struct")
|
||||
// ErrMissingParamArgument - missing parameters argument for handler
|
||||
ErrMissingParamArgument = Err("handler second argument must be a struct")
|
||||
|
||||
// errUnexportedName - argument is unexported in struct
|
||||
const errUnexportedName = cerr("unexported name")
|
||||
// ErrUnexportedName - argument is unexported in struct
|
||||
ErrUnexportedName = Err("unexported name")
|
||||
|
||||
// errWrongOutputArgumentType - wrong type for output first argument
|
||||
const errWrongOutputArgumentType = cerr("handler first output argument must be a *struct")
|
||||
// ErrWrongOutputArgumentType - wrong type for output first argument
|
||||
ErrWrongOutputArgumentType = Err("handler first output argument must be a *struct")
|
||||
|
||||
// errMissingConfigArgument - missing an input/output argument in handler struct
|
||||
const errMissingConfigArgument = cerr("missing an argument from the configuration")
|
||||
// ErrMissingConfigArgument - missing an input/output argument in handler struct
|
||||
ErrMissingConfigArgument = Err("missing an argument from the configuration")
|
||||
|
||||
// errWrongParamTypeFromConfig - a configuration parameter type is invalid in the handler param struct
|
||||
const errWrongParamTypeFromConfig = cerr("invalid struct field type")
|
||||
// ErrWrongParamTypeFromConfig - a configuration parameter type is invalid in the handler param struct
|
||||
ErrWrongParamTypeFromConfig = Err("invalid struct field type")
|
||||
|
||||
// errMissingHandlerErrorArgument - missing handler output error
|
||||
const errMissingHandlerErrorArgument = cerr("last output must be of type api.Err")
|
||||
// ErrMissingHandlerErrorArgument - missing handler output error
|
||||
ErrMissingHandlerErrorArgument = Err("last output must be of type api.Err")
|
||||
)
|
||||
|
|
|
@ -38,7 +38,7 @@ func Build(fn interface{}, service config.Service) (*Handler, error) {
|
|||
)
|
||||
|
||||
if fnType.Kind() != reflect.Func {
|
||||
return nil, errHandlerNotFunc
|
||||
return nil, ErrHandlerNotFunc
|
||||
}
|
||||
if err := h.signature.ValidateInput(fnType); err != nil {
|
||||
return nil, fmt.Errorf("input: %w", err)
|
||||
|
|
|
@ -53,7 +53,7 @@ func (s *Signature) ValidateInput(handlerType reflect.Type) error {
|
|||
|
||||
// missing or invalid first arg: context.Context
|
||||
if handlerType.NumIn() < 1 {
|
||||
return errMissingHandlerContextArgument
|
||||
return ErrMissingHandlerContextArgument
|
||||
}
|
||||
firstArgType := handlerType.In(0)
|
||||
|
||||
|
@ -65,35 +65,35 @@ func (s *Signature) ValidateInput(handlerType reflect.Type) error {
|
|||
if len(s.Input) == 0 {
|
||||
// input struct provided
|
||||
if handlerType.NumIn() > 1 {
|
||||
return errUnexpectedInput
|
||||
return ErrUnexpectedInput
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// too much arguments
|
||||
if handlerType.NumIn() > 2 {
|
||||
return errMissingHandlerInputArgument
|
||||
return ErrMissingHandlerInputArgument
|
||||
}
|
||||
|
||||
// arg must be a struct
|
||||
inStruct := handlerType.In(1)
|
||||
if inStruct.Kind() != reflect.Struct {
|
||||
return errMissingParamArgument
|
||||
return ErrMissingParamArgument
|
||||
}
|
||||
|
||||
// check for invalid param
|
||||
for name, ptype := range s.Input {
|
||||
if name[0] == strings.ToLower(name)[0] {
|
||||
return fmt.Errorf("%s: %w", name, errUnexportedName)
|
||||
return fmt.Errorf("%s: %w", name, ErrUnexportedName)
|
||||
}
|
||||
|
||||
field, exists := inStruct.FieldByName(name)
|
||||
if !exists {
|
||||
return fmt.Errorf("%s: %w", name, errMissingConfigArgument)
|
||||
return fmt.Errorf("%s: %w", name, ErrMissingConfigArgument)
|
||||
}
|
||||
|
||||
if !ptype.AssignableTo(field.Type) {
|
||||
return fmt.Errorf("%s: %w (%s instead of %s)", name, errWrongParamTypeFromConfig, field.Type, ptype)
|
||||
return fmt.Errorf("%s: %w (%s instead of %s)", name, ErrWrongParamTypeFromConfig, field.Type, ptype)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,13 +105,13 @@ func (s Signature) ValidateOutput(handlerType reflect.Type) error {
|
|||
errType := reflect.TypeOf(api.ErrUnknown)
|
||||
|
||||
if handlerType.NumOut() < 1 {
|
||||
return errMissingHandlerErrorArgument
|
||||
return ErrMissingHandlerErrorArgument
|
||||
}
|
||||
|
||||
// last output must be api.Err
|
||||
lastArgType := handlerType.Out(handlerType.NumOut() - 1)
|
||||
if !lastArgType.AssignableTo(errType) {
|
||||
return errMissingHandlerErrorArgument
|
||||
return ErrMissingHandlerErrorArgument
|
||||
}
|
||||
|
||||
// no output -> ok
|
||||
|
@ -120,29 +120,29 @@ func (s Signature) ValidateOutput(handlerType reflect.Type) error {
|
|||
}
|
||||
|
||||
if handlerType.NumOut() < 2 {
|
||||
return errMissingHandlerOutputArgument
|
||||
return ErrMissingHandlerOutputArgument
|
||||
}
|
||||
|
||||
// fail if first output is not a pointer to struct
|
||||
outStructPtr := handlerType.Out(0)
|
||||
if outStructPtr.Kind() != reflect.Ptr {
|
||||
return errWrongOutputArgumentType
|
||||
return ErrWrongOutputArgumentType
|
||||
}
|
||||
|
||||
outStruct := outStructPtr.Elem()
|
||||
if outStruct.Kind() != reflect.Struct {
|
||||
return errWrongOutputArgumentType
|
||||
return ErrWrongOutputArgumentType
|
||||
}
|
||||
|
||||
// fail on invalid output
|
||||
for name, ptype := range s.Output {
|
||||
if name[0] == strings.ToLower(name)[0] {
|
||||
return fmt.Errorf("%s: %w", name, errUnexportedName)
|
||||
return fmt.Errorf("%s: %w", name, ErrUnexportedName)
|
||||
}
|
||||
|
||||
field, exists := outStruct.FieldByName(name)
|
||||
if !exists {
|
||||
return fmt.Errorf("%s: %w", name, errMissingConfigArgument)
|
||||
return fmt.Errorf("%s: %w", name, ErrMissingConfigArgument)
|
||||
}
|
||||
|
||||
// ignore types evalutating to nil
|
||||
|
@ -151,7 +151,7 @@ func (s Signature) ValidateOutput(handlerType reflect.Type) error {
|
|||
}
|
||||
|
||||
if !field.Type.ConvertibleTo(ptype) {
|
||||
return fmt.Errorf("%s: %w (%s instead of %s)", name, errWrongParamTypeFromConfig, field.Type, ptype)
|
||||
return fmt.Errorf("%s: %w (%s instead of %s)", name, ErrWrongParamTypeFromConfig, field.Type, ptype)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,14 +30,14 @@ func TestInputCheck(t *testing.T) {
|
|||
Input: map[string]reflect.Type{},
|
||||
Fn: func(context.Context, int) {},
|
||||
FnCtx: func(context.Context, int) {},
|
||||
Err: errUnexpectedInput,
|
||||
Err: ErrUnexpectedInput,
|
||||
},
|
||||
{
|
||||
Name: "no input 2 given",
|
||||
Input: map[string]reflect.Type{},
|
||||
Fn: func(context.Context, int, string) {},
|
||||
FnCtx: func(context.Context, int, string) {},
|
||||
Err: errUnexpectedInput,
|
||||
Err: ErrUnexpectedInput,
|
||||
},
|
||||
{
|
||||
Name: "1 input 0 given",
|
||||
|
@ -46,7 +46,7 @@ func TestInputCheck(t *testing.T) {
|
|||
},
|
||||
Fn: func(context.Context) {},
|
||||
FnCtx: func(context.Context) {},
|
||||
Err: errMissingHandlerInputArgument,
|
||||
Err: ErrMissingHandlerInputArgument,
|
||||
},
|
||||
{
|
||||
Name: "1 input non-struct given",
|
||||
|
@ -55,7 +55,7 @@ func TestInputCheck(t *testing.T) {
|
|||
},
|
||||
Fn: func(context.Context, int) {},
|
||||
FnCtx: func(context.Context, int) {},
|
||||
Err: errMissingParamArgument,
|
||||
Err: ErrMissingParamArgument,
|
||||
},
|
||||
{
|
||||
Name: "unexported input",
|
||||
|
@ -64,7 +64,7 @@ func TestInputCheck(t *testing.T) {
|
|||
},
|
||||
Fn: func(context.Context, struct{}) {},
|
||||
FnCtx: func(context.Context, struct{}) {},
|
||||
Err: errUnexportedName,
|
||||
Err: ErrUnexportedName,
|
||||
},
|
||||
{
|
||||
Name: "1 input empty struct given",
|
||||
|
@ -73,7 +73,7 @@ func TestInputCheck(t *testing.T) {
|
|||
},
|
||||
Fn: func(context.Context, struct{}) {},
|
||||
FnCtx: func(context.Context, struct{}) {},
|
||||
Err: errMissingConfigArgument,
|
||||
Err: ErrMissingConfigArgument,
|
||||
},
|
||||
{
|
||||
Name: "1 input invalid given",
|
||||
|
@ -82,7 +82,7 @@ func TestInputCheck(t *testing.T) {
|
|||
},
|
||||
Fn: func(context.Context, struct{ Test1 string }) {},
|
||||
FnCtx: func(context.Context, struct{ Test1 string }) {},
|
||||
Err: errWrongParamTypeFromConfig,
|
||||
Err: ErrWrongParamTypeFromConfig,
|
||||
},
|
||||
{
|
||||
Name: "1 input valid given",
|
||||
|
@ -100,7 +100,7 @@ func TestInputCheck(t *testing.T) {
|
|||
},
|
||||
Fn: func(context.Context, struct{}) {},
|
||||
FnCtx: func(context.Context, struct{}) {},
|
||||
Err: errMissingConfigArgument,
|
||||
Err: ErrMissingConfigArgument,
|
||||
},
|
||||
{
|
||||
Name: "1 input ptr invalid given",
|
||||
|
@ -109,7 +109,7 @@ func TestInputCheck(t *testing.T) {
|
|||
},
|
||||
Fn: func(context.Context, struct{ Test1 string }) {},
|
||||
FnCtx: func(context.Context, struct{ Test1 string }) {},
|
||||
Err: errWrongParamTypeFromConfig,
|
||||
Err: ErrWrongParamTypeFromConfig,
|
||||
},
|
||||
{
|
||||
Name: "1 input ptr invalid ptr type given",
|
||||
|
@ -118,7 +118,7 @@ func TestInputCheck(t *testing.T) {
|
|||
},
|
||||
Fn: func(context.Context, struct{ Test1 *string }) {},
|
||||
FnCtx: func(context.Context, struct{ Test1 *string }) {},
|
||||
Err: errWrongParamTypeFromConfig,
|
||||
Err: ErrWrongParamTypeFromConfig,
|
||||
},
|
||||
{
|
||||
Name: "1 input ptr valid given",
|
||||
|
@ -261,13 +261,13 @@ func TestOutputCheck(t *testing.T) {
|
|||
{
|
||||
Output: map[string]reflect.Type{},
|
||||
Fn: func(context.Context) {},
|
||||
Err: errMissingHandlerOutputArgument,
|
||||
Err: ErrMissingHandlerOutputArgument,
|
||||
},
|
||||
// no input -> with last type not api.Err
|
||||
{
|
||||
Output: map[string]reflect.Type{},
|
||||
Fn: func(context.Context) bool { return true },
|
||||
Err: errMissingHandlerErrorArgument,
|
||||
Err: ErrMissingHandlerErrorArgument,
|
||||
},
|
||||
// no input -> with api.Err
|
||||
{
|
||||
|
@ -279,13 +279,13 @@ func TestOutputCheck(t *testing.T) {
|
|||
{
|
||||
Output: map[string]reflect.Type{},
|
||||
Fn: func(context.Context) api.Err { return api.ErrSuccess },
|
||||
Err: errMissingHandlerContextArgument,
|
||||
Err: ErrMissingHandlerContextArgument,
|
||||
},
|
||||
// no input -> invlaid context.Context type
|
||||
{
|
||||
Output: map[string]reflect.Type{},
|
||||
Fn: func(context.Context, int) api.Err { return api.ErrSuccess },
|
||||
Err: errMissingHandlerContextArgument,
|
||||
Err: ErrMissingHandlerContextArgument,
|
||||
},
|
||||
// func can have output if not specified
|
||||
{
|
||||
|
@ -299,7 +299,7 @@ func TestOutputCheck(t *testing.T) {
|
|||
"Test1": reflect.TypeOf(int(0)),
|
||||
},
|
||||
Fn: func() api.Err { return api.ErrSuccess },
|
||||
Err: errWrongOutputArgumentType,
|
||||
Err: ErrWrongOutputArgumentType,
|
||||
},
|
||||
// output not a pointer
|
||||
{
|
||||
|
@ -307,7 +307,7 @@ func TestOutputCheck(t *testing.T) {
|
|||
"Test1": reflect.TypeOf(int(0)),
|
||||
},
|
||||
Fn: func() (int, api.Err) { return 0, api.ErrSuccess },
|
||||
Err: errWrongOutputArgumentType,
|
||||
Err: ErrWrongOutputArgumentType,
|
||||
},
|
||||
// output not a pointer to struct
|
||||
{
|
||||
|
@ -315,7 +315,7 @@ func TestOutputCheck(t *testing.T) {
|
|||
"Test1": reflect.TypeOf(int(0)),
|
||||
},
|
||||
Fn: func() (*int, api.Err) { return nil, api.ErrSuccess },
|
||||
Err: errWrongOutputArgumentType,
|
||||
Err: ErrWrongOutputArgumentType,
|
||||
},
|
||||
// unexported param name
|
||||
{
|
||||
|
@ -323,7 +323,7 @@ func TestOutputCheck(t *testing.T) {
|
|||
"test1": reflect.TypeOf(int(0)),
|
||||
},
|
||||
Fn: func() (*struct{}, api.Err) { return nil, api.ErrSuccess },
|
||||
Err: errUnexportedName,
|
||||
Err: ErrUnexportedName,
|
||||
},
|
||||
// output field missing
|
||||
{
|
||||
|
@ -331,7 +331,7 @@ func TestOutputCheck(t *testing.T) {
|
|||
"Test1": reflect.TypeOf(int(0)),
|
||||
},
|
||||
Fn: func() (*struct{}, api.Err) { return nil, api.ErrSuccess },
|
||||
Err: errMissingConfigArgument,
|
||||
Err: ErrMissingConfigArgument,
|
||||
},
|
||||
// output field invalid type
|
||||
{
|
||||
|
@ -339,7 +339,7 @@ func TestOutputCheck(t *testing.T) {
|
|||
"Test1": reflect.TypeOf(int(0)),
|
||||
},
|
||||
Fn: func() (*struct{ Test1 string }, api.Err) { return nil, api.ErrSuccess },
|
||||
Err: errWrongParamTypeFromConfig,
|
||||
Err: ErrWrongParamTypeFromConfig,
|
||||
},
|
||||
// output field valid type
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue