Passed
Push — main ( 8fe6b9...10a5f7 )
by Rushan
01:01 queued 11s
created

validation_test.ExampleValidator_AtIndex   A

Complexity

Conditions 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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