Passed
Push — main ( dace85...224888 )
by Rushan
53s queued 11s
created

it.StringComparisonConstraint.Name   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
dl 0
loc 2
ccs 0
cts 1
cp 0
crap 2
rs 10
c 0
b 0
f 0
nop 0
1
package it
2
3
import (
4
	"strconv"
5
	"time"
6
7
	"github.com/muonsoft/validation"
8
	"github.com/muonsoft/validation/code"
9
	"github.com/muonsoft/validation/generic"
10
	"github.com/muonsoft/validation/message"
11
)
12
13
// NumberComparisonConstraint is used for various numeric comparisons between integer and float values.
14
// Values are compared as integers if the compared and specified values are integers.
15
// Otherwise, numbers are always compared as floating point numbers.
16
type NumberComparisonConstraint struct {
17
	isIgnored       bool
18
	code            string
19
	messageTemplate string
20
	comparedValue   string
21
	isValid         func(value generic.Number) bool
22
}
23
24
// IsEqualToInteger checks that the number (integer or float) is equal to the specified integer value.
25
// Values are compared as integers if the compared and specified values are integers.
26
// Otherwise, numbers are always compared as floating point numbers.
27
//
28
// Example
29
//  v := 1
30
//  err := validator.ValidateNumber(&v, it.IsEqualToInteger(2))
31
func IsEqualToInteger(value int64) NumberComparisonConstraint {
32 1
	v := generic.NewNumberFromInt(value)
33
34 1
	return NumberComparisonConstraint{
35
		code:            code.Equal,
36
		messageTemplate: message.Equal,
37
		comparedValue:   v.String(),
38
		isValid: func(n generic.Number) bool {
39 1
			return n.IsEqualTo(v)
40
		},
41
	}
42
}
43
44
// IsEqualToFloat checks that the number (integer or float) is equal to the specified float value.
45
// Values are compared as integers if the compared and specified values are integers.
46
// Otherwise, numbers are always compared as floating point numbers.
47
//
48
// Example
49
//  v := 1.1
50
//  err := validator.ValidateNumber(&v, it.IsEqualToFloat(1.2))
51
func IsEqualToFloat(value float64) NumberComparisonConstraint {
52 1
	v := generic.NewNumberFromFloat(value)
53
54 1
	return NumberComparisonConstraint{
55
		code:            code.Equal,
56
		messageTemplate: message.Equal,
57
		comparedValue:   v.String(),
58
		isValid: func(n generic.Number) bool {
59 1
			return n.IsEqualTo(v)
60
		},
61
	}
62
}
63
64
// IsNotEqualToInteger checks that the number (integer or float) is not equal to the specified integer value.
65
// Values are compared as integers if the compared and specified values are integers.
66
// Otherwise, numbers are always compared as floating point numbers.
67
//
68
// Example
69
//  v := 1
70
//  err := validator.ValidateNumber(&v, it.IsNotEqualToInteger(1))
71
func IsNotEqualToInteger(value int64) NumberComparisonConstraint {
72 1
	v := generic.NewNumberFromInt(value)
73
74 1
	return NumberComparisonConstraint{
75
		code:            code.NotEqual,
76
		messageTemplate: message.NotEqual,
77
		comparedValue:   v.String(),
78
		isValid: func(n generic.Number) bool {
79 1
			return !n.IsEqualTo(v)
80
		},
81
	}
82
}
83
84
// IsNotEqualToFloat checks that the number (integer or float) is not equal to the specified float value.
85
// Values are compared as integers if the compared and specified values are integers.
86
// Otherwise, numbers are always compared as floating point numbers.
87
//
88
// Example
89
//  v := 1.1
90
//  err := validator.ValidateNumber(&v, it.IsNotEqualToFloat(1.1))
91
func IsNotEqualToFloat(value float64) NumberComparisonConstraint {
92 1
	v := generic.NewNumberFromFloat(value)
93
94 1
	return NumberComparisonConstraint{
95
		code:            code.NotEqual,
96
		messageTemplate: message.NotEqual,
97
		comparedValue:   v.String(),
98
		isValid: func(n generic.Number) bool {
99 1
			return !n.IsEqualTo(v)
100
		},
101
	}
102
}
103
104
// IsLessThanInteger checks that the number (integer or float) is less than the specified integer value.
105
// Values are compared as integers if the compared and specified values are integers.
106
// Otherwise, numbers are always compared as floating point numbers.
107
//
108
// Example
109
//  v := 1
110
//  err := validator.ValidateNumber(&v, it.IsLessThanInteger(1))
111
func IsLessThanInteger(value int64) NumberComparisonConstraint {
112 1
	v := generic.NewNumberFromInt(value)
113
114 1
	return NumberComparisonConstraint{
115
		code:            code.TooHigh,
116
		messageTemplate: message.TooHigh,
117
		comparedValue:   v.String(),
118
		isValid: func(n generic.Number) bool {
119 1
			return n.IsLessThan(v)
120
		},
121
	}
122
}
123
124
// IsLessThanFloat checks that the number (integer or float) is less than the specified float value.
125
// Values are compared as integers if the compared and specified values are integers.
126
// Otherwise, numbers are always compared as floating point numbers.
127
//
128
// Example
129
//  v := 1.1
130
//  err := validator.ValidateNumber(&v, it.IsLessThanFloat(1.1))
131
func IsLessThanFloat(value float64) NumberComparisonConstraint {
132 1
	v := generic.NewNumberFromFloat(value)
133
134 1
	return NumberComparisonConstraint{
135
		code:            code.TooHigh,
136
		messageTemplate: message.TooHigh,
137
		comparedValue:   v.String(),
138
		isValid: func(n generic.Number) bool {
139 1
			return n.IsLessThan(v)
140
		},
141
	}
142
}
143
144
// IsLessThanOrEqualInteger checks that the number (integer or float) is less than or
145
// equal to the specified integer value. Values are compared as integers if the compared
146
// and specified values are integers. Otherwise, numbers are always compared as floating point numbers.
147
//
148
// Example
149
//  v := 1
150
//  err := validator.ValidateNumber(&v, it.IsLessThanOrEqualInteger(2))
151
func IsLessThanOrEqualInteger(value int64) NumberComparisonConstraint {
152 1
	v := generic.NewNumberFromInt(value)
153
154 1
	return NumberComparisonConstraint{
155
		code:            code.TooHighOrEqual,
156
		messageTemplate: message.TooHighOrEqual,
157
		comparedValue:   v.String(),
158
		isValid: func(n generic.Number) bool {
159 1
			return n.IsLessThan(v) || n.IsEqualTo(v)
160
		},
161
	}
162
}
163
164
// IsLessThanOrEqualFloat checks that the number (integer or float) is less than or
165
// equal to the specified float value. Values are compared as integers if the compared
166
// and specified values are integers. Otherwise, numbers are always compared as floating point numbers.
167
//
168
// Example
169
//  v := 1.1
170
//  err := validator.ValidateNumber(&v, it.IsLessThanOrEqualFloat(1.2))
171
func IsLessThanOrEqualFloat(value float64) NumberComparisonConstraint {
172 1
	v := generic.NewNumberFromFloat(value)
173
174 1
	return NumberComparisonConstraint{
175
		code:            code.TooHighOrEqual,
176
		messageTemplate: message.TooHighOrEqual,
177
		comparedValue:   v.String(),
178
		isValid: func(n generic.Number) bool {
179 1
			return n.IsLessThan(v) || n.IsEqualTo(v)
180
		},
181
	}
182
}
183
184
// IsGreaterThanInteger checks that the number (integer or float) is greater than the specified integer value.
185
// Values are compared as integers if the compared and specified values are integers.
186
// Otherwise, numbers are always compared as floating point numbers.
187
//
188
// Example
189
//  v := 1
190
//  err := validator.ValidateNumber(&v, it.IsGreaterThanInteger(1))
191
func IsGreaterThanInteger(value int64) NumberComparisonConstraint {
192 1
	v := generic.NewNumberFromInt(value)
193
194 1
	return NumberComparisonConstraint{
195
		code:            code.TooLow,
196
		messageTemplate: message.TooLow,
197
		comparedValue:   v.String(),
198
		isValid: func(n generic.Number) bool {
199 1
			return n.IsGreaterThan(v)
200
		},
201
	}
202
}
203
204
// IsGreaterThanFloat checks that the number (integer or float) is greater than the specified float value.
205
// Values are compared as integers if the compared and specified values are integers.
206
// Otherwise, numbers are always compared as floating point numbers.
207
//
208
// Example
209
//  v := 1.1
210
//  err := validator.ValidateNumber(&v, it.IsGreaterThanFloat(1.1))
211
func IsGreaterThanFloat(value float64) NumberComparisonConstraint {
212 1
	v := generic.NewNumberFromFloat(value)
213
214 1
	return NumberComparisonConstraint{
215
		code:            code.TooLow,
216
		messageTemplate: message.TooLow,
217
		comparedValue:   v.String(),
218
		isValid: func(n generic.Number) bool {
219 1
			return n.IsGreaterThan(v)
220
		},
221
	}
222
}
223
224
// IsGreaterThanOrEqualInteger checks that the number (integer or float) is greater than or
225
// equal to the specified integer value. Values are compared as integers if the compared
226
// and specified values are integers. Otherwise, numbers are always compared as floating point numbers.
227
//
228
// Example
229
//  v := 1
230
//  err := validator.ValidateNumber(&v, it.IsGreaterThanOrEqualInteger(2))
231
func IsGreaterThanOrEqualInteger(value int64) NumberComparisonConstraint {
232 1
	v := generic.NewNumberFromInt(value)
233
234 1
	return NumberComparisonConstraint{
235
		code:            code.TooLowOrEqual,
236
		messageTemplate: message.TooLowOrEqual,
237
		comparedValue:   v.String(),
238
		isValid: func(n generic.Number) bool {
239 1
			return n.IsGreaterThan(v) || n.IsEqualTo(v)
240
		},
241
	}
242
}
243
244
// IsGreaterThanOrEqualFloat checks that the number (integer or float) is greater than or
245
// equal to the specified float value. Values are compared as integers if the compared
246
// and specified values are integers. Otherwise, numbers are always compared as floating point numbers.
247
//
248
// Example
249
//  v := 1.1
250
//  err := validator.ValidateNumber(&v, it.IsGreaterThanOrEqualFloat(1.2))
251
func IsGreaterThanOrEqualFloat(value float64) NumberComparisonConstraint {
252 1
	v := generic.NewNumberFromFloat(value)
253
254 1
	return NumberComparisonConstraint{
255
		code:            code.TooLowOrEqual,
256
		messageTemplate: message.TooLowOrEqual,
257
		comparedValue:   v.String(),
258
		isValid: func(n generic.Number) bool {
259 1
			return n.IsGreaterThan(v) || n.IsEqualTo(v)
260
		},
261
	}
262
}
263
264
// IsPositive checks that the value is a positive number (integer or float). Zero is neither
265
// positive nor negative. If you want to allow zero use IsPositiveOrZero comparison.
266
//
267
// Example
268
//  v := -1
269
//  err := validator.ValidateNumber(&v, it.IsPositive())
270
func IsPositive() NumberComparisonConstraint {
271 1
	v := generic.NewNumberFromInt(0)
272
273 1
	return NumberComparisonConstraint{
274
		code:            code.NotPositive,
275
		messageTemplate: message.NotPositive,
276
		comparedValue:   v.String(),
277
		isValid: func(n generic.Number) bool {
278 1
			return n.IsGreaterThan(v)
279
		},
280
	}
281
}
282
283
// IsPositiveOrZero checks that the value is a positive number (integer or float) or equal to zero.
284
// If you don't want to allow zero as a valid value, use IsPositive comparison.
285
//
286
// Example
287
//  v := -1
288
//  err := validator.ValidateNumber(&v, it.IsPositiveOrZero())
289
func IsPositiveOrZero() NumberComparisonConstraint {
290 1
	v := generic.NewNumberFromInt(0)
291
292 1
	return NumberComparisonConstraint{
293
		code:            code.NotPositiveOrZero,
294
		messageTemplate: message.NotPositiveOrZero,
295
		comparedValue:   v.String(),
296
		isValid: func(n generic.Number) bool {
297 1
			return n.IsGreaterThan(v) || n.IsEqualTo(v)
298
		},
299
	}
300
}
301
302
// IsNegative checks that the value is a negative number (integer or float). Zero is neither
303
// positive nor negative. If you want to allow zero use IsNegativeOrZero comparison.
304
//
305
// Example
306
//  v := 1
307
//  err := validator.ValidateNumber(&v, it.IsNegative())
308
func IsNegative() NumberComparisonConstraint {
309 1
	v := generic.NewNumberFromInt(0)
310
311 1
	return NumberComparisonConstraint{
312
		code:            code.NotNegative,
313
		messageTemplate: message.NotNegative,
314
		comparedValue:   v.String(),
315
		isValid: func(n generic.Number) bool {
316 1
			return n.IsLessThan(v)
317
		},
318
	}
319
}
320
321
// IsNegativeOrZero checks that the value is a negative number (integer or float) or equal to zero.
322
// If you don't want to allow zero as a valid value, use IsNegative comparison.
323
//
324
// Example
325
//  v := -1
326
//  err := validator.ValidateNumber(&v, it.IsNegativeOrZero())
327
func IsNegativeOrZero() NumberComparisonConstraint {
328 1
	v := generic.NewNumberFromInt(0)
329
330 1
	return NumberComparisonConstraint{
331
		code:            code.NotNegativeOrZero,
332
		messageTemplate: message.NotNegativeOrZero,
333
		comparedValue:   v.String(),
334
		isValid: func(n generic.Number) bool {
335 1
			return n.IsLessThan(v) || n.IsEqualTo(v)
336
		},
337
	}
338
}
339
340
// SetUp always returns no error.
341
func (c NumberComparisonConstraint) SetUp() error {
342 1
	return nil
343
}
344
345
// Name is the constraint name.
346
func (c NumberComparisonConstraint) Name() string {
347
	return "NumberComparisonConstraint"
348
}
349
350
// Message sets the violation message template. You can use template parameters
351
// for injecting its values into the final message:
352
//
353
//  {{ comparedValue }} - the expected value;
354
//  {{ value }} - the current (invalid) value.
355
func (c NumberComparisonConstraint) Message(message string) NumberComparisonConstraint {
356 1
	c.messageTemplate = message
357 1
	return c
358
}
359
360
// When enables conditional validation of this constraint. If the expression evaluates to false,
361
// then the constraint will be ignored.
362
func (c NumberComparisonConstraint) When(condition bool) NumberComparisonConstraint {
363 1
	c.isIgnored = !condition
364 1
	return c
365
}
366
367
func (c NumberComparisonConstraint) ValidateNumber(value generic.Number, scope validation.Scope) error {
368 1
	if c.isIgnored || value.IsNil() || c.isValid(value) {
369 1
		return nil
370
	}
371
372 1
	return scope.BuildViolation(c.code, c.messageTemplate).
373
		SetParameters([]validation.TemplateParameter{
374
			{Key: "{{ comparedValue }}", Value: c.comparedValue},
375
			{Key: "{{ value }}", Value: value.String()},
376
		}).
377
		CreateViolation()
378
}
379
380
// StringComparisonConstraint is used to compare strings.
381
type StringComparisonConstraint struct {
382
	isIgnored       bool
383
	code            string
384
	messageTemplate string
385
	comparedValue   string
386
	isValid         func(value string) bool
387
}
388
389
// IsEqualToString checks that the string value is equal to the specified string value.
390
//
391
// Example
392
//  v := "actual"
393
//  err := validator.ValidateString(&v, it.IsEqualToString("expected"))
394
func IsEqualToString(value string) StringComparisonConstraint {
395 1
	return StringComparisonConstraint{
396
		code:            code.Equal,
397
		messageTemplate: message.Equal,
398
		comparedValue:   value,
399
		isValid: func(actualValue string) bool {
400 1
			return value == actualValue
401
		},
402
	}
403
}
404
405
// IsNotEqualToString checks that the string value is not equal to the specified string value.
406
//
407
// Example
408
//  v := "expected"
409
//  err := validator.ValidateString(&v, it.IsNotEqualToString("expected"))
410
func IsNotEqualToString(value string) StringComparisonConstraint {
411 1
	return StringComparisonConstraint{
412
		code:            code.NotEqual,
413
		messageTemplate: message.NotEqual,
414
		comparedValue:   value,
415
		isValid: func(actualValue string) bool {
416 1
			return value != actualValue
417
		},
418
	}
419
}
420
421
// SetUp always returns no error.
422
func (c StringComparisonConstraint) SetUp() error {
423 1
	return nil
424
}
425
426
// Name is the constraint name.
427
func (c StringComparisonConstraint) Name() string {
428
	return "StringComparisonConstraint"
429
}
430
431
// Message sets the violation message template. You can use template parameters
432
// for injecting its values into the final message:
433
//
434
//  {{ comparedValue }} - the expected value;
435
//  {{ value }} - the current (invalid) value.
436
//
437
// All string values are quoted strings.
438
func (c StringComparisonConstraint) Message(message string) StringComparisonConstraint {
439 1
	c.messageTemplate = message
440 1
	return c
441
}
442
443
// When enables conditional validation of this constraint. If the expression evaluates to false,
444
// then the constraint will be ignored.
445
func (c StringComparisonConstraint) When(condition bool) StringComparisonConstraint {
446 1
	c.isIgnored = !condition
447 1
	return c
448
}
449
450
func (c StringComparisonConstraint) ValidateString(value *string, scope validation.Scope) error {
451 1
	if c.isIgnored || value == nil || c.isValid(*value) {
452 1
		return nil
453
	}
454
455 1
	return scope.BuildViolation(c.code, c.messageTemplate).
456
		SetParameters([]validation.TemplateParameter{
457
			{Key: "{{ comparedValue }}", Value: strconv.Quote(c.comparedValue)},
458
			{Key: "{{ value }}", Value: strconv.Quote(*value)},
459
		}).
460
		CreateViolation()
461
}
462
463
// TimeComparisonConstraint is used to compare time values.
464
type TimeComparisonConstraint struct {
465
	isIgnored       bool
466
	code            string
467
	messageTemplate string
468
	comparedValue   time.Time
469
	layout          string
470
	isValid         func(value time.Time) bool
471
}
472
473
// IsEarlierThan checks that the given time is earlier than the specified value.
474
//
475
// Example
476
//  t := time.Now()
477
//  err := validator.ValidateTime(&t, it.IsEarlierThan(time.Now().Add(time.Hour)))
478
func IsEarlierThan(value time.Time) TimeComparisonConstraint {
479 1
	return TimeComparisonConstraint{
480
		code:            code.TooLate,
481
		messageTemplate: message.TooLate,
482
		comparedValue:   value,
483
		layout:          time.RFC3339,
484
		isValid: func(actualValue time.Time) bool {
485 1
			return actualValue.Before(value)
486
		},
487
	}
488
}
489
490
// IsEarlierThanOrEqual checks that the given time is earlier or equal to the specified value.
491
//
492
// Example
493
//  t := time.Now()
494
//  err := validator.ValidateTime(&t, it.IsEarlierThanOrEqual(time.Now().Add(time.Hour)))
495
func IsEarlierThanOrEqual(value time.Time) TimeComparisonConstraint {
496 1
	return TimeComparisonConstraint{
497
		code:            code.TooLateOrEqual,
498
		messageTemplate: message.TooLateOrEqual,
499
		comparedValue:   value,
500
		layout:          time.RFC3339,
501
		isValid: func(actualValue time.Time) bool {
502 1
			return actualValue.Before(value) || actualValue == value
503
		},
504
	}
505
}
506
507
// IsLaterThan checks that the given time is later than the specified value.
508
//
509
// Example
510
//  t := time.Now()
511
//  err := validator.ValidateTime(&t, it.IsLaterThan(time.Now().Sub(time.Hour)))
512
func IsLaterThan(value time.Time) TimeComparisonConstraint {
513 1
	return TimeComparisonConstraint{
514
		code:            code.TooEarly,
515
		messageTemplate: message.TooEarly,
516
		comparedValue:   value,
517
		layout:          time.RFC3339,
518
		isValid: func(actualValue time.Time) bool {
519 1
			return actualValue.After(value)
520
		},
521
	}
522
}
523
524
// IsLaterThanOrEqual checks that the given time is later or equal to the specified value.
525
//
526
// Example
527
//  t := time.Now()
528
//  err := validator.ValidateTime(&t, it.IsLaterThanOrEqual(time.Now().Sub(time.Hour)))
529
func IsLaterThanOrEqual(value time.Time) TimeComparisonConstraint {
530 1
	return TimeComparisonConstraint{
531
		code:            code.TooEarlyOrEqual,
532
		messageTemplate: message.TooEarlyOrEqual,
533
		comparedValue:   value,
534
		layout:          time.RFC3339,
535
		isValid: func(actualValue time.Time) bool {
536 1
			return actualValue.After(value) || actualValue == value
537
		},
538
	}
539
}
540
541
// SetUp always returns no error.
542
func (c TimeComparisonConstraint) SetUp() error {
543 1
	return nil
544
}
545
546
// Name is the constraint name.
547
func (c TimeComparisonConstraint) Name() string {
548
	return "TimeComparisonConstraint"
549
}
550
551
// Message sets the violation message template. You can use template parameters
552
// for injecting its values into the final message:
553
//
554
//  {{ comparedValue }} - the expected value;
555
//  {{ value }} - the current (invalid) value.
556
//
557
// All values are formatted by the layout that can be defined by the Layout method.
558
// Default layout is time.RFC3339.
559
func (c TimeComparisonConstraint) Message(message string) TimeComparisonConstraint {
560 1
	c.messageTemplate = message
561 1
	return c
562
}
563
564
// Layout can be used to set the layout that is used to format time values.
565
func (c TimeComparisonConstraint) Layout(layout string) TimeComparisonConstraint {
566 1
	c.layout = layout
567 1
	return c
568
}
569
570
// When enables conditional validation of this constraint. If the expression evaluates to false,
571
// then the constraint will be ignored.
572
func (c TimeComparisonConstraint) When(condition bool) TimeComparisonConstraint {
573 1
	c.isIgnored = !condition
574 1
	return c
575
}
576
577
func (c TimeComparisonConstraint) ValidateTime(value *time.Time, scope validation.Scope) error {
578 1
	if c.isIgnored || value == nil || c.isValid(*value) {
579 1
		return nil
580
	}
581
582 1
	return scope.BuildViolation(c.code, c.messageTemplate).
583
		SetParameters([]validation.TemplateParameter{
584
			{Key: "{{ comparedValue }}", Value: c.comparedValue.Format(c.layout)},
585
			{Key: "{{ value }}", Value: value.Format(c.layout)},
586
		}).
587
		CreateViolation()
588
}
589