Skip to content

A validator generator for structs/maps for your go applications.

License

Notifications You must be signed in to change notification settings

kanryu/validagen

Repository files navigation

Validagen

A validator generator for structs/maps for your go applications.

Features

  • Simplicity
  • Efficient validators are automatically generated(for ozzo-validation/v4)
  • Prevent bugs by declaratively writing validator settings
  • Generating a validator for the struct automatically generated by oapi-codegen
  • Automatic generation of unit tests for validators

Install

go install github.com/kanryu/validagen

How to use

e.g. There is a struct.

type Address struct {
	Food   string
	Income float64
	Mail   string
	People int
	Street string
	State  string
}

You will write a toml as example.toml.

# Type: struct or map
Type="struct"
# MethodName: (optional) method name of the validator. Validate is default

# Validators.XXX: Validator information for struct XXX
[Validators.Address]
# Name: (optional) struct identifier. key name is substituted as default
# Package: (optional) Validator package name. strings.ToLower(Name) as default
Package = "example"
# Receiver: (optional) receiver of the validator method
# Dir: (optional) Directory to output validator source code. Package name is default
# FileName: (optional) Validator file name. "[ToSnake(Name)]_validator.go" is the default
# FileMode: (optional) file mode of the validator source code 0644 is default
# Import: (optional) Add additional packages when validator source code imports them
# Properties: validators for each field of struct
Properties.Food.Type = "string"
Properties.Food.Required = true
Properties.Food.In = {String=["Cheeze", "Milk", "Meat"]}
Properties.Income.Type = "float"
Properties.Income.Required = true
Properties.Income.In = {Float=[1.1,2.2,3.3]}
Properties.Mail.Type = "string"
Properties.Mail.Required = true
Properties.Mail.Email = true
Properties.People.Type = "int"
Properties.People.Required = true
Properties.People.In = {Int=[1,2,3]}
Properties.State.Type = "string"
Properties.State.Required = true
Properties.State.match = "^[A-Z]{2}$"
Properties.Street.Type = "string"
Properties.Street.Required = true
Properties.Street.Length = [5,50]

You will run validagen.

validagen generate example.toml

You can find the validator as example/address_validator.go

// Code generated by github.com/kanryu/validagen. DO NOT EDIT.
package example

import (
	"regexp"
	"github.com/go-ozzo/ozzo-validation/v4/is"
	validation "github.com/go-ozzo/ozzo-validation/v4"
)

// Validate validater for Address struct
func (a Address) Validate() error {
	return validation.ValidateStruct(&a,
		validation.Field(&a.Food, validation.In("Cheeze", "Milk", "Meat"), validation.Required),
		validation.Field(&a.Income, validation.In(1.1, 2.2, 3.3), validation.Required),
		validation.Field(&a.Mail, validation.Required, is.Email),
		validation.Field(&a.People, validation.In(1, 2, 3), validation.Required),
		validation.Field(&a.State, validation.Match(regexp.MustCompile("^[A-Z]{2}$")), validation.Required),
		validation.Field(&a.Street, validation.Length(5,50), validation.Required),
	)
}

How to test

You can get also test for the validators.

You will add lines into the toml.

[Validators.Address.TestData]
# Testing: flag of generating tests
Testing = true
# Valid: a map of valid data of the struct
Valid.Food = {String=["Cheeze"]}
Valid.Income = {Float=[2.2]}
Valid.Mail = {String=["[email protected]"]}
Valid.People = {Int=[3]}
Valid.State = {String=["SF"]}
Valid.Street = {String=["street"]}
# Invalid: amap of invalid data of the struct.
# each failed test generate contains on invalid property value
Invalid.Food = {String=["Cheezended"]}
Invalid.Income = {Float=[2.233]}
Invalid.Mail = {String=["nil"]}
Invalid.People = {Int=[33]}
Invalid.State = {String=["SFX"]}
Invalid.Street = {String=["fail"]}

After you run validagen again, you can get test as example/address_validator_test.go.

package example


import (
	"testing"
)

// TestAddress_Validate a test suite for (a *Address)Validate()
func TestAddress_Validate(t *testing.T) {
	tests := []struct {
		name    string
		a       Address
		wantErr bool
	}{
		{wantErr: false, name: "OK", a: Address{Food:"Cheeze",Income:2.2,Mail:"[email protected]",People:3,State:"SF",Street:"street"}},
		{wantErr: true, name: "NG for Food", a: Address{Food:"Cheezended",Income:2.2,Mail:"[email protected]",People:3,State:"SF",Street:"street"}},
		{wantErr: true, name: "NG for Income", a: Address{Food:"Cheeze",Income:2.233,Mail:"[email protected]",People:3,State:"SF",Street:"street"}},
		{wantErr: true, name: "NG for Mail", a: Address{Food:"Cheeze",Income:2.2,Mail:"nil",People:3,State:"SF",Street:"street"}},
		{wantErr: true, name: "NG for People", a: Address{Food:"Cheeze",Income:2.2,Mail:"[email protected]",People:33,State:"SF",Street:"street"}},
		{wantErr: true, name: "NG for State", a: Address{Food:"Cheeze",Income:2.2,Mail:"[email protected]",People:3,State:"SFX",Street:"street"}},
		{wantErr: true, name: "NG for Street", a: Address{Food:"Cheeze",Income:2.2,Mail:"[email protected]",People:3,State:"SF",Street:"fail"}},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := tt.a.Validate()
			if tt.wantErr {
				if err == nil {
					t.Fatalf("%q. wantErr %v, but actual err %v", tt.name, tt.wantErr, err)
				}
			} else if err != nil {
				t.Fatalf("%q. wantErr %v, but actual err occured %+v", tt.name, tt.wantErr, err)
			}
		})
	}
}

Author

KATO Kanryu([email protected])

License

MIT

About

A validator generator for structs/maps for your go applications.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published