How to define a validator.Fieldlevel equivalent of a given string variable in Go?

Viewed 511

I'm validating my config file using Go's validator package

One of the fields(createTime) from the config file I'm reading as a string, and want to make sure that it is a valid time duration:

type Config struct{
    ...
    CreateTime   string `yaml:"createTime" validate:"duration,required"`
    ...
}

So, I have written a custom validation function as follows:

import (
    "time"
    "github.com/go-playground/validator/v10"
)

// isValidDuration is a custom validation function, and it will check if the given string is a valid time duration
func isValidDuration(fl validator.FieldLevel) bool {
    if _, err := time.ParseDuration(fl.Field().String()); err != nil {
        return false
    }
    return true
}

Which I'm using for validation as follows:

func (configObject *Config) Validate() error {

    // Validate configurations
    validate := validator.New()
    if err := validate.RegisterValidation("duration", isValidDuration); err != nil {
        return err
    }
    return validate.Struct(configObject)
}

The custom validator is working fine and I want to write a unit test for isValidDuration function. Following is the unit test boilerplate generated by IDE:

import (
    "testing"
    "github.com/go-playground/validator/v10"
)

func Test_isValidDuration(t *testing.T) {
    type args struct {
        fl validator.FieldLevel
    }
    var tests = []struct {
        name string
        args args
        want bool
    }{
        // TODO: Add test cases.
        {name: "positive", args: ???????, want: true},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if got := isValidDuration(tt.args.fl); got != tt.want {
                t.Errorf("isValidDuration() = %v, want %v", got, tt.want)
            }
        })
    }
}

I'm new to Go and not sure what to pass in the args field of the testcase above. How do I create a struct containing one validator.FieldLevel field?

Ideally, I would like to pass something like "10m" as args and since it is a valid time duration, would expect the output of isValidDuration as true since "10m" is a valid duration. I'm trying this: {name: "positive", args: struct{ fl validator.FieldLevel }{fl: "10m"}, want: true} but getting this ereor: '"10m"' (type string) cannot be represented by the type validator.FieldLevel

How do I create a validator.FieldLevel variable with value equivalent to "10m"? Could someone please help me out?

1 Answers

problem1

A language semantic problem, fl is not the type String.

{
  name: "positive", 
  args: args{
    fl: validator.FieldLevel{
       // ....
    },
  }, 
  want: true,
},

problem2

How to use validator.FieldLevel.

In code base, we can see FieldLevel is a interface, and you need create struct validate, which is not exported and not supposed to be used by user.

type FieldLevel interface

// ...

var _ FieldLevel = new(validate)

answer

So, you'd best to write your UT like UT of validator package. Don't use the code from your IDE!

// have a look at this UT
// github.com/go-playground/validator/v10@v10.10.0/validator_test.go
func TestKeysCustomValidation(t *testing.T) {
Related