Skip to content

Commit

Permalink
Merge pull request #72 from muonsoft/next
Browse files Browse the repository at this point in the history
Next
  • Loading branch information
strider2038 authored Apr 17, 2022
2 parents 0922cad + b953224 commit aafecfa
Show file tree
Hide file tree
Showing 16 changed files with 1,115 additions and 552 deletions.
2 changes: 1 addition & 1 deletion .scrutinizer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ build:
- go mod download
tests:
override:
- command: go test -v $(go list ./...) -coverpkg .,./it,./validator -coverprofile=cover.out
- command: go test -v $(go list ./...) -coverpkg .,./it,./is,./validate,./validator -coverprofile=cover.out
coverage:
file: 'cover.out'
format: 'go-cc'
Expand Down
1 change: 1 addition & 0 deletions contraint.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/muonsoft/validation/message"
)

// Numeric is used as a type parameter for numeric values.
type Numeric interface {
~float32 | ~float64 |
~int | ~int8 | ~int16 | ~int32 | ~int64 |
Expand Down
3 changes: 3 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import (
"strings"
)

// ConstraintError is used to return critical error from constraint that immediately
// stops the validation process. It is recommended to use Scope.NewConstraintError() method
// to initiate an error from current scope.
type ConstraintError struct {
ConstraintName string
Path *PropertyPath
Expand Down
83 changes: 83 additions & 0 deletions example_check_no_violations_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package validation_test

import (
"context"
"fmt"

"github.com/muonsoft/validation"
"github.com/muonsoft/validation/it"
"github.com/muonsoft/validation/validator"
)

type Vehicle struct {
Model string
MaxSpeed int
}

func (v Vehicle) Validate(ctx context.Context, validator *validation.Validator) error {
return validator.Validate(ctx,
validation.StringProperty("model", v.Model, it.IsNotBlank(), it.HasMaxLength(100)),
validation.NumberProperty[int]("maxSpeed", v.MaxSpeed, it.IsBetween(50, 200)),
)
}

type Car struct {
Vehicle
PassengerSeats int
}

func (c Car) Validate(ctx context.Context, validator *validation.Validator) error {
return validator.Validate(ctx,
validation.CheckNoViolations(c.Vehicle.Validate(ctx, validator)),
validation.NumberProperty[int]("passengerSeats", c.PassengerSeats, it.IsBetween(2, 6)),
)
}

type Truck struct {
Vehicle
LoadCapacity float64
}

func (t Truck) Validate(ctx context.Context, validator *validation.Validator) error {
return validator.Validate(ctx,
validation.CheckNoViolations(t.Vehicle.Validate(ctx, validator)),
validation.NumberProperty[float64]("loadCapacity", t.LoadCapacity, it.IsBetween(10.0, 200.0)),
)
}

func ExampleCheckNoViolations() {
vehicles := []validation.Validatable{
Car{
Vehicle: Vehicle{
Model: "Audi",
MaxSpeed: 10,
},
PassengerSeats: 1,
},
Truck{
Vehicle: Vehicle{
Model: "Benz",
MaxSpeed: 20,
},
LoadCapacity: 5,
},
}

for i, vehicle := range vehicles {
err := validator.ValidateIt(context.Background(), vehicle)
if violations, ok := validation.UnwrapViolationList(err); ok {
fmt.Println("vehicle", i, "is not valid:")
for violation := violations.First(); violation != nil; violation = violation.Next() {
fmt.Println(violation)
}
}
}

// Output:
// vehicle 0 is not valid:
// violation at 'maxSpeed': This value should be between 50 and 200.
// violation at 'passengerSeats': This value should be between 2 and 6.
// vehicle 1 is not valid:
// violation at 'maxSpeed': This value should be between 50 and 200.
// violation at 'loadCapacity': This value should be between 10 and 200.
}
101 changes: 86 additions & 15 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -625,24 +625,38 @@ func ExampleSequentially() {
}

func ExampleAtLeastOneOf() {
title := "bar"

err := validator.Validate(
context.Background(),
validation.AtLeastOneOf(
validation.String(title, it.IsBlank()),
validation.String(title, it.HasMinLength(5)),
),
)
banners := []struct {
Name string
Keywords []string
Companies []string
Brands []string
}{
{Name: "Acme banner", Companies: []string{"Acme"}},
{Name: "Empty banner"},
}

if violations, ok := validation.UnwrapViolationList(err); ok {
for violation := violations.First(); violation != nil; violation = violation.Next() {
fmt.Println(violation)
for _, banner := range banners {
err := validator.Validate(
context.Background(),
validation.AtLeastOneOf(
validation.CountableProperty("keywords", len(banner.Keywords), it.IsNotBlank()),
validation.CountableProperty("companies", len(banner.Companies), it.IsNotBlank()),
validation.CountableProperty("brands", len(banner.Brands), it.IsNotBlank()),
),
)
if violations, ok := validation.UnwrapViolationList(err); ok {
fmt.Println("banner", banner.Name, "is not valid:")
for violation := violations.First(); violation != nil; violation = violation.Next() {
fmt.Println(violation)
}
}
}

// Output:
// violation: This value should be blank.
// violation: This value is too short. It should have 5 characters or more.
// banner Empty banner is not valid:
// violation at 'keywords': This value should not be blank.
// violation at 'companies': This value should not be blank.
// violation at 'brands': This value should not be blank.
}

func ExampleValidator_Validate_basicValidation() {
Expand All @@ -669,14 +683,71 @@ func ExampleValidator_Validate_singletonValidator() {
// violation: This value should not be blank.
}

func ExampleValidator_ValidateString_shorthandAlias() {
func ExampleValidator_ValidateBool() {
v := false
err := validator.ValidateBool(context.Background(), v, it.IsTrue())
fmt.Println(err)
// Output:
// violation: This value should be true.
}

func ExampleValidator_ValidateInt() {
v := 5
err := validator.ValidateInt(context.Background(), v, it.IsGreaterThan(5))
fmt.Println(err)
// Output:
// violation: This value should be greater than 5.
}

func ExampleValidator_ValidateFloat() {
v := 5.5
err := validator.ValidateFloat(context.Background(), v, it.IsGreaterThan(6.5))
fmt.Println(err)
// Output:
// violation: This value should be greater than 6.5.
}

func ExampleValidator_ValidateString() {
err := validator.ValidateString(context.Background(), "", it.IsNotBlank())

fmt.Println(err)
// Output:
// violation: This value should not be blank.
}

func ExampleValidator_ValidateStrings() {
v := []string{"foo", "bar", "baz", "foo"}
err := validator.ValidateStrings(context.Background(), v, it.HasUniqueValues[string]())
fmt.Println(err)
// Output:
// violation: This collection should contain only unique elements.
}

func ExampleValidator_ValidateCountable() {
s := []string{"a", "b"}
err := validator.ValidateCountable(context.Background(), len(s), it.HasMinCount(3))
fmt.Println(err)
// Output:
// violation: This collection should contain 3 elements or more.
}

func ExampleValidator_ValidateTime() {
t := time.Now()
compared, _ := time.Parse(time.RFC3339, "2006-01-02T15:00:00Z")
err := validator.ValidateTime(context.Background(), t, it.IsEarlierThan(compared))
fmt.Println(err)
// Output:
// violation: This value should be earlier than 2006-01-02T15:00:00Z.
}

func ExampleValidator_ValidateEachString() {
v := []string{""}
err := validator.ValidateEachString(context.Background(), v, it.IsNotBlank())
fmt.Println(err)
// Output:
// violation at '[0]': This value should not be blank.
}

func ExampleValidator_Validate_basicStructValidation() {
document := struct {
Title string
Expand Down
55 changes: 55 additions & 0 deletions example_validate_it_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package validation_test

import (
"context"
"fmt"

"github.com/muonsoft/validation"
"github.com/muonsoft/validation/it"
"github.com/muonsoft/validation/validator"
)

type Person struct {
Name string
Surname string
Age int
}

func (p Person) Validate(ctx context.Context, validator *validation.Validator) error {
return validator.Validate(ctx,
validation.StringProperty("name", p.Name, it.IsNotBlank(), it.HasMaxLength(50)),
validation.StringProperty("surname", p.Surname, it.IsNotBlank(), it.HasMaxLength(100)),
validation.NumberProperty[int]("age", p.Age, it.IsBetween(18, 100)),
)
}

func ExampleValidator_ValidateIt() {
persons := []Person{
{
Name: "John",
Surname: "Doe",
Age: 23,
},
{
Name: "",
Surname: "",
Age: 0,
},
}

for i, person := range persons {
err := validator.ValidateIt(context.Background(), person)
if violations, ok := validation.UnwrapViolationList(err); ok {
fmt.Println("person", i, "is not valid:")
for violation := violations.First(); violation != nil; violation = violation.Next() {
fmt.Println(violation)
}
}
}

// Output:
// person 1 is not valid:
// violation at 'name': This value should not be blank.
// violation at 'surname': This value should not be blank.
// violation at 'age': This value should be between 18 and 100.
}
Loading

0 comments on commit aafecfa

Please sign in to comment.