diff --git a/check_required.go b/check_required.go index 9de4f7d..4d5cac8 100644 --- a/check_required.go +++ b/check_required.go @@ -2,9 +2,16 @@ package checker import "reflect" +// ResultRequired indicates that the required value is missing. const ResultRequired Result = "REQUIRED" -func checkRequired(value reflect.Value) Result { +// makeRequired makes a checker function for required. +func makeRequired(_ string) CheckFunc { + return checkRequired +} + +// checkRequired checks if the required value is provided. +func checkRequired(value, _ reflect.Value) Result { if value.IsZero() { return ResultRequired } diff --git a/check_required_test.go b/check_required_test.go index d7ddaa0..82ae55a 100644 --- a/check_required_test.go +++ b/check_required_test.go @@ -8,7 +8,7 @@ import ( func TestCheckRequiredValidString(t *testing.T) { s := "valid" - if checkRequired(reflect.ValueOf(s)) != ResultValid { + if checkRequired(reflect.ValueOf(s), reflect.ValueOf(nil)) != ResultValid { t.Fail() } } @@ -16,7 +16,7 @@ func TestCheckRequiredValidString(t *testing.T) { func TestCheckRequiredUninitializedString(t *testing.T) { var s string - if checkRequired(reflect.ValueOf(s)) != ResultRequired { + if checkRequired(reflect.ValueOf(s), reflect.ValueOf(nil)) != ResultRequired { t.Fail() } } @@ -24,7 +24,7 @@ func TestCheckRequiredUninitializedString(t *testing.T) { func TestCheckRequiredEmptyString(t *testing.T) { s := "" - if checkRequired(reflect.ValueOf(s)) != ResultRequired { + if checkRequired(reflect.ValueOf(s), reflect.ValueOf(nil)) != ResultRequired { t.Fail() } } @@ -32,7 +32,7 @@ func TestCheckRequiredEmptyString(t *testing.T) { func TestCheckRequiredUninitializedNumber(t *testing.T) { var n int - if checkRequired(reflect.ValueOf(n)) != ResultRequired { + if checkRequired(reflect.ValueOf(n), reflect.ValueOf(nil)) != ResultRequired { t.Fail() } } @@ -40,7 +40,7 @@ func TestCheckRequiredUninitializedNumber(t *testing.T) { func TestCheckRequiredValidSlice(t *testing.T) { s := []int{1} - if checkRequired(reflect.ValueOf(s)) != ResultValid { + if checkRequired(reflect.ValueOf(s), reflect.ValueOf(nil)) != ResultValid { t.Fail() } } @@ -48,7 +48,7 @@ func TestCheckRequiredValidSlice(t *testing.T) { func TestCheckRequiredUninitializedSlice(t *testing.T) { var s []int - if checkRequired(reflect.ValueOf(s)) != ResultRequired { + if checkRequired(reflect.ValueOf(s), reflect.ValueOf(nil)) != ResultRequired { t.Fail() } } @@ -56,7 +56,7 @@ func TestCheckRequiredUninitializedSlice(t *testing.T) { func TestCheckRequiredEmptySlice(t *testing.T) { s := make([]int, 0) - if checkRequired(reflect.ValueOf(s)) != ResultRequired { + if checkRequired(reflect.ValueOf(s), reflect.ValueOf(nil)) != ResultRequired { t.Fail() } } @@ -64,7 +64,7 @@ func TestCheckRequiredEmptySlice(t *testing.T) { func TestCheckRequiredValidArray(t *testing.T) { s := [1]int{1} - if checkRequired(reflect.ValueOf(s)) != ResultValid { + if checkRequired(reflect.ValueOf(s), reflect.ValueOf(nil)) != ResultValid { t.Fail() } } @@ -72,7 +72,7 @@ func TestCheckRequiredValidArray(t *testing.T) { func TestCheckRequiredEmptyArray(t *testing.T) { s := [1]int{} - if checkRequired(reflect.ValueOf(s)) != ResultRequired { + if checkRequired(reflect.ValueOf(s), reflect.ValueOf(nil)) != ResultRequired { t.Fail() } } @@ -82,7 +82,7 @@ func TestCheckRequiredValidMap(t *testing.T) { "a": "b", } - if checkRequired(reflect.ValueOf(m)) != ResultValid { + if checkRequired(reflect.ValueOf(m), reflect.ValueOf(nil)) != ResultValid { t.Fail() } } @@ -90,7 +90,7 @@ func TestCheckRequiredValidMap(t *testing.T) { func TestCheckRequiredUninitializedMap(t *testing.T) { var m map[string]string - if checkRequired(reflect.ValueOf(m)) != ResultRequired { + if checkRequired(reflect.ValueOf(m), reflect.ValueOf(nil)) != ResultRequired { t.Fail() } } @@ -98,7 +98,17 @@ func TestCheckRequiredUninitializedMap(t *testing.T) { func TestCheckRequiredEmptyMap(t *testing.T) { m := map[string]string{} - if checkRequired(reflect.ValueOf(m)) != ResultRequired { + if checkRequired(reflect.ValueOf(m), reflect.ValueOf(nil)) != ResultRequired { + t.Fail() + } +} + +func TestMakeRequired(t *testing.T) { + check := makeRequired("") + + s := "valid" + + if check(reflect.ValueOf(s), reflect.ValueOf(nil)) != ResultValid { t.Fail() } } diff --git a/checker.go b/checker.go index bada92d..1b21025 100644 --- a/checker.go +++ b/checker.go @@ -1,14 +1,55 @@ // Package checker is a Go library for validating user input through struct tags. package checker +import ( + "fmt" + "reflect" + "strings" +) + // Result is a unique textual identifier for the mistake. type Result string -// ResultValid result indicates that the user input is valid. -const ResultValid Result = "VALID" +// CheckFunc defines the checker function. +type CheckFunc func(value, parent reflect.Value) Result + +// MakeFunc defines the maker function. +type MakeFunc func(params string) CheckFunc // Mistake provides the field where the mistake was made and a result for the mistake. type Mistake struct { Field string Result Result } + +// ResultValid result indicates that the user input is valid. +const ResultValid Result = "VALID" + +// makers provdes mapping to maker function for the checkers. +var makers = map[string]MakeFunc{ + "required": makeRequired, +} + +// Register registers the given checker name and the maker function. +func Register(name string, maker MakeFunc) { + makers[name] = maker +} + +// initCheckers initializes the checkers provided in the config. +func initCheckers(config string) []CheckFunc { + fields := strings.Fields(config) + checkers := make([]CheckFunc, len(fields)) + + for i, field := range fields { + name, params, _ := strings.Cut(field, ":") + + maker, ok := makers[name] + if !ok { + panic(fmt.Sprintf("checker %s is unkown", name)) + } + + checkers[i] = maker(params) + } + + return checkers +} diff --git a/checker_test.go b/checker_test.go new file mode 100644 index 0000000..f5974d1 --- /dev/null +++ b/checker_test.go @@ -0,0 +1,52 @@ +package checker + +import ( + "reflect" + "testing" +) + +func TestInitCheckersUnknown(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Fail() + } + }() + + initCheckers("unknown") +} + +func TestInitCheckersKnwon(t *testing.T) { + checkers := initCheckers("required") + + if len(checkers) != 1 { + t.Fail() + } + + if reflect.ValueOf(checkers[0]).Pointer() != reflect.ValueOf(checkRequired).Pointer() { + t.Fail() + } +} + +func TestRegister(t *testing.T) { + var checker CheckFunc = func(_, _ reflect.Value) Result { + return ResultValid + } + + var maker MakeFunc = func(_ string) CheckFunc { + return checker + } + + name := "test" + + Register(name, maker) + + checkers := initCheckers(name) + + if len(checkers) != 1 { + t.Fail() + } + + if reflect.ValueOf(checkers[0]).Pointer() != reflect.ValueOf(checker).Pointer() { + t.Fail() + } +}