migrate typecheck.builtin into config.datatype.builtin
This commit is contained in:
parent
003fe4d2e7
commit
e12c52b88f
|
@ -0,0 +1,17 @@
|
|||
package builtin
|
||||
|
||||
import "git.xdrm.io/go/aicra/config/datatype"
|
||||
|
||||
// AnyDataType is what its name tells
|
||||
type AnyDataType struct{}
|
||||
|
||||
// Build returns the validator
|
||||
func (AnyDataType) Build(typeName string) datatype.Validator {
|
||||
// nothing if type not handled
|
||||
if typeName != "any" {
|
||||
return nil
|
||||
}
|
||||
return func(value interface{}) (interface{}, bool) {
|
||||
return value, true
|
||||
}
|
||||
}
|
|
@ -4,26 +4,13 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.xdrm.io/go/aicra/typecheck/builtin"
|
||||
"git.xdrm.io/go/aicra/config/datatype/builtin"
|
||||
)
|
||||
|
||||
func TestAny_New(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
inst := interface{}(builtin.NewAny())
|
||||
|
||||
switch cast := inst.(type) {
|
||||
case *builtin.Any:
|
||||
return
|
||||
default:
|
||||
t.Errorf("expect %T ; got %T", &builtin.Any{}, cast)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAny_AvailableTypes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
inst := builtin.NewAny()
|
||||
dt := builtin.AnyDataType{}
|
||||
|
||||
tests := []struct {
|
||||
Type string
|
||||
|
@ -39,9 +26,9 @@ func TestAny_AvailableTypes(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range tests {
|
||||
checker := inst.Checker(test.Type)
|
||||
validator := dt.Build(test.Type)
|
||||
|
||||
if checker == nil {
|
||||
if validator == nil {
|
||||
if test.Handled {
|
||||
t.Errorf("expect %q to be handled", test.Type)
|
||||
}
|
||||
|
@ -60,8 +47,8 @@ func TestAny_AlwaysTrue(t *testing.T) {
|
|||
|
||||
const typeName = "any"
|
||||
|
||||
checker := builtin.NewAny().Checker(typeName)
|
||||
if checker == nil {
|
||||
validator := builtin.AnyDataType{}.Build(typeName)
|
||||
if validator == nil {
|
||||
t.Errorf("expect %q to be handled", typeName)
|
||||
t.Fail()
|
||||
}
|
||||
|
@ -76,7 +63,7 @@ func TestAny_AlwaysTrue(t *testing.T) {
|
|||
|
||||
for i, value := range values {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
if !checker(value) {
|
||||
if _, isValid := validator(value); !isValid {
|
||||
t.Errorf("expect value to be valid")
|
||||
t.Fail()
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package builtin
|
||||
|
||||
import "git.xdrm.io/go/aicra/config/datatype"
|
||||
|
||||
// BoolDataType is what its name tells
|
||||
type BoolDataType struct{}
|
||||
|
||||
// Build returns the validator
|
||||
func (BoolDataType) Build(typeName string) datatype.Validator {
|
||||
// nothing if type not handled
|
||||
if typeName != "bool" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return func(value interface{}) (interface{}, bool) {
|
||||
switch cast := value.(type) {
|
||||
case bool:
|
||||
return cast, true
|
||||
|
||||
case string:
|
||||
strVal := string(cast)
|
||||
return strVal == "true", strVal == "true" || strVal == "false"
|
||||
case []byte:
|
||||
strVal := string(cast)
|
||||
return strVal == "true", strVal == "true" || strVal == "false"
|
||||
|
||||
default:
|
||||
return false, false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,26 +4,13 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.xdrm.io/go/aicra/typecheck/builtin"
|
||||
"git.xdrm.io/go/aicra/config/datatype/builtin"
|
||||
)
|
||||
|
||||
func TestBool_New(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
inst := interface{}(builtin.NewBool())
|
||||
|
||||
switch cast := inst.(type) {
|
||||
case *builtin.Bool:
|
||||
return
|
||||
default:
|
||||
t.Errorf("expect %T ; got %T", &builtin.Bool{}, cast)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBool_AvailableTypes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
inst := builtin.NewBool()
|
||||
dt := builtin.BoolDataType{}
|
||||
|
||||
tests := []struct {
|
||||
Type string
|
||||
|
@ -39,8 +26,8 @@ func TestBool_AvailableTypes(t *testing.T) {
|
|||
|
||||
for _, test := range tests {
|
||||
t.Run(test.Type, func(t *testing.T) {
|
||||
checker := inst.Checker(test.Type)
|
||||
if checker == nil {
|
||||
validator := dt.Build(test.Type)
|
||||
if validator == nil {
|
||||
if test.Handled {
|
||||
t.Errorf("expect %q to be handled", test.Type)
|
||||
t.Fail()
|
||||
|
@ -62,8 +49,8 @@ func TestBool_Values(t *testing.T) {
|
|||
|
||||
const typeName = "bool"
|
||||
|
||||
checker := builtin.NewBool().Checker(typeName)
|
||||
if checker == nil {
|
||||
validator := builtin.BoolDataType{}.Build(typeName)
|
||||
if validator == nil {
|
||||
t.Errorf("expect %q to be handled", typeName)
|
||||
t.Fail()
|
||||
}
|
||||
|
@ -98,7 +85,7 @@ func TestBool_Values(t *testing.T) {
|
|||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
if checker(test.Value) {
|
||||
if _, isValid := validator(test.Value); isValid {
|
||||
if !test.Valid {
|
||||
t.Errorf("expect value to be invalid")
|
||||
t.Fail()
|
|
@ -0,0 +1,47 @@
|
|||
package builtin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"git.xdrm.io/go/aicra/config/datatype"
|
||||
)
|
||||
|
||||
// FloatDataType is what its name tells
|
||||
type FloatDataType struct{}
|
||||
|
||||
// Build returns the validator
|
||||
func (FloatDataType) Build(typeName string) datatype.Validator {
|
||||
// nothing if type not handled
|
||||
if typeName != "float64" && typeName != "float" {
|
||||
return nil
|
||||
}
|
||||
return func(value interface{}) (interface{}, bool) {
|
||||
switch cast := value.(type) {
|
||||
|
||||
case int:
|
||||
return float64(cast), true
|
||||
|
||||
case uint:
|
||||
return float64(cast), true
|
||||
|
||||
case float64:
|
||||
return cast, true
|
||||
|
||||
// serialized string -> try to convert to float
|
||||
case []byte:
|
||||
num := json.Number(cast)
|
||||
floatVal, err := num.Float64()
|
||||
return floatVal, err == nil
|
||||
|
||||
case string:
|
||||
num := json.Number(cast)
|
||||
floatVal, err := num.Float64()
|
||||
return floatVal, err == nil
|
||||
|
||||
// unknown type
|
||||
default:
|
||||
return 0, false
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,26 +5,13 @@ import (
|
|||
"math"
|
||||
"testing"
|
||||
|
||||
"git.xdrm.io/go/aicra/typecheck/builtin"
|
||||
"git.xdrm.io/go/aicra/config/datatype/builtin"
|
||||
)
|
||||
|
||||
func TestFloat64_New(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
inst := interface{}(builtin.NewFloat64())
|
||||
|
||||
switch cast := inst.(type) {
|
||||
case *builtin.Float64:
|
||||
return
|
||||
default:
|
||||
t.Errorf("expect %T ; got %T", &builtin.Float64{}, cast)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat64_AvailableTypes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
inst := builtin.NewFloat64()
|
||||
dt := builtin.FloatDataType{}
|
||||
|
||||
tests := []struct {
|
||||
Type string
|
||||
|
@ -46,8 +33,8 @@ func TestFloat64_AvailableTypes(t *testing.T) {
|
|||
|
||||
for _, test := range tests {
|
||||
t.Run(test.Type, func(t *testing.T) {
|
||||
checker := inst.Checker(test.Type)
|
||||
if checker == nil {
|
||||
validator := dt.Build(test.Type)
|
||||
if validator == nil {
|
||||
if test.Handled {
|
||||
t.Errorf("expect %q to be handled", test.Type)
|
||||
t.Fail()
|
||||
|
@ -69,8 +56,8 @@ func TestFloat64_Values(t *testing.T) {
|
|||
|
||||
const typeName = "float"
|
||||
|
||||
checker := builtin.NewFloat64().Checker(typeName)
|
||||
if checker == nil {
|
||||
validator := builtin.FloatDataType{}.Build(typeName)
|
||||
if validator == nil {
|
||||
t.Errorf("expect %q to be handled", typeName)
|
||||
t.Fail()
|
||||
}
|
||||
|
@ -110,7 +97,7 @@ func TestFloat64_Values(t *testing.T) {
|
|||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
if checker(test.Value) {
|
||||
if _, isValid := validator(test.Value); isValid {
|
||||
if !test.Valid {
|
||||
t.Errorf("expect value to be invalid")
|
||||
t.Fail()
|
|
@ -0,0 +1,52 @@
|
|||
package builtin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
|
||||
"git.xdrm.io/go/aicra/config/datatype"
|
||||
)
|
||||
|
||||
// IntDataType is what its name tells
|
||||
type IntDataType struct{}
|
||||
|
||||
// Build returns the validator
|
||||
func (IntDataType) Build(typeName string) datatype.Validator {
|
||||
// nothing if type not handled
|
||||
if typeName != "int" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return func(value interface{}) (interface{}, bool) {
|
||||
switch cast := value.(type) {
|
||||
|
||||
case int:
|
||||
return cast, true
|
||||
|
||||
case uint:
|
||||
overflows := cast > math.MaxInt64
|
||||
return int(cast), !overflows
|
||||
|
||||
case float64:
|
||||
intVal := int(cast)
|
||||
overflows := cast < float64(math.MinInt64) || cast > float64(math.MaxInt64)
|
||||
return intVal, cast == float64(intVal) && !overflows
|
||||
|
||||
// serialized string -> try to convert to float
|
||||
case string:
|
||||
num := json.Number(cast)
|
||||
intVal, err := num.Int64()
|
||||
return int(intVal), err == nil
|
||||
// serialized string -> try to convert to float
|
||||
|
||||
case []byte:
|
||||
num := json.Number(cast)
|
||||
intVal, err := num.Int64()
|
||||
return int(intVal), err == nil
|
||||
|
||||
// unknown type
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,26 +5,13 @@ import (
|
|||
"math"
|
||||
"testing"
|
||||
|
||||
"git.xdrm.io/go/aicra/typecheck/builtin"
|
||||
"git.xdrm.io/go/aicra/config/datatype/builtin"
|
||||
)
|
||||
|
||||
func TestInt_New(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
inst := interface{}(builtin.NewInt())
|
||||
|
||||
switch cast := inst.(type) {
|
||||
case *builtin.Int:
|
||||
return
|
||||
default:
|
||||
t.Errorf("expect %T ; got %T", &builtin.Int{}, cast)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt_AvailableTypes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
inst := builtin.NewInt()
|
||||
dt := builtin.IntDataType{}
|
||||
|
||||
tests := []struct {
|
||||
Type string
|
||||
|
@ -40,8 +27,8 @@ func TestInt_AvailableTypes(t *testing.T) {
|
|||
|
||||
for _, test := range tests {
|
||||
t.Run(test.Type, func(t *testing.T) {
|
||||
checker := inst.Checker(test.Type)
|
||||
if checker == nil {
|
||||
validator := dt.Build(test.Type)
|
||||
if validator == nil {
|
||||
if test.Handled {
|
||||
t.Errorf("expect %q to be handled", test.Type)
|
||||
t.Fail()
|
||||
|
@ -63,8 +50,8 @@ func TestInt_Values(t *testing.T) {
|
|||
|
||||
const typeName = "int"
|
||||
|
||||
checker := builtin.NewInt().Checker(typeName)
|
||||
if checker == nil {
|
||||
validator := builtin.IntDataType{}.Build(typeName)
|
||||
if validator == nil {
|
||||
t.Errorf("expect %q to be handled", typeName)
|
||||
t.Fail()
|
||||
}
|
||||
|
@ -110,7 +97,7 @@ func TestInt_Values(t *testing.T) {
|
|||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
if checker(test.Value) {
|
||||
if _, isValid := validator(test.Value); isValid {
|
||||
if !test.Valid {
|
||||
t.Errorf("expect value to be invalid")
|
||||
t.Fail()
|
|
@ -4,28 +4,24 @@ import (
|
|||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"git.xdrm.io/go/aicra/typecheck"
|
||||
"git.xdrm.io/go/aicra/config/datatype"
|
||||
)
|
||||
|
||||
var fixedLengthRegex = regexp.MustCompile(`^string\((\d+)\)$`)
|
||||
var variableLengthRegex = regexp.MustCompile(`^string\((\d+), ?(\d+)\)$`)
|
||||
|
||||
// String checks if a value is a string
|
||||
type String struct{}
|
||||
// StringDataType is what its name tells
|
||||
type StringDataType struct{}
|
||||
|
||||
// NewString returns a bare string type checker
|
||||
func NewString() *String {
|
||||
return &String{}
|
||||
}
|
||||
|
||||
// Checker returns the checker function. Availables type names are : `string`, `string(length)` and `string(minLength, maxLength)`.
|
||||
func (s String) Checker(typeName string) typecheck.CheckerFunc {
|
||||
isSimpleString := typeName == "string"
|
||||
// Build returns the validator.
|
||||
// availables type names are : `string`, `string(length)` and `string(minLength, maxLength)`.
|
||||
func (s StringDataType) Build(typeName string) datatype.Validator {
|
||||
simple := typeName == "string"
|
||||
fixedLengthMatches := fixedLengthRegex.FindStringSubmatch(typeName)
|
||||
variableLengthMatches := variableLengthRegex.FindStringSubmatch(typeName)
|
||||
|
||||
// nothing if type not handled
|
||||
if !isSimpleString && fixedLengthMatches == nil && variableLengthMatches == nil {
|
||||
if !simple && fixedLengthMatches == nil && variableLengthMatches == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -53,10 +49,10 @@ func (s String) Checker(typeName string) typecheck.CheckerFunc {
|
|||
max = exMax
|
||||
}
|
||||
|
||||
return func(value interface{}) bool {
|
||||
return func(value interface{}) (interface{}, bool) {
|
||||
// preprocessing error
|
||||
if mustFail {
|
||||
return false
|
||||
return "", false
|
||||
}
|
||||
|
||||
// check type
|
||||
|
@ -68,21 +64,21 @@ func (s String) Checker(typeName string) typecheck.CheckerFunc {
|
|||
}
|
||||
|
||||
if !isString {
|
||||
return false
|
||||
return "", false
|
||||
}
|
||||
|
||||
if isSimpleString {
|
||||
return true
|
||||
if simple {
|
||||
return strValue, true
|
||||
}
|
||||
|
||||
// check length against previously extracted length
|
||||
l := len(strValue)
|
||||
return l >= min && l <= max
|
||||
return strValue, l >= min && l <= max
|
||||
}
|
||||
}
|
||||
|
||||
// getFixedLength returns the fixed length from regex matches and a success state.
|
||||
func (String) getFixedLength(regexMatches []string) (int, bool) {
|
||||
func (StringDataType) getFixedLength(regexMatches []string) (int, bool) {
|
||||
// incoherence error
|
||||
if regexMatches == nil || len(regexMatches) < 2 {
|
||||
return 0, false
|
||||
|
@ -98,7 +94,7 @@ func (String) getFixedLength(regexMatches []string) (int, bool) {
|
|||
}
|
||||
|
||||
// getVariableLength returns the length min and max from regex matches and a success state.
|
||||
func (String) getVariableLength(regexMatches []string) (int, int, bool) {
|
||||
func (StringDataType) getVariableLength(regexMatches []string) (int, int, bool) {
|
||||
// incoherence error
|
||||
if regexMatches == nil || len(regexMatches) < 3 {
|
||||
return 0, 0, false
|
|
@ -4,26 +4,13 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.xdrm.io/go/aicra/typecheck/builtin"
|
||||
"git.xdrm.io/go/aicra/config/datatype/builtin"
|
||||
)
|
||||
|
||||
func TestString_New(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
inst := interface{}(builtin.NewString())
|
||||
|
||||
switch cast := inst.(type) {
|
||||
case *builtin.String:
|
||||
return
|
||||
default:
|
||||
t.Errorf("expect %T ; got %T", &builtin.String{}, cast)
|
||||
}
|
||||
}
|
||||
|
||||
func TestString_AvailableTypes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
inst := builtin.NewString()
|
||||
dt := builtin.StringDataType{}
|
||||
|
||||
tests := []struct {
|
||||
Type string
|
||||
|
@ -66,9 +53,9 @@ func TestString_AvailableTypes(t *testing.T) {
|
|||
|
||||
for _, test := range tests {
|
||||
t.Run(test.Type, func(t *testing.T) {
|
||||
checker := inst.Checker(test.Type)
|
||||
validator := dt.Build(test.Type)
|
||||
|
||||
if checker == nil {
|
||||
if validator == nil {
|
||||
if test.Handled {
|
||||
t.Errorf("expect %q to be handled", test.Type)
|
||||
}
|
||||
|
@ -88,8 +75,8 @@ func TestString_AnyLength(t *testing.T) {
|
|||
|
||||
const typeName = "string"
|
||||
|
||||
checker := builtin.NewString().Checker(typeName)
|
||||
if checker == nil {
|
||||
validator := builtin.StringDataType{}.Build(typeName)
|
||||
if validator == nil {
|
||||
t.Errorf("expect %q to be handled", typeName)
|
||||
t.Fail()
|
||||
}
|
||||
|
@ -107,7 +94,7 @@ func TestString_AnyLength(t *testing.T) {
|
|||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
if checker(test.Value) {
|
||||
if _, isValid := validator(test.Value); isValid {
|
||||
if !test.Valid {
|
||||
t.Errorf("expect value to be invalid")
|
||||
t.Fail()
|
||||
|
@ -146,14 +133,14 @@ func TestString_FixedLength(t *testing.T) {
|
|||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
checker := builtin.NewString().Checker(test.Type)
|
||||
if checker == nil {
|
||||
validator := builtin.StringDataType{}.Build(test.Type)
|
||||
if validator == nil {
|
||||
t.Errorf("expect %q to be handled", test.Type)
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
if checker(test.Value) {
|
||||
if _, isValid := validator(test.Value); isValid {
|
||||
if !test.Valid {
|
||||
t.Errorf("expect value to be invalid")
|
||||
t.Fail()
|
||||
|
@ -207,14 +194,14 @@ func TestString_VariableLength(t *testing.T) {
|
|||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
checker := builtin.NewString().Checker(test.Type)
|
||||
if checker == nil {
|
||||
validator := builtin.StringDataType{}.Build(test.Type)
|
||||
if validator == nil {
|
||||
t.Errorf("expect %q to be handled", test.Type)
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
if checker(test.Value) {
|
||||
if _, isValid := validator(test.Value); isValid {
|
||||
if !test.Valid {
|
||||
t.Errorf("expect value to be invalid")
|
||||
t.Fail()
|
|
@ -0,0 +1,58 @@
|
|||
package builtin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
|
||||
"git.xdrm.io/go/aicra/config/datatype"
|
||||
)
|
||||
|
||||
// UintDataType is what its name tells
|
||||
type UintDataType struct{}
|
||||
|
||||
// Build returns the validator
|
||||
func (UintDataType) Build(typeName string) datatype.Validator {
|
||||
// nothing if type not handled
|
||||
if typeName != "uint" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return func(value interface{}) (interface{}, bool) {
|
||||
switch cast := value.(type) {
|
||||
|
||||
case int:
|
||||
return uint(cast), cast >= 0
|
||||
|
||||
case uint:
|
||||
return cast, true
|
||||
|
||||
case float64:
|
||||
uintVal := uint(cast)
|
||||
overflows := cast < 0 || cast > math.MaxUint64
|
||||
return uintVal, cast == float64(uintVal) && !overflows
|
||||
|
||||
// serialized string -> try to convert to float
|
||||
case string:
|
||||
num := json.Number(cast)
|
||||
floatVal, err := num.Float64()
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
overflows := floatVal < 0 || floatVal > math.MaxUint64
|
||||
return uint(floatVal), !overflows
|
||||
|
||||
case []byte:
|
||||
num := json.Number(cast)
|
||||
floatVal, err := num.Float64()
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
overflows := floatVal < 0 || floatVal > math.MaxUint64
|
||||
return uint(floatVal), !overflows
|
||||
|
||||
// unknown type
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,26 +5,13 @@ import (
|
|||
"math"
|
||||
"testing"
|
||||
|
||||
"git.xdrm.io/go/aicra/typecheck/builtin"
|
||||
"git.xdrm.io/go/aicra/config/datatype/builtin"
|
||||
)
|
||||
|
||||
func TestUint_New(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
inst := interface{}(builtin.NewUint())
|
||||
|
||||
switch cast := inst.(type) {
|
||||
case *builtin.Uint:
|
||||
return
|
||||
default:
|
||||
t.Errorf("expect %T ; got %T", &builtin.Uint{}, cast)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint_AvailableTypes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
inst := builtin.NewUint()
|
||||
dt := builtin.UintDataType{}
|
||||
|
||||
tests := []struct {
|
||||
Type string
|
||||
|
@ -40,8 +27,8 @@ func TestUint_AvailableTypes(t *testing.T) {
|
|||
|
||||
for _, test := range tests {
|
||||
t.Run(test.Type, func(t *testing.T) {
|
||||
checker := inst.Checker(test.Type)
|
||||
if checker == nil {
|
||||
validator := dt.Build(test.Type)
|
||||
if validator == nil {
|
||||
if test.Handled {
|
||||
t.Errorf("expect %q to be handled", test.Type)
|
||||
t.Fail()
|
||||
|
@ -63,8 +50,8 @@ func TestUint_Values(t *testing.T) {
|
|||
|
||||
const typeName = "uint"
|
||||
|
||||
checker := builtin.NewUint().Checker(typeName)
|
||||
if checker == nil {
|
||||
validator := builtin.UintDataType{}.Build(typeName)
|
||||
if validator == nil {
|
||||
t.Errorf("expect %q to be handled", typeName)
|
||||
t.Fail()
|
||||
}
|
||||
|
@ -110,7 +97,7 @@ func TestUint_Values(t *testing.T) {
|
|||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
if checker(test.Value) {
|
||||
if _, isValid := validator(test.Value); isValid {
|
||||
if !test.Valid {
|
||||
t.Errorf("expect value to be invalid")
|
||||
t.Fail()
|
|
@ -1,22 +0,0 @@
|
|||
package builtin
|
||||
|
||||
import "git.xdrm.io/go/aicra/typecheck"
|
||||
|
||||
// Any is a permissive type checker
|
||||
type Any struct{}
|
||||
|
||||
// NewAny returns a bare any type checker
|
||||
func NewAny() *Any {
|
||||
return &Any{}
|
||||
}
|
||||
|
||||
// Checker returns the checker function
|
||||
func (Any) Checker(typeName string) typecheck.CheckerFunc {
|
||||
// nothing if type not handled
|
||||
if typeName != "any" {
|
||||
return nil
|
||||
}
|
||||
return func(interface{}) bool {
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package builtin
|
||||
|
||||
import "git.xdrm.io/go/aicra/typecheck"
|
||||
|
||||
// Bool checks if a value is a boolean
|
||||
type Bool struct{}
|
||||
|
||||
// NewBool returns a bare boolean type checker
|
||||
func NewBool() *Bool {
|
||||
return &Bool{}
|
||||
}
|
||||
|
||||
// Checker returns the checker function
|
||||
func (Bool) Checker(typeName string) typecheck.CheckerFunc {
|
||||
// nothing if type not handled
|
||||
if typeName != "bool" {
|
||||
return nil
|
||||
}
|
||||
return func(value interface{}) bool {
|
||||
_, isBool := readBool(value)
|
||||
return isBool
|
||||
}
|
||||
}
|
||||
|
||||
// readBool tries to read a serialized boolean and returns whether it succeeded.
|
||||
func readBool(value interface{}) (bool, bool) {
|
||||
switch cast := value.(type) {
|
||||
case bool:
|
||||
return cast, true
|
||||
|
||||
case string:
|
||||
strVal := string(cast)
|
||||
return strVal == "true", strVal == "true" || strVal == "false"
|
||||
|
||||
case []byte:
|
||||
strVal := string(cast)
|
||||
return strVal == "true", strVal == "true" || strVal == "false"
|
||||
|
||||
default:
|
||||
return false, false
|
||||
}
|
||||
|
||||
return false, false
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package builtin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"git.xdrm.io/go/aicra/typecheck"
|
||||
)
|
||||
|
||||
// Float64 checks if a value is a float64
|
||||
type Float64 struct{}
|
||||
|
||||
// NewFloat64 returns a bare number type checker
|
||||
func NewFloat64() *Float64 {
|
||||
return &Float64{}
|
||||
}
|
||||
|
||||
// Checker returns the checker function
|
||||
func (Float64) Checker(typeName string) typecheck.CheckerFunc {
|
||||
// nothing if type not handled
|
||||
if typeName != "float64" && typeName != "float" {
|
||||
return nil
|
||||
}
|
||||
return func(value interface{}) bool {
|
||||
_, isFloat := readFloat(value)
|
||||
return isFloat
|
||||
}
|
||||
}
|
||||
|
||||
// readFloat tries to read a serialized float and returns whether it succeeded.
|
||||
func readFloat(value interface{}) (float64, bool) {
|
||||
switch cast := value.(type) {
|
||||
|
||||
case int:
|
||||
return float64(cast), true
|
||||
|
||||
case uint:
|
||||
return float64(cast), true
|
||||
|
||||
case float64:
|
||||
return cast, true
|
||||
|
||||
// serialized string -> try to convert to float
|
||||
case string:
|
||||
num := json.Number(cast)
|
||||
floatVal, err := num.Float64()
|
||||
return floatVal, err == nil
|
||||
|
||||
case []byte:
|
||||
num := json.Number(cast)
|
||||
floatVal, err := num.Float64()
|
||||
return floatVal, err == nil
|
||||
|
||||
// unknown type
|
||||
default:
|
||||
return 0, false
|
||||
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
package builtin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
|
||||
"git.xdrm.io/go/aicra/typecheck"
|
||||
)
|
||||
|
||||
// Int checks if a value is an int
|
||||
type Int struct{}
|
||||
|
||||
// NewInt returns a bare number type checker
|
||||
func NewInt() *Int {
|
||||
return &Int{}
|
||||
}
|
||||
|
||||
// Checker returns the checker function
|
||||
func (Int) Checker(typeName string) typecheck.CheckerFunc {
|
||||
// nothing if type not handled
|
||||
if typeName != "int" {
|
||||
return nil
|
||||
}
|
||||
return func(value interface{}) bool {
|
||||
_, isInt := readInt(value)
|
||||
|
||||
return isInt
|
||||
}
|
||||
}
|
||||
|
||||
// readInt tries to read a serialized int and returns whether it succeeded.
|
||||
func readInt(value interface{}) (int, bool) {
|
||||
switch cast := value.(type) {
|
||||
|
||||
case int:
|
||||
return cast, true
|
||||
|
||||
case uint:
|
||||
overflows := cast > math.MaxInt64
|
||||
return int(cast), !overflows
|
||||
|
||||
case float64:
|
||||
intVal := int(cast)
|
||||
overflows := cast < float64(math.MinInt64) || cast > float64(math.MaxInt64)
|
||||
return intVal, cast == float64(intVal) && !overflows
|
||||
|
||||
// serialized string -> try to convert to float
|
||||
case string:
|
||||
num := json.Number(cast)
|
||||
intVal, err := num.Int64()
|
||||
return int(intVal), err == nil
|
||||
// serialized string -> try to convert to float
|
||||
|
||||
case []byte:
|
||||
num := json.Number(cast)
|
||||
intVal, err := num.Int64()
|
||||
return int(intVal), err == nil
|
||||
|
||||
// unknown type
|
||||
default:
|
||||
return 0, false
|
||||
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
package builtin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
|
||||
"git.xdrm.io/go/aicra/typecheck"
|
||||
)
|
||||
|
||||
// Uint checks if a value is an uint
|
||||
type Uint struct{}
|
||||
|
||||
// NewUint returns a bare number type checker
|
||||
func NewUint() *Uint {
|
||||
return &Uint{}
|
||||
}
|
||||
|
||||
// Checker returns the checker function
|
||||
func (Uint) Checker(typeName string) typecheck.CheckerFunc {
|
||||
// nothing if type not handled
|
||||
if typeName != "uint" {
|
||||
return nil
|
||||
}
|
||||
return func(value interface{}) bool {
|
||||
_, isInt := readUint(value)
|
||||
|
||||
return isInt
|
||||
}
|
||||
}
|
||||
|
||||
// readUint tries to read a serialized uint and returns whether it succeeded.
|
||||
func readUint(value interface{}) (uint, bool) {
|
||||
switch cast := value.(type) {
|
||||
|
||||
case int:
|
||||
return uint(cast), cast >= 0
|
||||
|
||||
case uint:
|
||||
return cast, true
|
||||
|
||||
case float64:
|
||||
uintVal := uint(cast)
|
||||
overflows := cast < 0 || cast > math.MaxUint64
|
||||
return uintVal, cast == float64(uintVal) && !overflows
|
||||
|
||||
// serialized string -> try to convert to float
|
||||
case string:
|
||||
num := json.Number(cast)
|
||||
floatVal, err := num.Float64()
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
overflows := floatVal < 0 || floatVal > math.MaxUint64
|
||||
return uint(floatVal), !overflows
|
||||
|
||||
case []byte:
|
||||
num := json.Number(cast)
|
||||
floatVal, err := num.Float64()
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
overflows := floatVal < 0 || floatVal > math.MaxUint64
|
||||
return uint(floatVal), !overflows
|
||||
|
||||
// unknown type
|
||||
default:
|
||||
return 0, false
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue