Test Failed
Push — main ( 05cfc8...747a0a )
by Igor
02:24
created

validation_test.WebstoreItems.Validate   A

Complexity

Conditions 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
dl 0
loc 12
rs 10
c 0
b 0
f 0
nop 3
1
package validation_test
2
3
import (
4
	"context"
5
	"fmt"
6
	"net/url"
7
8
	"github.com/muonsoft/validation"
9
	"github.com/muonsoft/validation/it"
10
	"github.com/muonsoft/validation/validator"
11
)
12
13
type Webstore struct {
14
	Name  string
15
	URL   string
16
	Items WebstoreItems
17
}
18
19
func (w Webstore) Validate(ctx context.Context, validator *validation.Validator) error {
20
	domain := ""
21
	u, err := url.Parse(w.URL)
22
	if err == nil {
23
		domain = u.Host
24
	}
25
26
	return validator.Validate(
27
		ctx,
28
		validation.StringProperty("name", w.Name, it.IsNotBlank(), it.HasMaxLength(100)),
29
		validation.StringProperty("url", w.URL, it.IsNotBlank(), it.IsURL()),
30
		validation.CountableProperty("items", len(w.Items), it.IsNotBlank(), it.HasMaxCount(20)),
31
		validation.ValidProperty(
32
			"items",
33
			validation.ValidatableFunc(func(ctx context.Context, validator *validation.Validator) error {
34
				// passing context value by callback function
35
				return w.Items.Validate(ctx, validator, domain)
36
			}),
37
		),
38
	)
39
}
40
41
type WebstoreItem struct {
42
	Name  string
43
	URL   string
44
	Price int
45
}
46
47
func (w WebstoreItem) Validate(ctx context.Context, validator *validation.Validator, webstoreDomain string) error {
48
	return validator.Validate(
49
		ctx,
50
		validation.StringProperty("name", w.Name, it.IsNotBlank(), it.HasMaxLength(100)),
51
		validation.NumberProperty[int]("price", w.Price, it.IsNotBlankNumber[int](), it.IsLessThan[int](10000)),
52
		validation.StringProperty(
53
			"url", w.URL,
54
			it.IsNotBlank(),
55
			// using webstore domain passed as a function parameter
56
			it.IsURL().WithHosts(webstoreDomain).WithProhibitedMessage(
57
				`Webstore item URL domain must match "{{ webstoreDomain }}".`,
58
				validation.TemplateParameter{Key: "{{ webstoreDomain }}", Value: webstoreDomain},
59
			),
60
		),
61
	)
62
}
63
64
type WebstoreItems []WebstoreItem
65
66
func (items WebstoreItems) Validate(ctx context.Context, validator *validation.Validator, webstoreDomain string) error {
67
	violations := validation.NewViolationList()
68
69
	for i, item := range items {
70
		// passing context value to each item
71
		err := violations.AppendFromError(item.Validate(ctx, validator.AtIndex(i), webstoreDomain))
72
		if err != nil {
73
			return err
74
		}
75
	}
76
77
	return violations.AsError()
78
}
79
80
func ExampleValidatableFunc_Validate() {
81
	store := Webstore{
82
		Name: "Acme store",
83
		URL:  "https://acme.com/homepage",
84
		Items: []WebstoreItem{
85
			{
86
				Name:  "Book",
87
				URL:   "https://acme.com/items/the-book",
88
				Price: 100,
89
			},
90
			{
91
				Name:  "Notepad",
92
				URL:   "https://store.com/items/notepad",
93
				Price: 1000,
94
			},
95
		},
96
	}
97
98
	err := validator.Validate(context.Background(), validation.Valid(store))
99
100
	if violations, ok := validation.UnwrapViolationList(err); ok {
101
		violations.ForEach(func(i int, violation validation.Violation) error {
102
			fmt.Println(violation)
103
			return nil
104
		})
105
	}
106
	// Output:
107
	// violation at "items[1].url": "Webstore item URL domain must match "acme.com"."
108
}
109