aicra/internal/dynfunc/spec_test.go

398 lines
9.5 KiB
Go
Raw Normal View History

package dynfunc
2020-03-29 17:14:12 +00:00
import (
"errors"
2020-03-29 17:23:13 +00:00
"fmt"
2020-03-29 17:14:12 +00:00
"reflect"
"testing"
2020-03-29 17:23:13 +00:00
"git.xdrm.io/go/aicra/api"
2020-03-29 17:14:12 +00:00
)
func TestInputCheck(t *testing.T) {
tcases := []struct {
2021-04-18 16:26:37 +00:00
Name string
2020-03-29 17:14:12 +00:00
Input map[string]reflect.Type
Fn interface{}
FnCtx interface{}
2020-03-29 17:14:12 +00:00
Err error
}{
{
2021-04-18 16:26:37 +00:00
Name: "no input 0 given",
2020-03-29 17:14:12 +00:00
Input: map[string]reflect.Type{},
Fn: func() {},
FnCtx: func(api.Ctx) {},
2020-03-29 17:14:12 +00:00
Err: nil,
},
{
2021-04-18 16:26:37 +00:00
Name: "no input 1 given",
Input: map[string]reflect.Type{},
Fn: func(int) {},
FnCtx: func(api.Ctx, int) {},
2021-04-18 16:26:37 +00:00
Err: errUnexpectedInput,
},
{
Name: "no input 2 given",
2020-03-29 17:14:12 +00:00
Input: map[string]reflect.Type{},
Fn: func(int, string) {},
FnCtx: func(api.Ctx, int, string) {},
2020-04-04 10:46:43 +00:00
Err: errUnexpectedInput,
2020-03-29 17:14:12 +00:00
},
{
2021-04-18 16:26:37 +00:00
Name: "1 input 0 given",
2020-03-29 17:14:12 +00:00
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(int(0)),
},
Fn: func() {},
FnCtx: func(api.Ctx) {},
Err: errMissingHandlerArgumentParam,
2020-03-29 17:14:12 +00:00
},
{
2021-04-18 16:26:37 +00:00
Name: "1 input non-struct given",
2020-03-29 17:14:12 +00:00
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(int(0)),
},
Fn: func(int) {},
FnCtx: func(api.Ctx, int) {},
Err: errMissingParamArgument,
2020-03-29 17:14:12 +00:00
},
{
2021-04-18 16:26:37 +00:00
Name: "unexported input",
2020-03-29 17:14:12 +00:00
Input: map[string]reflect.Type{
"test1": reflect.TypeOf(int(0)),
},
Fn: func(struct{}) {},
FnCtx: func(api.Ctx, struct{}) {},
Err: errUnexportedName,
2020-03-29 17:14:12 +00:00
},
{
2021-04-18 16:26:37 +00:00
Name: "1 input empty struct given",
2020-03-29 17:14:12 +00:00
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(int(0)),
},
Fn: func(struct{}) {},
FnCtx: func(api.Ctx, struct{}) {},
Err: errMissingParamFromConfig,
2020-03-29 17:14:12 +00:00
},
{
2021-04-18 16:26:37 +00:00
Name: "1 input invalid given",
2020-03-29 17:14:12 +00:00
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(int(0)),
},
Fn: func(struct{ Test1 string }) {},
FnCtx: func(api.Ctx, struct{ Test1 string }) {},
Err: errWrongParamTypeFromConfig,
2020-03-29 17:14:12 +00:00
},
{
2021-04-18 16:26:37 +00:00
Name: "1 input valid given",
2020-03-29 17:14:12 +00:00
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(int(0)),
},
Fn: func(struct{ Test1 int }) {},
FnCtx: func(api.Ctx, struct{ Test1 int }) {},
Err: nil,
2020-03-29 17:14:12 +00:00
},
2021-04-18 16:26:37 +00:00
{
Name: "1 input ptr empty struct given",
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(new(int)),
},
Fn: func(struct{}) {},
FnCtx: func(api.Ctx, struct{}) {},
Err: errMissingParamFromConfig,
2021-04-18 16:26:37 +00:00
},
{
Name: "1 input ptr invalid given",
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(new(int)),
},
Fn: func(struct{ Test1 string }) {},
FnCtx: func(api.Ctx, struct{ Test1 string }) {},
Err: errWrongParamTypeFromConfig,
2021-04-18 16:26:37 +00:00
},
{
Name: "1 input ptr invalid ptr type given",
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(new(int)),
},
Fn: func(struct{ Test1 *string }) {},
FnCtx: func(api.Ctx, struct{ Test1 *string }) {},
Err: errWrongParamTypeFromConfig,
2021-04-18 16:26:37 +00:00
},
{
Name: "1 input ptr valid given",
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(new(int)),
},
Fn: func(struct{ Test1 *int }) {},
FnCtx: func(api.Ctx, struct{ Test1 *int }) {},
Err: nil,
2021-04-18 16:26:37 +00:00
},
{
Name: "1 valid string",
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(string("")),
},
Fn: func(struct{ Test1 string }) {},
FnCtx: func(api.Ctx, struct{ Test1 string }) {},
Err: nil,
2021-04-18 16:26:37 +00:00
},
{
Name: "1 valid uint",
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(uint(0)),
},
Fn: func(struct{ Test1 uint }) {},
FnCtx: func(api.Ctx, struct{ Test1 uint }) {},
Err: nil,
2021-04-18 16:26:37 +00:00
},
{
Name: "1 valid float64",
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(float64(0)),
},
Fn: func(struct{ Test1 float64 }) {},
FnCtx: func(api.Ctx, struct{ Test1 float64 }) {},
Err: nil,
2021-04-18 16:26:37 +00:00
},
{
Name: "1 valid []byte",
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf([]byte("")),
},
Fn: func(struct{ Test1 []byte }) {},
FnCtx: func(api.Ctx, struct{ Test1 []byte }) {},
Err: nil,
2021-04-18 16:26:37 +00:00
},
{
Name: "1 valid []rune",
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf([]rune("")),
},
Fn: func(struct{ Test1 []rune }) {},
FnCtx: func(api.Ctx, struct{ Test1 []rune }) {},
Err: nil,
2021-04-18 16:26:37 +00:00
},
{
Name: "1 valid *string",
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(new(string)),
},
Fn: func(struct{ Test1 *string }) {},
FnCtx: func(api.Ctx, struct{ Test1 *string }) {},
Err: nil,
2021-04-18 16:26:37 +00:00
},
{
Name: "1 valid *uint",
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(new(uint)),
},
Fn: func(struct{ Test1 *uint }) {},
FnCtx: func(api.Ctx, struct{ Test1 *uint }) {},
Err: nil,
2021-04-18 16:26:37 +00:00
},
{
Name: "1 valid *float64",
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(new(float64)),
},
Fn: func(struct{ Test1 *float64 }) {},
FnCtx: func(api.Ctx, struct{ Test1 *float64 }) {},
Err: nil,
2021-04-18 16:26:37 +00:00
},
{
Name: "1 valid *[]byte",
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(new([]byte)),
},
Fn: func(struct{ Test1 *[]byte }) {},
FnCtx: func(api.Ctx, struct{ Test1 *[]byte }) {},
Err: nil,
2021-04-18 16:26:37 +00:00
},
{
Name: "1 valid *[]rune",
Input: map[string]reflect.Type{
"Test1": reflect.TypeOf(new([]rune)),
},
Fn: func(struct{ Test1 *[]rune }) {},
FnCtx: func(api.Ctx, struct{ Test1 *[]rune }) {},
Err: nil,
2021-04-18 16:26:37 +00:00
},
2020-03-29 17:14:12 +00:00
}
2021-04-18 16:26:37 +00:00
for _, tcase := range tcases {
t.Run(tcase.Name, func(t *testing.T) {
t.Parallel()
2020-03-29 17:14:12 +00:00
// mock spec
s := spec{
Input: tcase.Input,
Output: nil,
}
t.Run("with-context", func(t *testing.T) {
err := s.checkInput(reflect.TypeOf(tcase.FnCtx), 1)
if err == nil && tcase.Err != nil {
t.Errorf("expected an error: '%s'", tcase.Err.Error())
t.FailNow()
}
if err != nil && tcase.Err == nil {
t.Errorf("unexpected error: '%s'", err.Error())
t.FailNow()
}
2020-03-29 17:14:12 +00:00
if err != nil && tcase.Err != nil {
if !errors.Is(err, tcase.Err) {
t.Errorf("expected the error <%s> got <%s>", tcase.Err, err)
t.FailNow()
}
}
})
t.Run("without-context", func(t *testing.T) {
err := s.checkInput(reflect.TypeOf(tcase.Fn), 0)
if err == nil && tcase.Err != nil {
t.Errorf("expected an error: '%s'", tcase.Err.Error())
2020-03-29 17:14:12 +00:00
t.FailNow()
}
if err != nil && tcase.Err == nil {
t.Errorf("unexpected error: '%s'", err.Error())
t.FailNow()
}
if err != nil && tcase.Err != nil {
if !errors.Is(err, tcase.Err) {
t.Errorf("expected the error <%s> got <%s>", tcase.Err, err)
t.FailNow()
}
}
})
2020-03-29 17:14:12 +00:00
})
}
}
2020-03-29 17:23:13 +00:00
func TestOutputCheck(t *testing.T) {
tcases := []struct {
Output map[string]reflect.Type
Fn interface{}
Err error
}{
// no input -> missing api.Err
2020-03-29 17:23:13 +00:00
{
Output: map[string]reflect.Type{},
Fn: func() {},
2020-04-04 10:46:43 +00:00
Err: errMissingHandlerOutput,
2020-03-29 17:23:13 +00:00
},
// no input -> with last type not api.Err
{
Output: map[string]reflect.Type{},
Fn: func() bool { return true },
2020-04-04 10:46:43 +00:00
Err: errMissingHandlerErrorOutput,
},
// no input -> with api.Err
2020-03-29 17:23:13 +00:00
{
Output: map[string]reflect.Type{},
Fn: func() api.Err { return api.ErrSuccess },
2020-03-29 17:23:13 +00:00
Err: nil,
},
// func can have output if not specified
{
Output: map[string]reflect.Type{},
Fn: func() (*struct{}, api.Err) { return nil, api.ErrSuccess },
2020-03-29 17:23:13 +00:00
Err: nil,
},
// missing output struct in func
{
Output: map[string]reflect.Type{
"Test1": reflect.TypeOf(int(0)),
},
Fn: func() api.Err { return api.ErrSuccess },
2020-04-04 10:46:43 +00:00
Err: errMissingParamOutput,
2020-03-29 17:23:13 +00:00
},
// output not a pointer
{
Output: map[string]reflect.Type{
"Test1": reflect.TypeOf(int(0)),
},
Fn: func() (int, api.Err) { return 0, api.ErrSuccess },
2020-04-04 10:46:43 +00:00
Err: errMissingParamOutput,
2020-03-29 17:23:13 +00:00
},
// output not a pointer to struct
{
Output: map[string]reflect.Type{
"Test1": reflect.TypeOf(int(0)),
},
Fn: func() (*int, api.Err) { return nil, api.ErrSuccess },
2020-04-04 10:46:43 +00:00
Err: errMissingParamOutput,
2020-03-29 17:23:13 +00:00
},
// unexported param name
{
Output: map[string]reflect.Type{
"test1": reflect.TypeOf(int(0)),
},
Fn: func() (*struct{}, api.Err) { return nil, api.ErrSuccess },
2020-04-04 10:46:43 +00:00
Err: errUnexportedName,
2020-03-29 17:23:13 +00:00
},
// output field missing
{
Output: map[string]reflect.Type{
"Test1": reflect.TypeOf(int(0)),
},
Fn: func() (*struct{}, api.Err) { return nil, api.ErrSuccess },
2020-04-04 10:46:43 +00:00
Err: errMissingParamFromConfig,
2020-03-29 17:23:13 +00:00
},
// output field invalid type
{
Output: map[string]reflect.Type{
"Test1": reflect.TypeOf(int(0)),
},
Fn: func() (*struct{ Test1 string }, api.Err) { return nil, api.ErrSuccess },
2020-04-04 10:46:43 +00:00
Err: errWrongParamTypeFromConfig,
2020-03-29 17:23:13 +00:00
},
// output field valid type
{
Output: map[string]reflect.Type{
"Test1": reflect.TypeOf(int(0)),
},
Fn: func() (*struct{ Test1 int }, api.Err) { return nil, api.ErrSuccess },
2020-03-29 17:23:13 +00:00
Err: nil,
},
// ignore type check on nil type
{
Output: map[string]reflect.Type{
"Test1": nil,
},
Fn: func() (*struct{ Test1 int }, api.Err) { return nil, api.ErrSuccess },
Err: nil,
},
2020-03-29 17:23:13 +00:00
}
for i, tcase := range tcases {
t.Run(fmt.Sprintf("case.%d", i), func(t *testing.T) {
t.Parallel()
2020-03-29 17:23:13 +00:00
// mock spec
s := spec{
Input: nil,
Output: tcase.Output,
}
err := s.checkOutput(reflect.TypeOf(tcase.Fn))
2020-03-29 17:23:13 +00:00
if err == nil && tcase.Err != nil {
t.Errorf("expected an error: '%s'", tcase.Err.Error())
t.FailNow()
}
if err != nil && tcase.Err == nil {
t.Errorf("unexpected error: '%s'", err.Error())
t.FailNow()
}
if err != nil && tcase.Err != nil {
if !errors.Is(err, tcase.Err) {
t.Errorf("expected the error <%s> got <%s>", tcase.Err, err)
t.FailNow()
}
}
})
}
}