refactor-test #15
|
@ -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")
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue