Test Failed
Pull Request — main (#74)
by Igor
02:02
created

it.CountConstraint.WithMinError   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
crap 1
nop 1
1
package it
2
3
import (
4
	"strconv"
5
6
	"github.com/muonsoft/validation"
7
)
8
9
// CountConstraint checks that a given collection's (array, slice or a map) length is between some minimum and
10
// maximum value.
11
type CountConstraint struct {
12
	isIgnored              bool
13
	checkMin               bool
14
	checkMax               bool
15
	min                    int
16
	max                    int
17
	groups                 []string
18
	minErr                 error
19
	maxErr                 error
20
	exactErr               error
21
	minMessageTemplate     string
22
	minMessageParameters   validation.TemplateParameterList
23
	maxMessageTemplate     string
24
	maxMessageParameters   validation.TemplateParameterList
25
	exactMessageTemplate   string
26
	exactMessageParameters validation.TemplateParameterList
27
}
28
29
func newCountConstraint(min int, max int, checkMin bool, checkMax bool) CountConstraint {
30
	return CountConstraint{
31
		min:                  min,
32
		max:                  max,
33 1
		checkMin:             checkMin,
34
		checkMax:             checkMax,
35
		minErr:               validation.ErrTooFewElements,
36
		maxErr:               validation.ErrTooManyElements,
37
		exactErr:             validation.ErrNotExactCount,
38
		minMessageTemplate:   validation.ErrTooFewElements.Template(),
39
		maxMessageTemplate:   validation.ErrTooManyElements.Template(),
40
		exactMessageTemplate: validation.ErrNotExactCount.Template(),
41
	}
42
}
43
44
// HasMinCount creates a CountConstraint that checks the length of the iterable (slice, array, or map)
45
// is greater than the minimum value.
46
func HasMinCount(min int) CountConstraint {
47
	return newCountConstraint(min, 0, true, false)
48
}
49
50 1
// HasMaxCount creates a CountConstraint that checks the length of the iterable (slice, array, or map)
51
// is less than the maximum value.
52
func HasMaxCount(max int) CountConstraint {
53
	return newCountConstraint(0, max, false, true)
54
}
55
56 1
// HasCountBetween creates a CountConstraint that checks the length of the iterable (slice, array, or map)
57
// is between some minimum and maximum value.
58
func HasCountBetween(min int, max int) CountConstraint {
59
	return newCountConstraint(min, max, true, true)
60
}
61
62 1
// HasExactCount creates a CountConstraint that checks the length of the iterable (slice, array, or map)
63
// has exact value.
64
func HasExactCount(count int) CountConstraint {
65
	return newCountConstraint(count, count, true, true)
66
}
67
68 1
// When enables conditional validation of this constraint. If the expression evaluates to false,
69
// then the constraint will be ignored.
70
func (c CountConstraint) When(condition bool) CountConstraint {
71
	c.isIgnored = !condition
72
	return c
73 1
}
74
75
// WhenGroups enables conditional validation of the constraint by using the validation groups.
76
func (c CountConstraint) WhenGroups(groups ...string) CountConstraint {
77
	c.groups = groups
78
	return c
79
}
80
81
// WithMinError overrides default underlying error for violation that will be shown if the
82
// collection length is less than the minimum value.
83
func (c CountConstraint) WithMinError(err error) CountConstraint {
84 1
	c.minErr = err
85 1
	return c
86
}
87
88
// WithMaxError overrides default underlying error for violation that will be shown if the
89
// collection length is greater than the maximum value.
90 1
func (c CountConstraint) WithMaxError(err error) CountConstraint {
91 1
	c.maxErr = err
92
	return c
93
}
94
95
// WithExactError overrides default underlying error for violation that will be shown if minimum and
96
// maximum values are equal and the length of the collection is not exactly this value.
97 1
func (c CountConstraint) WithExactError(err error) CountConstraint {
98 1
	c.exactErr = err
99
	return c
100
}
101
102
// WithMinMessage sets the violation message that will be shown if the collection length is less than
103
// the minimum value. You can set custom template parameters for injecting its values
104 1
// into the final message. Also, you can use default parameters:
105 1
//
106
//	{{ count }} - the current collection size;
107
//	{{ limit }} - the lower limit.
108
func (c CountConstraint) WithMinMessage(template string, parameters ...validation.TemplateParameter) CountConstraint {
109
	c.minMessageTemplate = template
110
	c.minMessageParameters = parameters
111 1
	return c
112 1
}
113
114
// WithMaxMessage sets the violation message that will be shown if the collection length is greater than
115
// the maximum value. You can set custom template parameters for injecting its values
116
// into the final message. Also, you can use default parameters:
117
//
118
//	{{ count }} - the current collection size;
119
//	{{ limit }} - the upper limit.
120
func (c CountConstraint) WithMaxMessage(template string, parameters ...validation.TemplateParameter) CountConstraint {
121
	c.maxMessageTemplate = template
122 1
	c.maxMessageParameters = parameters
123 1
	return c
124 1
}
125
126
// WithExactMessage sets the violation message that will be shown if minimum and maximum values are equal and
127
// the length of the collection is not exactly this value. You can set custom template parameters
128
// for injecting its values into the final message. Also, you can use default parameters:
129
//
130
//	{{ count }} - the current collection size;
131
//	{{ limit }} - the exact expected collection size.
132
func (c CountConstraint) WithExactMessage(template string, parameters ...validation.TemplateParameter) CountConstraint {
133
	c.exactMessageTemplate = template
134 1
	c.exactMessageParameters = parameters
135 1
	return c
136 1
}
137
138
func (c CountConstraint) ValidateCountable(count int, scope validation.Scope) error {
139
	if c.isIgnored || scope.IsIgnored(c.groups...) {
140
		return nil
141
	}
142
	if c.checkMax && count > c.max {
143
		return c.newViolation(count, c.max, c.maxErr, c.maxMessageTemplate, c.maxMessageParameters, scope)
144
	}
145
	if c.checkMin && count < c.min {
146 1
		return c.newViolation(count, c.min, c.minErr, c.minMessageTemplate, c.minMessageParameters, scope)
147 1
	}
148 1
149
	return nil
150
}
151
152 1
func (c CountConstraint) newViolation(
153
	count, limit int,
154
	err error,
155
	template string,
156 1
	parameters validation.TemplateParameterList,
157 1
	scope validation.Scope,
158
) validation.Violation {
159 1
	if c.checkMin && c.checkMax && c.min == c.max {
160 1
		template = c.exactMessageTemplate
161
		parameters = c.exactMessageParameters
162 1
		err = c.exactErr
163 1
	}
164
165
	return scope.BuildViolation(err, template).
166 1
		WithPluralCount(limit).
167
		WithParameters(
168
			parameters.Prepend(
169
				validation.TemplateParameter{Key: "{{ count }}", Value: strconv.Itoa(count)},
170
				validation.TemplateParameter{Key: "{{ limit }}", Value: strconv.Itoa(limit)},
171
			)...,
172
		).
173
		Create()
174
}
175