Passed
Push — main ( 41473a...4a4d10 )
by Igor
13:02 queued 11:12
created

validation_test.ExampleValidator_Validate_translationsByContextArgument   A

Complexity

Conditions 3

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 13
nop 0
dl 0
loc 18
rs 9.75
c 0
b 0
f 0
1
package validation_test
2
3
import (
4
	"context"
5
	"errors"
6
	"fmt"
7
	"log"
8
	"regexp"
9
	"time"
10
11
	languagepkg "github.com/muonsoft/language"
12
	"github.com/muonsoft/validation"
13
	"github.com/muonsoft/validation/it"
14
	"github.com/muonsoft/validation/message/translations/russian"
15
	"github.com/muonsoft/validation/validator"
16
	"golang.org/x/text/feature/plural"
17
	"golang.org/x/text/language"
18
	"golang.org/x/text/message/catalog"
19
)
20
21
func ExampleValue() {
22
	v := ""
23
	err := validator.Validate(validation.Value(v, it.IsNotBlank()))
24
	fmt.Println(err)
25
	// Output:
26
	// violation: This value should not be blank.
27
}
28
29
func ExamplePropertyValue() {
30
	v := Book{Title: ""}
31
	err := validator.Validate(
32
		validation.PropertyValue("title", v.Title, it.IsNotBlank()),
33
	)
34
	fmt.Println(err)
35
	// Output:
36
	// violation at 'title': This value should not be blank.
37
}
38
39
func ExampleBool() {
40
	v := false
41
	err := validator.Validate(validation.Bool(&v, it.IsTrue()))
42
	fmt.Println(err)
43
	// Output:
44
	// violation: This value should be true.
45
}
46
47
func ExampleBoolProperty() {
48
	v := struct {
49
		IsPublished bool
50
	}{
51
		IsPublished: false,
52
	}
53
	err := validator.Validate(
54
		validation.BoolProperty("isPublished", &v.IsPublished, it.IsTrue()),
55
	)
56
	fmt.Println(err)
57
	// Output:
58
	// violation at 'isPublished': This value should be true.
59
}
60
61
func ExampleNumber() {
62
	v := 5
63
	err := validator.Validate(validation.Number(&v, it.IsGreaterThanInteger(5)))
64
	fmt.Println(err)
65
	// Output:
66
	// violation: This value should be greater than 5.
67
}
68
69
func ExampleNumberProperty() {
70
	v := struct {
71
		Count int
72
	}{
73
		Count: 5,
74
	}
75
	err := validator.Validate(
76
		validation.NumberProperty("count", &v.Count, it.IsGreaterThanInteger(5)),
77
	)
78
	fmt.Println(err)
79
	// Output:
80
	// violation at 'count': This value should be greater than 5.
81
}
82
83
func ExampleString() {
84
	v := ""
85
	err := validator.Validate(validation.String(&v, it.IsNotBlank()))
86
	fmt.Println(err)
87
	// Output:
88
	// violation: This value should not be blank.
89
}
90
91
func ExampleStringProperty() {
92
	v := Book{Title: ""}
93
	err := validator.Validate(
94
		validation.StringProperty("title", &v.Title, it.IsNotBlank()),
95
	)
96
	fmt.Println(err)
97
	// Output:
98
	// violation at 'title': This value should not be blank.
99
}
100
101
func ExampleIterable() {
102
	v := make([]string, 0)
103
	err := validator.Validate(validation.Iterable(v, it.IsNotBlank()))
104
	fmt.Println(err)
105
	// Output:
106
	// violation: This value should not be blank.
107
}
108
109
func ExampleIterableProperty() {
110
	v := Product{Tags: []string{}}
111
	err := validator.Validate(
112
		validation.IterableProperty("tags", v.Tags, it.IsNotBlank()),
113
	)
114
	fmt.Println(err)
115
	// Output:
116
	// violation at 'tags': This value should not be blank.
117
}
118
119
func ExampleCountable() {
120
	s := []string{"a", "b"}
121
	err := validator.Validate(validation.Countable(len(s), it.HasMinCount(3)))
122
	fmt.Println(err)
123
	// Output:
124
	// violation: This collection should contain 3 elements or more.
125
}
126
127
func ExampleCountableProperty() {
128
	v := Product{Tags: []string{"a", "b"}}
129
	err := validator.Validate(
130
		validation.CountableProperty("tags", len(v.Tags), it.HasMinCount(3)),
131
	)
132
	fmt.Println(err)
133
	// Output:
134
	// violation at 'tags': This collection should contain 3 elements or more.
135
}
136
137
func ExampleTime() {
138
	t := time.Now()
139
	compared, _ := time.Parse(time.RFC3339, "2006-01-02T15:00:00Z")
140
	err := validator.Validate(
141
		validation.Time(&t, it.IsEarlierThan(compared)),
142
	)
143
	fmt.Println(err)
144
	// Output:
145
	// violation: This value should be earlier than 2006-01-02T15:00:00Z.
146
}
147
148
func ExampleTimeProperty() {
149
	v := struct {
150
		CreatedAt time.Time
151
	}{
152
		CreatedAt: time.Now(),
153
	}
154
	compared, _ := time.Parse(time.RFC3339, "2006-01-02T15:00:00Z")
155
	err := validator.Validate(
156
		validation.TimeProperty("createdAt", &v.CreatedAt, it.IsEarlierThan(compared)),
157
	)
158
	fmt.Println(err)
159
	// Output:
160
	// violation at 'createdAt': This value should be earlier than 2006-01-02T15:00:00Z.
161
}
162
163
func ExampleEach() {
164
	v := []string{""}
165
	err := validator.Validate(validation.Each(v, it.IsNotBlank()))
166
	fmt.Println(err)
167
	// Output:
168
	// violation at '[0]': This value should not be blank.
169
}
170
171
func ExampleEachProperty() {
172
	v := Product{Tags: []string{""}}
173
	err := validator.Validate(
174
		validation.EachProperty("tags", v.Tags, it.IsNotBlank()),
175
	)
176
	fmt.Println(err)
177
	// Output:
178
	// violation at 'tags[0]': This value should not be blank.
179
}
180
181
func ExampleEachString() {
182
	v := []string{""}
183
	err := validator.Validate(validation.EachString(v, it.IsNotBlank()))
184
	fmt.Println(err)
185
	// Output:
186
	// violation at '[0]': This value should not be blank.
187
}
188
189
func ExampleEachStringProperty() {
190
	v := Product{Tags: []string{""}}
191
	err := validator.Validate(
192
		validation.EachStringProperty("tags", v.Tags, it.IsNotBlank()),
193
	)
194
	fmt.Println(err)
195
	// Output:
196
	// violation at 'tags[0]': This value should not be blank.
197
}
198
199
func ExampleNewCustomStringConstraint() {
200
	validate := func(s string) bool {
201
		return s == "valid"
202
	}
203
	constraint := validation.NewCustomStringConstraint(
204
		validate,
205
		"ExampleConstraint", // constraint name
206
		"exampleCode",       // violation code
207
		"Unexpected value.", // violation message template
208
	)
209
210
	s := "foo"
211
	err := validator.ValidateString(&s, constraint)
212
213
	fmt.Println(err)
214
	// Output:
215
	// violation: Unexpected value.
216
}
217
218
func ExampleWhen() {
219
	visaRegex := regexp.MustCompile("^4[0-9]{12}(?:[0-9]{3})?$")
220
	masterCardRegex := regexp.MustCompile("^(5[1-5][0-9]{14}|2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12}))$")
221
222
	payment := struct {
223
		CardType   string
224
		CardNumber string
225
		Amount     int
226
	}{
227
		CardType:   "Visa",
228
		CardNumber: "4111",
229
		Amount:     1000,
230
	}
231
232
	err := validator.Validate(
233
		validation.StringProperty(
234
			"cardType",
235
			&payment.CardType,
236
			it.IsOneOfStrings("Visa", "MasterCard"),
237
		),
238
		validation.StringProperty(
239
			"cardNumber",
240
			&payment.CardNumber,
241
			validation.
242
				When(payment.CardType == "Visa").
243
				Then(it.Matches(visaRegex)).
244
				Else(it.Matches(masterCardRegex)),
245
		),
246
	)
247
248
	fmt.Println(err)
249
	// Output:
250
	// violation at 'cardNumber': This value is not valid.
251
}
252
253
func ExampleConditionalConstraint_Then() {
254
	v := "foo"
255
	err := validator.ValidateString(
256
		&v,
257
		validation.When(true).
258
			Then(
259
				it.Matches(regexp.MustCompile(`^\w+$`)),
260
			),
261
	)
262
	fmt.Println(err)
263
	// Output:
264
	// <nil>
265
}
266
267
func ExampleConditionalConstraint_Else() {
268
	v := "123"
269
	err := validator.ValidateString(
270
		&v,
271
		validation.When(false).
272
			Then(
273
				it.Matches(regexp.MustCompile(`^\w+$`)),
274
			).
275
			Else(
276
				it.Matches(regexp.MustCompile(`^\d+$`)),
277
			),
278
	)
279
	fmt.Println(err)
280
	// Output:
281
	// <nil>
282
}
283
284
func ExampleSequentially() {
285
	title := "bar"
286
287
	err := validator.ValidateString(
288
		&title,
289
		validation.Sequentially(
290
			it.IsBlank(),
291
			it.HasMinLength(5),
292
		),
293
	)
294
295
	fmt.Println(err)
296
	// Output:
297
	// violation: This value should be blank.
298
}
299
300
func ExampleValidator_Validate_basicValidation() {
301
	s := ""
302
303
	validator, err := validation.NewValidator()
304
	if err != nil {
305
		log.Fatal(err)
306
	}
307
	err = validator.Validate(validation.String(&s, it.IsNotBlank()))
308
309
	fmt.Println(err)
310
	// Output:
311
	// violation: This value should not be blank.
312
}
313
314
func ExampleValidator_Validate_singletonValidator() {
315
	s := ""
316
317
	err := validator.Validate(validation.String(&s, it.IsNotBlank()))
318
319
	fmt.Println(err)
320
	// Output:
321
	// violation: This value should not be blank.
322
}
323
324
func ExampleValidator_ValidateString_shorthandAlias() {
325
	s := ""
326
327
	err := validator.ValidateString(&s, it.IsNotBlank())
328
329
	fmt.Println(err)
330
	// Output:
331
	// violation: This value should not be blank.
332
}
333
334
func ExampleValidator_Validate_basicStructValidation() {
335
	document := struct {
336
		Title    string
337
		Keywords []string
338
	}{
339
		Title:    "",
340
		Keywords: []string{""},
341
	}
342
343
	err := validator.Validate(
344
		validation.StringProperty("title", &document.Title, it.IsNotBlank()),
345
		validation.CountableProperty("keywords", len(document.Keywords), it.HasCountBetween(2, 10)),
346
		validation.EachStringProperty("keywords", document.Keywords, it.IsNotBlank()),
347
	)
348
349
	if violations, ok := validation.UnwrapViolationList(err); ok {
350
		for violation := violations.First(); violation != nil; violation = violation.Next() {
351
			fmt.Println(violation)
352
		}
353
	}
354
	// Output:
355
	// violation at 'title': This value should not be blank.
356
	// violation at 'keywords': This collection should contain 2 elements or more.
357
	// violation at 'keywords[0]': This value should not be blank.
358
}
359
360
func ExampleValidator_Validate_conditionalValidationOnConstraint() {
361
	notes := []struct {
362
		Title    string
363
		IsPublic bool
364
		Text     string
365
	}{
366
		{Title: "published note", IsPublic: true, Text: "text of published note"},
367
		{Title: "draft note", IsPublic: true, Text: ""},
368
	}
369
370
	for i, note := range notes {
371
		err := validator.Validate(
372
			validation.StringProperty("name", &note.Title, it.IsNotBlank()),
373
			validation.StringProperty("text", &note.Text, it.IsNotBlank().When(note.IsPublic)),
374
		)
375
		if violations, ok := validation.UnwrapViolationList(err); ok {
376
			for violation := violations.First(); violation != nil; violation = violation.Next() {
377
				fmt.Printf("error on note %d: %s", i, violation)
378
			}
379
		}
380
	}
381
382
	// Output:
383
	// error on note 1: violation at 'text': This value should not be blank.
384
}
385
386
func ExampleValidator_Validate_passingPropertyPathViaOptions() {
387
	s := ""
388
389
	err := validator.Validate(
390
		validation.String(
391
			&s,
392
			validation.PropertyName("properties"),
393
			validation.ArrayIndex(1),
394
			validation.PropertyName("tag"),
395
			it.IsNotBlank(),
396
		),
397
	)
398
399
	violation := err.(*validation.ViolationList).First()
400
	fmt.Println("property path:", violation.PropertyPath().String())
401
	// Output:
402
	// property path: properties[1].tag
403
}
404
405
func ExampleValidator_Validate_propertyPathWithScopedValidator() {
406
	s := ""
407
408
	err := validator.
409
		AtProperty("properties").
410
		AtIndex(1).
411
		AtProperty("tag").
412
		Validate(validation.String(&s, it.IsNotBlank()))
413
414
	violation := err.(*validation.ViolationList).First()
415
	fmt.Println("property path:", violation.PropertyPath().String())
416
	// Output:
417
	// property path: properties[1].tag
418
}
419
420
func ExampleValidator_Validate_propertyPathBySpecialArgument() {
421
	s := ""
422
423
	err := validator.Validate(
424
		// this is an alias for
425
		// validation.String(&s, validation.PropertyName("property"), it.IsNotBlank()),
426
		validation.StringProperty("property", &s, it.IsNotBlank()),
427
	)
428
429
	violation := err.(*validation.ViolationList).First()
430
	fmt.Println("property path:", violation.PropertyPath().String())
431
	// Output:
432
	// property path: property
433
}
434
435
func ExampleValidator_AtProperty() {
436
	book := &Book{Title: ""}
437
438
	err := validator.AtProperty("book").Validate(
439
		validation.StringProperty("title", &book.Title, it.IsNotBlank()),
440
	)
441
442
	violation := err.(*validation.ViolationList).First()
443
	fmt.Println("property path:", violation.PropertyPath().String())
444
	// Output:
445
	// property path: book.title
446
}
447
448
func ExampleValidator_AtIndex() {
449
	books := []Book{{Title: ""}}
450
451
	err := validator.AtIndex(0).Validate(
452
		validation.StringProperty("title", &books[0].Title, it.IsNotBlank()),
453
	)
454
455
	violation := err.(*validation.ViolationList).First()
456
	fmt.Println("property path:", violation.PropertyPath().String())
457
	// Output:
458
	// property path: [0].title
459
}
460
461
func ExampleValidator_Validate_translationsByDefaultLanguage() {
462
	validator, err := validation.NewValidator(
463
		validation.Translations(russian.Messages),
464
		validation.DefaultLanguage(language.Russian),
465
	)
466
	if err != nil {
467
		log.Fatal(err)
468
	}
469
470
	s := ""
471
	err = validator.ValidateString(&s, it.IsNotBlank())
472
473
	fmt.Println(err)
474
	// Output:
475
	// violation: Значение не должно быть пустым.
476
}
477
478
func ExampleValidator_Validate_translationsByArgument() {
479
	validator, err := validation.NewValidator(
480
		validation.Translations(russian.Messages),
481
	)
482
	if err != nil {
483
		log.Fatal(err)
484
	}
485
486
	s := ""
487
	err = validator.Validate(
488
		validation.Language(language.Russian),
489
		validation.String(&s, it.IsNotBlank()),
490
	)
491
492
	fmt.Println(err)
493
	// Output:
494
	// violation: Значение не должно быть пустым.
495
}
496
497
func ExampleValidator_Validate_translationsByContextArgument() {
498
	validator, err := validation.NewValidator(
499
		validation.Translations(russian.Messages),
500
	)
501
	if err != nil {
502
		log.Fatal(err)
503
	}
504
505
	s := ""
506
	ctx := languagepkg.WithContext(context.Background(), language.Russian)
507
	err = validator.Validate(
508
		validation.Context(ctx),
509
		validation.String(&s, it.IsNotBlank()),
510
	)
511
512
	fmt.Println(err)
513
	// Output:
514
	// violation: Значение не должно быть пустым.
515
}
516
517
func ExampleValidator_Validate_translationsByContextValidator() {
518
	validator, err := validation.NewValidator(
519
		validation.Translations(russian.Messages),
520
	)
521
	if err != nil {
522
		log.Fatal(err)
523
	}
524
	ctx := languagepkg.WithContext(context.Background(), language.Russian)
525
	validator = validator.WithContext(ctx)
526
527
	s := ""
528
	err = validator.ValidateString(&s, it.IsNotBlank())
529
530
	fmt.Println(err)
531
	// Output:
532
	// violation: Значение не должно быть пустым.
533
}
534
535
func ExampleValidator_Validate_customizingErrorMessage() {
536
	s := ""
537
538
	err := validator.ValidateString(&s, it.IsNotBlank().Message("this value is required"))
539
540
	fmt.Println(err)
541
	// Output:
542
	// violation: this value is required
543
}
544
545
func ExampleValidator_Validate_translationForCustomMessage() {
546
	const customMessage = "tags should contain more than {{ limit }} element(s)"
547
	validator, err := validation.NewValidator(
548
		validation.Translations(map[language.Tag]map[string]catalog.Message{
549
			language.Russian: {
550
				customMessage: plural.Selectf(1, "",
551
					plural.One, "теги должны содержать {{ limit }} элемент и более",
552
					plural.Few, "теги должны содержать более {{ limit }} элемента",
553
					plural.Other, "теги должны содержать более {{ limit }} элементов"),
554
			},
555
		}),
556
	)
557
	if err != nil {
558
		log.Fatal(err)
559
	}
560
561
	var tags []string
562
	err = validator.Validate(
563
		validation.Language(language.Russian),
564
		validation.Iterable(tags, it.HasMinCount(1).MinMessage(customMessage)),
565
	)
566
567
	fmt.Println(err)
568
	// Output:
569
	// violation: теги должны содержать 1 элемент и более
570
}
571
572
func ExampleValidator_BuildViolation_buildingViolation() {
573
	validator, err := validation.NewValidator()
574
	if err != nil {
575
		log.Fatal(err)
576
	}
577
578
	violation := validator.BuildViolation("clientCode", "Client message with {{ parameter }}.").
579
		AddParameter("{{ parameter }}", "value").
580
		CreateViolation()
581
582
	fmt.Println(violation.Message())
583
	// Output:
584
	// Client message with value.
585
}
586
587
func ExampleValidator_BuildViolation_translatableParameter() {
588
	validator, err := validation.NewValidator(
589
		validation.Translations(map[language.Tag]map[string]catalog.Message{
590
			language.Russian: {
591
				"The operation is only possible for the {{ role }}.": catalog.String("Операция возможна только для {{ role }}."),
592
				"administrator role": catalog.String("роли администратора"),
593
			},
594
		}),
595
	)
596
	if err != nil {
597
		log.Fatal(err)
598
	}
599
600
	violation := validator.WithLanguage(language.Russian).
601
		BuildViolation("clientCode", "The operation is only possible for the {{ role }}.").
602
		SetParameters(validation.TemplateParameter{
603
			Key:              "{{ role }}",
604
			Value:            "administrator role",
605
			NeedsTranslation: true,
606
		}).
607
		CreateViolation()
608
609
	fmt.Println(violation.Message())
610
	// Output:
611
	// Операция возможна только для роли администратора.
612
}
613
614
func ExampleViolationList_First() {
615
	violations := validation.NewViolationList(
616
		validator.BuildViolation("", "foo").CreateViolation(),
617
		validator.BuildViolation("", "bar").CreateViolation(),
618
	)
619
620
	for violation := violations.First(); violation != nil; violation = violation.Next() {
621
		fmt.Println(violation)
622
	}
623
	// Output:
624
	// violation: foo
625
	// violation: bar
626
}
627
628
func ExampleViolationList_AppendFromError_addingViolation() {
629
	violations := validation.NewViolationList()
630
	err := validator.BuildViolation("", "foo").CreateViolation()
631
632
	appendErr := violations.AppendFromError(err)
633
634
	fmt.Println("append error:", appendErr)
635
	fmt.Println("violations:", violations)
636
	// Output:
637
	// append error: <nil>
638
	// violations: violation: foo
639
}
640
641
func ExampleViolationList_AppendFromError_addingViolationList() {
642
	violations := validation.NewViolationList()
643
	err := validation.NewViolationList(
644
		validator.BuildViolation("", "foo").CreateViolation(),
645
		validator.BuildViolation("", "bar").CreateViolation(),
646
	)
647
648
	appendErr := violations.AppendFromError(err)
649
650
	fmt.Println("append error:", appendErr)
651
	fmt.Println("violations:", violations)
652
	// Output:
653
	// append error: <nil>
654
	// violations: violation: foo; violation: bar
655
}
656
657
func ExampleViolationList_AppendFromError_addingError() {
658
	violations := validation.NewViolationList()
659
	err := errors.New("error")
660
661
	appendErr := violations.AppendFromError(err)
662
663
	fmt.Println("append error:", appendErr)
664
	fmt.Println("violations length:", violations.Len())
665
	// Output:
666
	// append error: error
667
	// violations length: 0
668
}
669