Go validate table test failing on only valid structs

// this is in a validation test

type Report struct {
    SysrptID    json.Number `json:"SysrptID" validate:"required"`
    Name        string      `json:"Name" validate:"required"`
    Description string      `json:"Description"`
    FileName    string      `json:"FileName"`
    RptType     string      `json:"RptType" validate:"oneof=AIS MDR CTE MCM GEN RAL DOC"`
    Category    []string   
}

// this is my validation code:

import (
	"fmt"
	"github.com/go-playground/validator"
	"regexp"
)

// ValidationError wraps the validators FieldError so we do not
// expose this to out code
type ValidationError struct {
	validator.FieldError
}

func (v ValidationError) Error() string {
	return fmt.Sprintf(
		"Key: '%s' Error: Field validation for '%s' failed on the '%s' tag",
		v.Namespace(),
		v.Field(),
		v.Tag(),
	)
}

// ValidationErrors is a collection of ValidationError
type ValidationErrors []ValidationError

// Errors converts the slice into a string slice
func (v ValidationErrors) Errors() []string {
	errs := []string{}
	for _, err := range v {
		errs = append(errs, err.Error())
	}

	return errs
}

// Validation contains
type Validation struct {
	validate *validator.Validate
}

// NewValidation creates a new Validation type
func NewValidation() *Validation {
	validate := validator.New()
	//validate.RegisterValidation("sku", validateSKU)

	return &Validation{validate}
}

// Validate the item
// for more detail the returned error can be cast into a
// validator.ValidationErrors collection
//
// if ve, ok := err.(validator.ValidationErrors); ok {
//			fmt.Println(ve.Namespace())
//			fmt.Println(ve.Field())
//			fmt.Println(ve.StructNamespace())
//			fmt.Println(ve.StructField())
//			fmt.Println(ve.Tag())
//			fmt.Println(ve.ActualTag())
//			fmt.Println(ve.Kind())
//			fmt.Println(ve.Type())
//			fmt.Println(ve.Value())
//			fmt.Println(ve.Param())
//			fmt.Println()
//	}
func (v *Validation) Validate(i interface{}) ValidationErrors {
	errs := v.validate.Struct(i).(validator.ValidationErrors)

// I think the issue is here :frowning: 
	if len(errs) == 0 {
		return nil
	}

	var returnErrs []ValidationError
	for _, err := range errs {
		// cast the FieldError into our ValidationError and append to the slice
		ve := ValidationError{err.(validator.FieldError)}
		returnErrs = append(returnErrs, ve)
	}

	return returnErrs
}

// validateSKU not used only example
func validateSKU(fl validator.FieldLevel) bool {
	// SKU must be in the format abc-abc-abc
	re := regexp.MustCompile(`[a-z]+-[a-z]+-[a-z]+`)
	sku := re.FindAllString(fl.Field().String(), -1)

	if len(sku) == 1 {
		return true
	}

	return false
}

// end of validator

// when i run this test i get a panic on what [i think] should be a valid // report it never hits the if statement, not sure what I am doing wrong
// the structs that fail validation work great.
// the panic is:
// 2021/02/17 08:13:36 panic occurred: interface conversion: error is // nil, not validator.ValidationErrors

func TestReportsValidator(t *testing.T) {
    tests := map[string]struct {
        input Report
        want  int
    }{
        //"just id":   {input: Report{SysrptID: "1"}, want: 2},
        //"just name": {input: Report{Name: "test report"}, want: 2},
        //"none": {input: Report{}, want: 3},
        "valid":   {input: Report{SysrptID: "1", Name: "test", RptType: "RAL"}, want: 0},
       //"trailing sep": {input: Report{}, want: 1},
    }

    for name, tc := range tests {
        fmt.Println(name, tc.input, tc.want)

        t.Run(name, func(t *testing.T) {
            v := NewValidation()
            defer func() {
                if err := recover(); err != nil {
                    log.Println("panic occurred:", err)
                }
            }()

            fe := v.Validate(tc.input)
            if fe != nil {
                assert.Len(t, fe, tc.want)
            }

            //diff := cmp.Diff(tc.want, got)
            //if diff != "" {
            //  t.Fatalf(diff)
            //}
        })

    }

}

Please wrap your code in three backticks like this:

```
code here
```

thanks!!

the go comma ok idiom to the rescue, it means I can return a nil if there are no validation issues. Bad bug in some youtube code. fixed by a test. it was happening on my service on adding an item that should have passed validation. coolness.

func (v *Validation) Validate(i interface{}) ValidationErrors {
	var returnErrs []ValidationError

	if errs, ok := v.validate.Struct(i).(validator.ValidationErrors); ok {

		if errs != nil {
			for _, err := range errs {
				if fe, ok := err.(validator.FieldError); ok {
					ve := ValidationError{fe}
					returnErrs = append(returnErrs, ve)
				}
			}
		}
	}

	return returnErrs
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.