diff --git a/error_msgs_test.go b/error_msgs_test.go index 1bf5f40..c4a63cc 100644 --- a/error_msgs_test.go +++ b/error_msgs_test.go @@ -21,7 +21,7 @@ func TestErrorMessages(t *testing.T) { "age": Int().GT(18).Required(), "time": Time().Before(time.Now()).Required(), "bool": Bool().True().Required(), - "slice": Slice(String()).Contains("foo").Required(), + "slice": Slice[string](String()).Contains("foo").Required(), }) var u Msgs diff --git a/pointers_test.go b/pointers_test.go index 5e12e45..419a7e6 100644 --- a/pointers_test.go +++ b/pointers_test.go @@ -136,7 +136,7 @@ func TestPtrNestedStructs(t *testing.T) { } func TestPtrInSlice(t *testing.T) { - schema := Slice(Ptr(Int())) + schema := Slice[*int](Ptr(Int())) var out []*int data := []any{10, 20, 30} @@ -154,7 +154,7 @@ func TestPtrSliceStruct(t *testing.T) { Value int } - schema := Slice(Ptr(Struct(Shape{ + schema := Slice[string](Ptr(Struct(Shape{ "value": Int(), }))) var out []*TestStruct @@ -218,7 +218,7 @@ func TestPtrToStruct(t *testing.T) { func TestPtrToSlice(t *testing.T) { var dest *[]*int - s := Ptr(Slice(Ptr(Int()))) + s := Ptr(Slice[int](Ptr(Int()))) err := s.Parse([]any{10, 20, 30}, &dest) assert.Nil(t, err) assert.NotNil(t, dest) diff --git a/pointers_validate_test.go b/pointers_validate_test.go index 12ea0a8..71ed56e 100644 --- a/pointers_validate_test.go +++ b/pointers_validate_test.go @@ -97,7 +97,7 @@ func TestValidatePtrNestedStructs(t *testing.T) { } func TestValidatePtrInSlice(t *testing.T) { - schema := Slice(Ptr(Int()).NotNil()) + schema := Slice[*int](Ptr(Int()).NotNil()) v1, v2, v3 := 10, 20, 30 var v4 *int out := []*int{&v1, &v2, &v3, v4} @@ -115,7 +115,7 @@ func TestValidatePtrSliceStruct(t *testing.T) { Value int } - schema := Slice(Ptr(Struct(Shape{ + schema := Slice[*Shape](Ptr(Struct(Shape{ "value": Int(), }))) out := []*TestStruct{ @@ -167,7 +167,7 @@ func TestValidatePtrToStruct(t *testing.T) { func TestValidatePtrToSlice(t *testing.T) { v1, v2, v3 := 10, 20, 30 dest := &[]*int{&v1, &v2, &v3} - s := Ptr(Slice(Ptr(Int()))) + s := Ptr(Slice[*int](Ptr(Int()))) errs := s.Validate(&dest) assert.Empty(t, errs) diff --git a/preprocess_test.go b/preprocess_test.go index ecd847a..07b4e8e 100644 --- a/preprocess_test.go +++ b/preprocess_test.go @@ -68,7 +68,7 @@ func TestPreprocessTime(t *testing.T) { func TestPreprocessSlice(t *testing.T) { s := Preprocess(func(data string, ctx Ctx) (out []string, err error) { return strings.Split(data, ","), nil - }, Slice(String().Min(1))) + }, Slice[string](String().Min(1))) out := []string{} errs := s.Parse("hello,world", &out) @@ -112,7 +112,7 @@ func TestPreprocessSliceOfStructs(t *testing.T) { result[i] = User{Id: parts[0], Name: parts[1]} } return result, nil - }, Slice(Struct(Shape{ + }, Slice[*Shape](Struct(Shape{ "Id": String().Min(1), "Name": String().Min(1), }))) @@ -140,7 +140,7 @@ func TestPreprocessStructWithSlice(t *testing.T) { }, nil }, Struct(Shape{ "Id": String().Min(1), - "Names": Slice(String().Min(1)), + "Names": Slice[string](String().Min(1)), })) var out User @@ -254,7 +254,7 @@ func TestPreprocessPtrSlice(t *testing.T) { s := Preprocess(func(data string, ctx Ctx) (out *[]string, err error) { slice := strings.Split(data, ",") return &slice, nil - }, Ptr(Slice(String().Min(1)))) + }, Ptr(Slice[string](String().Min(1)))) var out *[]string errs := s.Parse("a,b,c", &out) @@ -291,7 +291,7 @@ func TestPreprocessPartOfStruct(t *testing.T) { func TestPreprocessInSlice(t *testing.T) { - s := Slice( + s := Slice[string]( Preprocess(func(data string, ctx Ctx) (out int, err error) { return strconv.Atoi(data) }, Int().GT(0)), diff --git a/preprocess_validate_test.go b/preprocess_validate_test.go index f30825c..98a6365 100644 --- a/preprocess_validate_test.go +++ b/preprocess_validate_test.go @@ -66,7 +66,7 @@ func TestPreprocessTimeValidate(t *testing.T) { func TestPreprocessSliceValidate(t *testing.T) { s := Preprocess(func(data *[]string, ctx Ctx) (out []string, err error) { return append(*data, "!"), nil - }, Slice(String().Min(1))) + }, Slice[string](String().Min(1))) slice := []string{"hello", "world"} errs := s.Validate(&slice) @@ -105,7 +105,7 @@ func TestPreprocessSliceOfStructsValidate(t *testing.T) { result[i] = User{Id: u.Id + "!", Name: u.Name + "!"} } return result, nil - }, Slice(Struct(Shape{ + }, Slice[*Shape](Struct(Shape{ "Id": String().Min(1), "Name": String().Min(1), }))) @@ -138,7 +138,7 @@ func TestPreprocessStructWithSliceValidate(t *testing.T) { }, nil }, Struct(Shape{ "Id": String().Min(1), - "Names": Slice(String().Min(1)), + "Names": Slice[string](String().Min(1)), })) user := User{ @@ -268,7 +268,7 @@ func TestPreprocessPtrSliceValidate(t *testing.T) { s[i] = str + "!" } return &s, nil - }, Ptr(Slice(String().Min(1)))) + }, Ptr(Slice[string](String().Min(1)))) slice := []string{"a", "b", "c"} pslice := &slice diff --git a/slices.go b/slices.go index ab47ce7..4779c1d 100644 --- a/slices.go +++ b/slices.go @@ -10,24 +10,24 @@ import ( ) // ! INTERNALS -var _ ComplexZogSchema = &SliceSchema{} +var _ ComplexZogSchema = &SliceSchema[int]{} -type SliceSchema struct { - processors []p.ZProcessor[any] +type SliceSchema[T comparable] struct { + processors []p.ZProcessor[[]T] schema ZogSchema - required *p.Test[any] - defaultVal any + required *p.Test[[]T] + defaultVal []T // catch any coercer conf.CoercerFunc } // Returns the type of the schema -func (v *SliceSchema) getType() zconst.ZogType { +func (v *SliceSchema[T]) getType() zconst.ZogType { return zconst.TypeSlice } // Sets the coercer for the schema -func (v *SliceSchema) setCoercer(c conf.CoercerFunc) { +func (v *SliceSchema[T]) setCoercer(c conf.CoercerFunc) { v.coercer = c } @@ -35,8 +35,8 @@ func (v *SliceSchema) setCoercer(c conf.CoercerFunc) { // Creates a slice schema. That is a Zog representation of a slice. // It takes a ZogSchema which will be used to validate against all the items in the slice. -func Slice(schema ZogSchema, opts ...SchemaOption) *SliceSchema { - s := &SliceSchema{ +func Slice[T comparable](schema ZogSchema, opts ...SchemaOption) *SliceSchema[T] { + s := &SliceSchema[T]{ schema: schema, coercer: conf.Coercers.Slice, // default coercer } @@ -47,7 +47,7 @@ func Slice(schema ZogSchema, opts ...SchemaOption) *SliceSchema { } // Validates a slice -func (v *SliceSchema) Validate(data any, options ...ExecOption) ZogIssueMap { +func (v *SliceSchema[T]) Validate(data any, options ...ExecOption) ZogIssueMap { errs := p.NewErrsMap() defer errs.Free() @@ -65,7 +65,7 @@ func (v *SliceSchema) Validate(data any, options ...ExecOption) ZogIssueMap { } // Internal function to validate the data -func (v *SliceSchema) validate(ctx *p.SchemaCtx) { +func (v *SliceSchema[T]) validate(ctx *p.SchemaCtx) { refVal := reflect.ValueOf(ctx.ValPtr).Elem() // we use this to set the value to the ptr. But we still reference the ptr everywhere. This is correct even if it seems confusing. // 2. cast data to string & handle default/required @@ -107,7 +107,7 @@ func (v *SliceSchema) validate(ctx *p.SchemaCtx) { } // Only supports parsing from data=slice[any] to a dest =&slice[] (this can be typed. Doesn't have to be any) -func (v *SliceSchema) Parse(data any, dest any, options ...ExecOption) ZogIssueMap { +func (v *SliceSchema[T]) Parse(data any, dest any, options ...ExecOption) ZogIssueMap { errs := p.NewErrsMap() defer errs.Free() ctx := p.NewExecCtx(errs, conf.IssueFormatter) @@ -125,7 +125,7 @@ func (v *SliceSchema) Parse(data any, dest any, options ...ExecOption) ZogIssueM } // Internal function to process the data -func (v *SliceSchema) process(ctx *p.SchemaCtx) { +func (v *SliceSchema[T]) process(ctx *p.SchemaCtx) { // 2. cast data to string & handle default/required isZeroVal := p.IsParseZeroValue(ctx.Data, ctx) @@ -179,9 +179,9 @@ func (v *SliceSchema) process(ctx *p.SchemaCtx) { } // Adds transform function to schema. -func (v *SliceSchema) Transform(transform Transform[any]) *SliceSchema { - v.processors = append(v.processors, &p.TransformProcessor[any]{ - Transform: p.Transform[any](transform), +func (v *SliceSchema[T]) Transform(transform Transform[[]T]) *SliceSchema[T] { + v.processors = append(v.processors, &p.TransformProcessor[[]T]{ + Transform: p.Transform[[]T](transform), }) return v } @@ -189,8 +189,8 @@ func (v *SliceSchema) Transform(transform Transform[any]) *SliceSchema { // !MODIFIERS // marks field as required -func (v *SliceSchema) Required(options ...TestOption) *SliceSchema { - r := p.Required[any]() +func (v *SliceSchema[T]) Required(options ...TestOption) *SliceSchema[T] { + r := p.Required[[]T]() for _, opt := range options { opt(&r) } @@ -199,13 +199,13 @@ func (v *SliceSchema) Required(options ...TestOption) *SliceSchema { } // marks field as optional -func (v *SliceSchema) Optional() *SliceSchema { +func (v *SliceSchema[T]) Optional() *SliceSchema[T] { v.required = nil return v } // sets the default value -func (v *SliceSchema) Default(val any) *SliceSchema { +func (v *SliceSchema[T]) Default(val []T) *SliceSchema[T] { v.defaultVal = val return v } @@ -220,22 +220,22 @@ func (v *SliceSchema) Default(val any) *SliceSchema { // !TESTS // custom test function call it -> schema.Test(t z.Test) -func (v *SliceSchema) Test(t Test[any]) *SliceSchema { - x := p.Test[any](t) +func (v *SliceSchema[T]) Test(t Test[[]T]) *SliceSchema[T] { + x := p.Test[[]T](t) v.processors = append(v.processors, &x) return v } // Create a custom test function for the schema. This is similar to Zod's `.refine()` method. -func (v *SliceSchema) TestFunc(testFunc BoolTFunc[any], opts ...TestOption) *SliceSchema { - t := p.NewTestFunc("", p.BoolTFunc[any](testFunc), opts...) - v.Test(Test[any](*t)) +func (v *SliceSchema[T]) TestFunc(testFunc BoolTFunc[[]T], opts ...TestOption) *SliceSchema[T] { + t := p.NewTestFunc("", p.BoolTFunc[[]T](testFunc), opts...) + v.Test(Test[[]T](*t)) return v } // Minimum number of items -func (v *SliceSchema) Min(n int, options ...TestOption) *SliceSchema { - t, fn := sliceMin(n) +func (v *SliceSchema[T]) Min(n int, options ...TestOption) *SliceSchema[T] { + t, fn := sliceMin[T](n) p.TestFuncFromBool(fn, &t) for _, opt := range options { opt(&t) @@ -245,8 +245,8 @@ func (v *SliceSchema) Min(n int, options ...TestOption) *SliceSchema { } // Maximum number of items -func (v *SliceSchema) Max(n int, options ...TestOption) *SliceSchema { - t, fn := sliceMax(n) +func (v *SliceSchema[T]) Max(n int, options ...TestOption) *SliceSchema[T] { + t, fn := sliceMax[T](n) p.TestFuncFromBool(fn, &t) for _, opt := range options { opt(&t) @@ -256,8 +256,8 @@ func (v *SliceSchema) Max(n int, options ...TestOption) *SliceSchema { } // Exact number of items -func (v *SliceSchema) Len(n int, options ...TestOption) *SliceSchema { - t, fn := sliceLength(n) +func (v *SliceSchema[T]) Len(n int, options ...TestOption) *SliceSchema[T] { + t, fn := sliceLength[T](n) p.TestFuncFromBool(fn, &t) for _, opt := range options { opt(&t) @@ -267,23 +267,17 @@ func (v *SliceSchema) Len(n int, options ...TestOption) *SliceSchema { } // Slice contains a specific value -func (v *SliceSchema) Contains(value any, options ...TestOption) *SliceSchema { - fn := func(val any, ctx Ctx) bool { - rv := reflect.ValueOf(val).Elem() - if rv.Kind() != reflect.Slice { - return false - } - for idx := 0; idx < rv.Len(); idx++ { - v := rv.Index(idx).Interface() - - if reflect.DeepEqual(v, value) { +func (v *SliceSchema[T]) Contains(value T, options ...TestOption) *SliceSchema[T] { + fn := func(val []T, ctx Ctx) bool { + for _, v := range val { + if v == value { return true } } return false } - t := p.Test[any]{ + t := p.Test[[]T]{ IssueCode: zconst.IssueCodeContains, Params: make(map[string]any, 1), } @@ -296,16 +290,12 @@ func (v *SliceSchema) Contains(value any, options ...TestOption) *SliceSchema { return v } -func sliceMin(n int) (p.Test[any], p.BoolTFunc[any]) { - fn := func(val any, ctx Ctx) bool { - rv := reflect.ValueOf(val).Elem() - if rv.Kind() != reflect.Slice { - return false - } - return rv.Len() >= n +func sliceMin[T comparable](n int) (p.Test[[]T], p.BoolTFunc[[]T]) { + fn := func(val []T, ctx Ctx) bool { + return len(val) >= n } - t := p.Test[any]{ + t := p.Test[[]T]{ IssueCode: zconst.IssueCodeMin, Params: make(map[string]any, 1), } @@ -313,31 +303,24 @@ func sliceMin(n int) (p.Test[any], p.BoolTFunc[any]) { return t, fn } -func sliceMax(n int) (p.Test[any], p.BoolTFunc[any]) { - fn := func(val any, ctx Ctx) bool { - rv := reflect.ValueOf(val).Elem() - if rv.Kind() != reflect.Slice { - return false - } - return rv.Len() <= n +func sliceMax[T comparable](n int) (p.Test[[]T], p.BoolTFunc[[]T]) { + fn := func(val []T, ctx Ctx) bool { + return len(val) <= n } - t := p.Test[any]{ + t := p.Test[[]T]{ IssueCode: zconst.IssueCodeMax, Params: make(map[string]any, 1), } t.Params[zconst.IssueCodeMax] = n return t, fn } -func sliceLength(n int) (p.Test[any], p.BoolTFunc[any]) { - fn := func(val any, ctx Ctx) bool { - rv := reflect.ValueOf(val).Elem() - if rv.Kind() != reflect.Slice { - return false - } - return rv.Len() == n + +func sliceLength[T comparable](n int) (p.Test[[]T], p.BoolTFunc[[]T]) { + fn := func(val []T, ctx Ctx) bool { + return len(val) == n } - t := p.Test[any]{ + t := p.Test[[]T]{ IssueCode: zconst.IssueCodeLen, Params: make(map[string]any, 1), } diff --git a/slices_test.go b/slices_test.go index 3a4556d..ac7ff01 100644 --- a/slices_test.go +++ b/slices_test.go @@ -27,7 +27,7 @@ func TestSliceOfStructs(t *testing.T) { }) var teamSchema = Struct(Shape{ - "users": Slice(userSchema), + "users": Slice[User](userSchema), }) var data = map[string]interface{}{ @@ -63,7 +63,7 @@ func TestSliceOfStructs(t *testing.T) { func TestSliceOptionalSlice(t *testing.T) { s := []string{} - schema := Slice(String()) // should be optional by default + schema := Slice[string](String()) // should be optional by default errs := schema.Parse(nil, &s) assert.Nil(t, errs) @@ -78,7 +78,7 @@ func TestSliceOptionalSlice(t *testing.T) { func TestSliceRequired(t *testing.T) { s := []string{} customMsg := "This slice is required and cannot be empty" - schema := Slice(String()).Required(Message(customMsg)) + schema := Slice[string](String()).Required(Message(customMsg)) // Test with nil value errs := schema.Parse(nil, &s) @@ -93,7 +93,7 @@ func TestSliceRequired(t *testing.T) { } func TestSliceDefaultCoercing(t *testing.T) { s := []string{} - schema := Slice(String()) + schema := Slice[string](String()) errs := schema.Parse("a", &s) assert.Nil(t, errs) assert.Len(t, s, 1) @@ -101,7 +101,7 @@ func TestSliceDefaultCoercing(t *testing.T) { } func TestSliceDefault(t *testing.T) { - schema := Slice(String()).Default([]string{"a", "b", "c"}) + schema := Slice[string](String()).Default([]string{"a", "b", "c"}) s := []string{} err := schema.Parse(nil, &s) assert.Nil(t, err) @@ -114,7 +114,7 @@ func TestSliceDefault(t *testing.T) { func TestSlicePassSchema(t *testing.T) { s := []string{} - schema := Slice(String().Required()) + schema := Slice[string](String().Required()) errs := schema.Parse([]any{"a", "b", "c"}, &s) assert.Nil(t, errs) @@ -126,7 +126,7 @@ func TestSlicePassSchema(t *testing.T) { func TestSliceErrors(t *testing.T) { s := []string{} - schema := Slice(String().Required().Min(2)) + schema := Slice[string](String().Required().Min(2)) errs := schema.Parse([]any{"a", "b"}, &s) assert.Len(t, errs, 3) @@ -138,10 +138,9 @@ func TestSliceErrors(t *testing.T) { func TestSliceTransform(t *testing.T) { s := []string{} - schema := Slice(String()).Transform(func(dataPtr any, ctx Ctx) error { - s := dataPtr.(*[]string) - for i := 0; i < len(*s); i++ { - (*s)[i] = strings.ToUpper((*s)[i]) + schema := Slice[string](String()).Transform(func(s []string, ctx Ctx) error { + for i := 0; i < len(s); i++ { + s[i] = strings.ToUpper(s[i]) } return nil }) @@ -159,7 +158,7 @@ func TestSliceLen(t *testing.T) { s := []string{} els := []string{"a", "b", "c", "d", "e"} - schema := Slice(String().Required()).Len(2) + schema := Slice[string](String().Required()).Len(2) errs := schema.Parse(els[:2], &s) assert.Len(t, s, 2) assert.Nil(t, errs) @@ -167,14 +166,14 @@ func TestSliceLen(t *testing.T) { assert.NotEmpty(t, errs) tutils.VerifyDefaultIssueMessagesMap(t, errs) // min - schema = Slice(String().Required()).Min(2) + schema = Slice[string](String().Required()).Min(2) errs = schema.Parse(els[:4], &s) assert.Nil(t, errs) errs = schema.Parse(els[:1], &s) assert.NotEmpty(t, errs) tutils.VerifyDefaultIssueMessagesMap(t, errs) // max - schema = Slice(String().Required()).Max(3) + schema = Slice[string](String().Required()).Max(3) errs = schema.Parse(els[:1], &s) assert.Nil(t, errs) errs = schema.Parse(els[:4], &s) @@ -187,12 +186,12 @@ func TestSliceContains(t *testing.T) { s := []string{} items := []string{"a", "b", "c"} - schema := Slice(String()).Contains("a") + schema := Slice[string](String()).Contains("a") errs := schema.Parse(items, &s) assert.Nil(t, errs) assert.Len(t, s, 3) - schema = Slice(String()).Contains("d") + schema = Slice[string](String()).Contains("d") errs = schema.Parse(items, &s) assert.NotEmpty(t, errs) tutils.VerifyDefaultIssueMessagesMap(t, errs) @@ -201,10 +200,9 @@ func TestSliceContains(t *testing.T) { func TestSliceCustomTest(t *testing.T) { input := []string{"abc", "defg", "hijkl"} s := []string{} - schema := Slice(String()).TestFunc(func(val any, ctx Ctx) bool { + schema := Slice[string](String()).TestFunc(func(val []string, ctx Ctx) bool { // Custom test logic here - x := val.(*[]string) - return reflect.DeepEqual(input, *x) + return reflect.DeepEqual(input, val) }, Message("custom")) errs := schema.Parse(input, &s) assert.Empty(t, errs) @@ -216,7 +214,7 @@ func TestSliceCustomTest(t *testing.T) { } func TestSliceSchemaOption(t *testing.T) { - s := Slice(String(), WithCoercer(func(original any) (value any, err error) { + s := Slice[string](String(), WithCoercer(func(original any) (value any, err error) { return []string{"coerced"}, nil })) @@ -227,6 +225,6 @@ func TestSliceSchemaOption(t *testing.T) { } func TestSliceGetType(t *testing.T) { - s := Slice(String()) + s := Slice[string](String()) assert.Equal(t, zconst.TypeSlice, s.getType()) } diff --git a/slices_validate_test.go b/slices_validate_test.go index 852019b..ebd56f1 100644 --- a/slices_validate_test.go +++ b/slices_validate_test.go @@ -9,7 +9,7 @@ import ( ) func TestValidateSliceRequired(t *testing.T) { - validator := Slice(String()) + validator := Slice[string](String()) dest := []string{"test"} errs := validator.Validate(&dest) if len(errs) > 0 { @@ -27,7 +27,7 @@ func TestValidateSliceRequired(t *testing.T) { } func TestValidateSliceOptional(t *testing.T) { - validator := Slice(String()).Optional() + validator := Slice[string](String()).Optional() dest := []string{"test"} errs := validator.Validate(&dest) if len(errs) > 0 { @@ -41,7 +41,7 @@ func TestValidateSliceOptional(t *testing.T) { } func TestValidateSliceDefault(t *testing.T) { - validator := Slice(String()).Default([]string{"default"}) + validator := Slice[string](String()).Default([]string{"default"}) dest := []string{} errs := validator.Validate(&dest) if len(errs) > 0 { @@ -51,16 +51,14 @@ func TestValidateSliceDefault(t *testing.T) { } func TestValidateSliceTransform(t *testing.T) { - transform := func(val any, ctx Ctx) error { - if v, ok := val.(*[]string); ok { - for i := range *v { - (*v)[i] = strings.ToUpper((*v)[i]) - } + transform := func(val []string, ctx Ctx) error { + for i := range val { + val[i] = strings.ToUpper(val[i]) } return nil } - validator := Slice(String()).Transform(transform) + validator := Slice[string](String()).Transform(transform) dest := []string{"test", "example"} errs := validator.Validate(&dest) if len(errs) > 0 { @@ -70,7 +68,7 @@ func TestValidateSliceTransform(t *testing.T) { } func TestValidateSliceLen(t *testing.T) { - validator := Slice(String()).Len(2) + validator := Slice[string](String()).Len(2) dest := []string{"test", "example"} errs := validator.Validate(&dest) if len(errs) > 0 { @@ -86,7 +84,7 @@ func TestValidateSliceLen(t *testing.T) { } func TestValidateSliceMin(t *testing.T) { - validator := Slice(String()).Min(2) + validator := Slice[string](String()).Min(2) dest := []string{"test", "example", "extra"} errs := validator.Validate(&dest) if len(errs) > 0 { @@ -102,7 +100,7 @@ func TestValidateSliceMin(t *testing.T) { } func TestValidateSliceMax(t *testing.T) { - validator := Slice(String()).Max(2) + validator := Slice[string](String()).Max(2) dest := []string{"test", "example"} errs := validator.Validate(&dest) if len(errs) > 0 { @@ -118,7 +116,7 @@ func TestValidateSliceMax(t *testing.T) { } func TestValidateSliceContains(t *testing.T) { - validator := Slice(String()).Contains("test") + validator := Slice[string](String()).Contains("test") dest := []string{"test", "example"} errs := validator.Validate(&dest) if len(errs) > 0 { @@ -134,11 +132,8 @@ func TestValidateSliceContains(t *testing.T) { } func TestValidateSliceCustomTest(t *testing.T) { - validator := Slice(String()).TestFunc(func(val any, ctx Ctx) bool { - if v, ok := val.(*[]string); ok { - return len(*v) > 0 && (*v)[0] == "test" - } - return false + validator := Slice[string](String()).TestFunc(func(val []string, ctx Ctx) bool { + return len(val) > 0 && val[0] == "test" }, Message("custom")) dest := []string{"test", "example"} @@ -189,7 +184,7 @@ func TestValidateSliceCustomTest(t *testing.T) { // } func TestValidateSliceMultipleValidators(t *testing.T) { - validator := Slice(String()). + validator := Slice[string](String()). Min(2, Message("too short")). Max(4, Message("too long")). Contains("test", Message("must contain test")) diff --git a/zhttp/zhttp_test.go b/zhttp/zhttp_test.go index 92c9d22..1bc0d90 100644 --- a/zhttp/zhttp_test.go +++ b/zhttp/zhttp_test.go @@ -82,7 +82,7 @@ func TestRequestParams(t *testing.T) { "isMarried": z.Bool().True(), "lights": z.Bool().True(), "cash": z.Float64().GT(10.0), - "swagger": z.Slice( + "swagger": z.Slice[string]( z.String().Min(1)).Min(2), "q": z.String().Required(), }) @@ -130,7 +130,7 @@ func TestRequestParamsOnJsonContentType(t *testing.T) { "isMarried": z.Bool().True(), "lights": z.Bool().True(), "cash": z.Float64().GT(10.0), - "swagger": z.Slice( + "swagger": z.Slice[string]( z.String().Min(1)).Min(2), "q": z.String().Required(), }) @@ -187,7 +187,7 @@ func TestRequestParamsOnDeleteMethodWithJsonContentType(t *testing.T) { "isMarried": z.Bool().True(), "lights": z.Bool().True(), "cash": z.Float64().GT(10.0), - "swagger": z.Slice( + "swagger": z.Slice[string]( z.String().Min(1)).Min(2), "q": z.String().Required(), })