unexport dynfunc errors

This commit is contained in:
Adrien Marquès 2020-04-04 12:46:43 +02:00
parent df56496a16
commit 90472b8bf7
Signed by: xdrm-brackets
GPG Key ID: D75243CA236D825E
4 changed files with 57 additions and 58 deletions

View File

@ -3,49 +3,48 @@ package dynfunc
// cerr allows you to create constant "const" error with type boxing. // cerr allows you to create constant "const" error with type boxing.
type cerr string type cerr string
// Error implements the error builtin interface.
func (err cerr) Error() string { func (err cerr) Error() string {
return string(err) return string(err)
} }
// ErrHandlerNotFunc - handler is not a func // errHandlerNotFunc - handler is not a func
const ErrHandlerNotFunc = cerr("handler must be a func") const errHandlerNotFunc = cerr("handler must be a func")
// ErrNoServiceForHandler - no service matching this handler // errNoServiceForHandler - no service matching this handler
const ErrNoServiceForHandler = cerr("no service found for this handler") const errNoServiceForHandler = cerr("no service found for this handler")
// ErrMissingHandlerArgumentParam - missing params arguments for handler // errMissingHandlerArgumentParam - missing params arguments for handler
const ErrMissingHandlerArgumentParam = cerr("missing handler argument : parameter struct") const errMissingHandlerArgumentParam = cerr("missing handler argument : parameter struct")
// ErrUnexpectedInput - input argument is not expected // errUnexpectedInput - input argument is not expected
const ErrUnexpectedInput = cerr("unexpected input struct") const errUnexpectedInput = cerr("unexpected input struct")
// ErrMissingHandlerOutput - missing output for handler // errMissingHandlerOutput - missing output for handler
const ErrMissingHandlerOutput = cerr("handler must have at least 1 output") const errMissingHandlerOutput = cerr("handler must have at least 1 output")
// ErrMissingHandlerOutputError - missing error output for handler // errMissingHandlerOutputError - missing error output for handler
const ErrMissingHandlerOutputError = cerr("handler must have its last output of type api.Error") const errMissingHandlerOutputError = cerr("handler must have its last output of type api.Error")
// ErrMissingRequestArgument - missing request argument for handler // errMissingRequestArgument - missing request argument for handler
const ErrMissingRequestArgument = cerr("handler first argument must be of type api.Request") const errMissingRequestArgument = cerr("handler first argument must be of type api.Request")
// ErrMissingParamArgument - missing parameters argument for handler // errMissingParamArgument - missing parameters argument for handler
const ErrMissingParamArgument = cerr("handler second argument must be a struct") const errMissingParamArgument = cerr("handler second argument must be a struct")
// ErrUnexportedName - argument is unexported in struct // errUnexportedName - argument is unexported in struct
const ErrUnexportedName = cerr("unexported name") const errUnexportedName = cerr("unexported name")
// ErrMissingParamOutput - missing output argument for handler // errMissingParamOutput - missing output argument for handler
const ErrMissingParamOutput = cerr("handler first output must be a *struct") const errMissingParamOutput = cerr("handler first output must be a *struct")
// ErrMissingParamFromConfig - missing a parameter in handler struct // errMissingParamFromConfig - missing a parameter in handler struct
const ErrMissingParamFromConfig = cerr("missing a parameter from configuration") const errMissingParamFromConfig = cerr("missing a parameter from configuration")
// ErrMissingOutputFromConfig - missing a parameter in handler struct // errMissingOutputFromConfig - missing a parameter in handler struct
const ErrMissingOutputFromConfig = cerr("missing a parameter from configuration") const errMissingOutputFromConfig = cerr("missing a parameter from configuration")
// ErrWrongParamTypeFromConfig - a configuration parameter type is invalid in the handler param struct // errWrongParamTypeFromConfig - a configuration parameter type is invalid in the handler param struct
const ErrWrongParamTypeFromConfig = cerr("invalid struct field type") const errWrongParamTypeFromConfig = cerr("invalid struct field type")
// ErrMissingHandlerErrorOutput - missing handler output error // errMissingHandlerErrorOutput - missing handler output error
const ErrMissingHandlerErrorOutput = cerr("last output must be of type api.Error") const errMissingHandlerErrorOutput = cerr("last output must be of type api.Error")

View File

@ -32,7 +32,7 @@ func Build(fn interface{}, service config.Service) (*Handler, error) {
fnv := reflect.ValueOf(fn) fnv := reflect.ValueOf(fn)
if fnv.Type().Kind() != reflect.Func { if fnv.Type().Kind() != reflect.Func {
return nil, ErrHandlerNotFunc return nil, errHandlerNotFunc
} }
if err := h.spec.checkInput(fnv); err != nil { if err := h.spec.checkInput(fnv); err != nil {

View File

@ -50,34 +50,34 @@ func (s spec) checkInput(fnv reflect.Value) error {
// no input -> ok // no input -> ok
if len(s.Input) == 0 { if len(s.Input) == 0 {
if fnt.NumIn() > 0 { if fnt.NumIn() > 0 {
return ErrUnexpectedInput return errUnexpectedInput
} }
return nil return nil
} }
if fnt.NumIn() != 1 { if fnt.NumIn() != 1 {
return ErrMissingHandlerArgumentParam return errMissingHandlerArgumentParam
} }
// arg must be a struct // arg must be a struct
structArg := fnt.In(0) structArg := fnt.In(0)
if structArg.Kind() != reflect.Struct { if structArg.Kind() != reflect.Struct {
return ErrMissingParamArgument return errMissingParamArgument
} }
// check for invalid param // check for invalid param
for name, ptype := range s.Input { for name, ptype := range s.Input {
if name[0] == strings.ToLower(name)[0] { if name[0] == strings.ToLower(name)[0] {
return fmt.Errorf("%s: %w", name, ErrUnexportedName) return fmt.Errorf("%s: %w", name, errUnexportedName)
} }
field, exists := structArg.FieldByName(name) field, exists := structArg.FieldByName(name)
if !exists { if !exists {
return fmt.Errorf("%s: %w", name, ErrMissingParamFromConfig) return fmt.Errorf("%s: %w", name, errMissingParamFromConfig)
} }
if !ptype.AssignableTo(field.Type) { 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)
} }
} }
@ -88,13 +88,13 @@ func (s spec) checkInput(fnv reflect.Value) error {
func (s spec) checkOutput(fnv reflect.Value) error { func (s spec) checkOutput(fnv reflect.Value) error {
fnt := fnv.Type() fnt := fnv.Type()
if fnt.NumOut() < 1 { if fnt.NumOut() < 1 {
return ErrMissingHandlerOutput return errMissingHandlerOutput
} }
// last output must be api.Error // last output must be api.Error
errOutput := fnt.Out(fnt.NumOut() - 1) errOutput := fnt.Out(fnt.NumOut() - 1)
if !errOutput.AssignableTo(reflect.TypeOf(api.ErrorUnknown)) { if !errOutput.AssignableTo(reflect.TypeOf(api.ErrorUnknown)) {
return ErrMissingHandlerErrorOutput return errMissingHandlerErrorOutput
} }
// no output -> ok // no output -> ok
@ -103,29 +103,29 @@ func (s spec) checkOutput(fnv reflect.Value) error {
} }
if fnt.NumOut() != 2 { if fnt.NumOut() != 2 {
return ErrMissingParamOutput return errMissingParamOutput
} }
// fail if first output is not a pointer to struct // fail if first output is not a pointer to struct
structOutputPtr := fnt.Out(0) structOutputPtr := fnt.Out(0)
if structOutputPtr.Kind() != reflect.Ptr { if structOutputPtr.Kind() != reflect.Ptr {
return ErrMissingParamOutput return errMissingParamOutput
} }
structOutput := structOutputPtr.Elem() structOutput := structOutputPtr.Elem()
if structOutput.Kind() != reflect.Struct { if structOutput.Kind() != reflect.Struct {
return ErrMissingParamOutput return errMissingParamOutput
} }
// fail on invalid output // fail on invalid output
for name, ptype := range s.Output { for name, ptype := range s.Output {
if name[0] == strings.ToLower(name)[0] { if name[0] == strings.ToLower(name)[0] {
return fmt.Errorf("%s: %w", name, ErrUnexportedName) return fmt.Errorf("%s: %w", name, errUnexportedName)
} }
field, exists := structOutput.FieldByName(name) field, exists := structOutput.FieldByName(name)
if !exists { if !exists {
return fmt.Errorf("%s: %w", name, ErrMissingOutputFromConfig) return fmt.Errorf("%s: %w", name, errMissingOutputFromConfig)
} }
// ignore types evalutating to nil // ignore types evalutating to nil
@ -134,7 +134,7 @@ func (s spec) checkOutput(fnv reflect.Value) error {
} }
if !field.Type.ConvertibleTo(ptype) { 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)
} }
} }

View File

@ -25,7 +25,7 @@ func TestInputCheck(t *testing.T) {
{ {
Input: map[string]reflect.Type{}, Input: map[string]reflect.Type{},
Fn: func(int, string) {}, Fn: func(int, string) {},
Err: ErrUnexpectedInput, Err: errUnexpectedInput,
}, },
// missing input struct in func // missing input struct in func
{ {
@ -33,7 +33,7 @@ func TestInputCheck(t *testing.T) {
"Test1": reflect.TypeOf(int(0)), "Test1": reflect.TypeOf(int(0)),
}, },
Fn: func() {}, Fn: func() {},
Err: ErrMissingHandlerArgumentParam, Err: errMissingHandlerArgumentParam,
}, },
// input not a struct // input not a struct
{ {
@ -41,7 +41,7 @@ func TestInputCheck(t *testing.T) {
"Test1": reflect.TypeOf(int(0)), "Test1": reflect.TypeOf(int(0)),
}, },
Fn: func(int) {}, Fn: func(int) {},
Err: ErrMissingParamArgument, Err: errMissingParamArgument,
}, },
// unexported param name // unexported param name
{ {
@ -49,7 +49,7 @@ func TestInputCheck(t *testing.T) {
"test1": reflect.TypeOf(int(0)), "test1": reflect.TypeOf(int(0)),
}, },
Fn: func(struct{}) {}, Fn: func(struct{}) {},
Err: ErrUnexportedName, Err: errUnexportedName,
}, },
// input field missing // input field missing
{ {
@ -57,7 +57,7 @@ func TestInputCheck(t *testing.T) {
"Test1": reflect.TypeOf(int(0)), "Test1": reflect.TypeOf(int(0)),
}, },
Fn: func(struct{}) {}, Fn: func(struct{}) {},
Err: ErrMissingParamFromConfig, Err: errMissingParamFromConfig,
}, },
// input field invalid type // input field invalid type
{ {
@ -65,7 +65,7 @@ func TestInputCheck(t *testing.T) {
"Test1": reflect.TypeOf(int(0)), "Test1": reflect.TypeOf(int(0)),
}, },
Fn: func(struct{ Test1 string }) {}, Fn: func(struct{ Test1 string }) {},
Err: ErrWrongParamTypeFromConfig, Err: errWrongParamTypeFromConfig,
}, },
// input field valid type // input field valid type
{ {
@ -115,13 +115,13 @@ func TestOutputCheck(t *testing.T) {
{ {
Output: map[string]reflect.Type{}, Output: map[string]reflect.Type{},
Fn: func() {}, Fn: func() {},
Err: ErrMissingHandlerOutput, Err: errMissingHandlerOutput,
}, },
// no input -> with last type not api.Error // no input -> with last type not api.Error
{ {
Output: map[string]reflect.Type{}, Output: map[string]reflect.Type{},
Fn: func() bool { return true }, Fn: func() bool { return true },
Err: ErrMissingHandlerErrorOutput, Err: errMissingHandlerErrorOutput,
}, },
// no input -> with api.Error // no input -> with api.Error
{ {
@ -141,7 +141,7 @@ func TestOutputCheck(t *testing.T) {
"Test1": reflect.TypeOf(int(0)), "Test1": reflect.TypeOf(int(0)),
}, },
Fn: func() api.Error { return api.ErrorSuccess }, Fn: func() api.Error { return api.ErrorSuccess },
Err: ErrMissingParamOutput, Err: errMissingParamOutput,
}, },
// output not a pointer // output not a pointer
{ {
@ -149,7 +149,7 @@ func TestOutputCheck(t *testing.T) {
"Test1": reflect.TypeOf(int(0)), "Test1": reflect.TypeOf(int(0)),
}, },
Fn: func() (int, api.Error) { return 0, api.ErrorSuccess }, Fn: func() (int, api.Error) { return 0, api.ErrorSuccess },
Err: ErrMissingParamOutput, Err: errMissingParamOutput,
}, },
// output not a pointer to struct // output not a pointer to struct
{ {
@ -157,7 +157,7 @@ func TestOutputCheck(t *testing.T) {
"Test1": reflect.TypeOf(int(0)), "Test1": reflect.TypeOf(int(0)),
}, },
Fn: func() (*int, api.Error) { return nil, api.ErrorSuccess }, Fn: func() (*int, api.Error) { return nil, api.ErrorSuccess },
Err: ErrMissingParamOutput, Err: errMissingParamOutput,
}, },
// unexported param name // unexported param name
{ {
@ -165,7 +165,7 @@ func TestOutputCheck(t *testing.T) {
"test1": reflect.TypeOf(int(0)), "test1": reflect.TypeOf(int(0)),
}, },
Fn: func() (*struct{}, api.Error) { return nil, api.ErrorSuccess }, Fn: func() (*struct{}, api.Error) { return nil, api.ErrorSuccess },
Err: ErrUnexportedName, Err: errUnexportedName,
}, },
// output field missing // output field missing
{ {
@ -173,7 +173,7 @@ func TestOutputCheck(t *testing.T) {
"Test1": reflect.TypeOf(int(0)), "Test1": reflect.TypeOf(int(0)),
}, },
Fn: func() (*struct{}, api.Error) { return nil, api.ErrorSuccess }, Fn: func() (*struct{}, api.Error) { return nil, api.ErrorSuccess },
Err: ErrMissingParamFromConfig, Err: errMissingParamFromConfig,
}, },
// output field invalid type // output field invalid type
{ {
@ -181,7 +181,7 @@ func TestOutputCheck(t *testing.T) {
"Test1": reflect.TypeOf(int(0)), "Test1": reflect.TypeOf(int(0)),
}, },
Fn: func() (*struct{ Test1 string }, api.Error) { return nil, api.ErrorSuccess }, Fn: func() (*struct{ Test1 string }, api.Error) { return nil, api.ErrorSuccess },
Err: ErrWrongParamTypeFromConfig, Err: errWrongParamTypeFromConfig,
}, },
// output field valid type // output field valid type
{ {