Passed
Pull Request — main (#25)
by Rushan
01:59
created

it.Matches   A

Complexity

Conditions 1

Size

Total Lines 5
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

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