Passed
Push — main ( 6408ea...b3a0a2 )
by Igor
02:30 queued 14s
created

it.RegexConstraint.Name   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
dl 0
loc 2
c 0
b 0
f 0
ccs 1
cts 1
cp 1
crap 1
rs 10
nop 0
1
package it
2
3
import (
4
	"github.com/muonsoft/validation"
5
	"github.com/muonsoft/validation/code"
6
	"github.com/muonsoft/validation/message"
7
8
	"regexp"
9
	"strconv"
10
	"unicode/utf8"
11
)
12
13
// LengthConstraint checks that a given string length is between some minimum and maximum value.
14
// If you want to check the length of the array, slice or a map use CountConstraint.
15
type LengthConstraint struct {
16
	isIgnored            bool
17
	checkMin             bool
18
	checkMax             bool
19
	min                  int
20
	max                  int
21
	minMessageTemplate   string
22
	maxMessageTemplate   string
23
	exactMessageTemplate string
24
}
25
26
func newLengthConstraint(min int, max int, checkMin bool, checkMax bool) LengthConstraint {
27 1
	return LengthConstraint{
28
		min:                  min,
29
		max:                  max,
30
		checkMin:             checkMin,
31
		checkMax:             checkMax,
32
		minMessageTemplate:   message.LengthTooFew,
33
		maxMessageTemplate:   message.LengthTooMany,
34
		exactMessageTemplate: message.LengthExact,
35
	}
36
}
37
38
// HasMinLength creates a LengthConstraint that checks the length of the string
39
// is greater than the minimum value.
40
//
41
// Example
42
//  v := "foo"
43
//  err := validator.ValidateString(&v, it.HasMinLength(5))
44
func HasMinLength(min int) LengthConstraint {
45 1
	return newLengthConstraint(min, 0, true, false)
46
}
47
48
// HasMaxLength creates a LengthConstraint that checks the length of the string
49
// is less than the maximum value.
50
//
51
// Example
52
//  v := "foo"
53
//  err := validator.ValidateString(&v, it.HasMaxLength(2))
54
func HasMaxLength(max int) LengthConstraint {
55 1
	return newLengthConstraint(0, max, false, true)
56
}
57
58
// HasLengthBetween creates a LengthConstraint that checks the length of the string
59
// is between some minimum and maximum value.
60
//
61
// Example
62
//  v := "foo"
63
//  err := validator.ValidateString(&v, it.HasLengthBetween(5, 10))
64
func HasLengthBetween(min int, max int) LengthConstraint {
65 1
	return newLengthConstraint(min, max, true, true)
66
}
67
68
// HasExactLength creates a LengthConstraint that checks the length of the string
69
// has exact value.
70
//
71
// Example
72
//  v := "foo"
73
//  err := validator.ValidateString(&v, it.HasExactLength(5))
74
func HasExactLength(count int) LengthConstraint {
75 1
	return newLengthConstraint(count, count, true, true)
76
}
77
78
// Name is the constraint name.
79
func (c LengthConstraint) Name() string {
80
	return "LengthConstraint"
81
}
82
83
// SetUp always returns no error.
84
func (c LengthConstraint) SetUp() error {
85 1
	return nil
86
}
87
88
// When enables conditional validation of this constraint. If the expression evaluates to false,
89
// then the constraint will be ignored.
90
func (c LengthConstraint) When(condition bool) LengthConstraint {
91 1
	c.isIgnored = !condition
92 1
	return c
93
}
94
95
// MinMessage sets the violation message that will be shown if the string length is less than
96
// the minimum value.
97
func (c LengthConstraint) MinMessage(message string) LengthConstraint {
98 1
	c.minMessageTemplate = message
99 1
	return c
100
}
101
102
// MaxMessage sets the violation message that will be shown if the string length is greater than
103
// the maximum value.
104
func (c LengthConstraint) MaxMessage(message string) LengthConstraint {
105 1
	c.maxMessageTemplate = message
106 1
	return c
107
}
108
109
// ExactMessage sets the violation message that will be shown if minimum and maximum values are equal and
110
// the length of the string is not exactly this value.
111
func (c LengthConstraint) ExactMessage(message string) LengthConstraint {
112 1
	c.exactMessageTemplate = message
113 1
	return c
114
}
115
116
func (c LengthConstraint) ValidateString(value *string, scope validation.Scope) error {
117 1
	if c.isIgnored || value == nil || *value == "" {
118 1
		return nil
119
	}
120
121 1
	count := utf8.RuneCountInString(*value)
122
123 1
	if c.checkMax && count > c.max {
124 1
		return c.newViolation(count, c.max, code.LengthTooMany, c.maxMessageTemplate, scope)
125
	}
126 1
	if c.checkMin && count < c.min {
127 1
		return c.newViolation(count, c.min, code.LengthTooFew, c.minMessageTemplate, scope)
128
	}
129
130 1
	return nil
131
}
132
133
func (c LengthConstraint) newViolation(
134
	count, limit int,
135
	violationCode, message string,
136
	scope validation.Scope,
137
) validation.Violation {
138 1
	if c.checkMin && c.checkMax && c.min == c.max {
139 1
		message = c.exactMessageTemplate
140 1
		violationCode = code.LengthExact
141
	}
142
143 1
	return scope.BuildViolation(violationCode, message).
144
		SetPluralCount(limit).
145
		SetParameters(map[string]string{
146
			"{{ count }}": strconv.Itoa(count),
147
			"{{ limit }}": strconv.Itoa(limit),
148
		}).
149
		CreateViolation()
150
}
151
152
// RegexConstraint is used to ensure that the given value corresponds to regex pattern.
153
type RegexConstraint struct {
154
	isIgnored       bool
155
	match           bool
156
	messageTemplate string
157
	regex           *regexp.Regexp
158
}
159
160
// Matches creates a RegexConstraint for checking whether a value match.
161
//
162
// Example
163
//	err := validator.ValidateString(&s, it.Matches(regexp.MustCompile("^[a-z]+$")))
164
func Matches(regex *regexp.Regexp) RegexConstraint {
165 1
	return RegexConstraint{
166
		regex:           regex,
167
		match:           true,
168
		messageTemplate: message.NotValid,
169
	}
170
}
171
172
// Matches creates a RegexConstraint for checking whether a value not match.
173
//
174
// Example
175
//	err := validator.ValidateString(&s, it.DoesNotMatch(regexp.MustCompile("^[a-z]+$")))
176
func DoesNotMatch(regex *regexp.Regexp) RegexConstraint {
177 1
	return RegexConstraint{
178
		regex:           regex,
179
		match:           false,
180
		messageTemplate: message.NotValid,
181
	}
182
}
183
184
// SetUp will return an error if the pattern is empty.
185
func (c RegexConstraint) SetUp() error {
186 1
	if c.regex == nil {
187 1
		return errEmptyRegex
188
	}
189
190 1
	return nil
191
}
192
193
// Name is the constraint name.
194
func (c RegexConstraint) Name() string {
195 1
	return "RegexConstraint"
196
}
197
198
// Message sets the violation message template. You can use template parameters.
199
// for injecting its values into the final message:
200
//
201
//	{{ value }} - the current (invalid) value.
202
func (c RegexConstraint) Message(message string) RegexConstraint {
203 1
	c.messageTemplate = message
204 1
	return c
205
}
206
207
// When enables conditional validation of this constraint. If the expression evaluates to false,
208
// then the constraint will be ignored.
209
func (c RegexConstraint) When(condition bool) RegexConstraint {
210 1
	c.isIgnored = !condition
211 1
	return c
212
}
213
214
func (c RegexConstraint) ValidateString(value *string, scope validation.Scope) error {
215 1
	if c.isIgnored || value == nil || *value == "" {
216 1
		return nil
217
	}
218
219 1
	if !(c.match != c.regex.MatchString(*value)) {
220 1
		return nil
221
	}
222
223 1
	return scope.
224
		BuildViolation(code.MatchingFailed, c.messageTemplate).
225
		SetParameter("{{ value }}", *value).
226
		CreateViolation()
227
}
228