Test Failed
Pull Request — main (#25)
by Rushan
01:51
created

it.RegexConstraint.SetUp   A

Complexity

Conditions 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 7
dl 0
loc 11
ccs 0
cts 0
cp 0
crap 12
rs 10
c 0
b 0
f 0
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
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 1
func newLengthConstraint(min int, max int, checkMin bool, checkMax bool) LengthConstraint {
26
	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 1
func HasMinLength(min int) LengthConstraint {
38
	return newLengthConstraint(min, 0, true, false)
39
}
40
41 1
func HasMaxLength(max int) LengthConstraint {
42
	return newLengthConstraint(0, max, false, true)
43
}
44
45
func HasLengthBetween(min int, max int) LengthConstraint {
46
	return newLengthConstraint(min, max, true, true)
47
}
48
49
func HasExactLength(count int) LengthConstraint {
50
	return newLengthConstraint(count, count, true, true)
51
}
52
53 1
func (c LengthConstraint) SetUp() error {
54
	return nil
55
}
56
57
func (c LengthConstraint) Name() string {
58
	return "LengthConstraint"
59
}
60
61 1
func (c LengthConstraint) When(condition bool) LengthConstraint {
62 1
	c.isIgnored = !condition
63
	return c
64
}
65
66 1
func (c LengthConstraint) MinMessage(message string) LengthConstraint {
67 1
	c.minMessageTemplate = message
68
	return c
69
}
70
71
func (c LengthConstraint) MaxMessage(message string) LengthConstraint {
72
	c.maxMessageTemplate = message
73
	return c
74
}
75
76
func (c LengthConstraint) ExactMessage(message string) LengthConstraint {
77
	c.exactMessageTemplate = message
78
	return c
79
}
80
81 1
func (c LengthConstraint) ValidateString(value *string, scope validation.Scope) error {
82 1
	if c.isIgnored || value == nil || *value == "" {
83
		return nil
84
	}
85 1
86
	count := utf8.RuneCountInString(*value)
87 1
88 1
	if c.checkMax && count > c.max {
89
		return c.newViolation(count, c.max, code.LengthTooMany, c.maxMessageTemplate, scope)
90 1
	}
91 1
	if c.checkMin && count < c.min {
92
		return c.newViolation(count, c.min, code.LengthTooFew, c.minMessageTemplate, scope)
93
	}
94 1
95
	return nil
96
}
97
98
func (c LengthConstraint) newViolation(
99
	count, limit int,
100
	violationCode, message string,
101
	scope validation.Scope,
102 1
) validation.Violation {
103
	if c.checkMin && c.checkMax && c.min == c.max {
104
		message = c.exactMessageTemplate
105
		violationCode = code.LengthExact
106
	}
107 1
108
	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("^[a-z]+$"))
129
func Matches(pattern string) RegexConstraint {
130
	return RegexConstraint{
131
		regex:           regex,
132
		match:           true,
133
		messageTemplate: message.NotValid,
134
	}
135
}
136
137
// SetUp will return an error if the pattern is empty.
138
func (c RegexConstraint) SetUp() error {
139
	if c.regex == nil {
140
		return errEmptyRegex
141
	}
142
143
	regex, err := regexp.Compile(c.pattern)
144
	if err != nil {
145
		return errInvalidPattern
146
	}
147
148
	return nil
149
}
150
151
// Name is the constraint name.
152
func (c RegexConstraint) Name() string {
153
	return "RegexConstraint"
154
}
155
156
// Message sets the violation message template. You can use template parameters.
157
// for injecting its values into the final message:
158
//
159
//	{{ value }} - the current (invalid) value.
160
func (c RegexConstraint) Message(message string) RegexConstraint {
161
	c.messageTemplate = message
162
	return c
163
}
164
165
// When enables conditional validation of this constraint. If the expression evaluates to false,
166
// then the constraint will be ignored.
167
func (c RegexConstraint) When(condition bool) RegexConstraint {
168
	c.isIgnored = !condition
169
	return c
170
}
171
172
func (c RegexConstraint) ValidateString(value *string, scope validation.Scope) error {
173
	if c.isIgnored || value == nil || *value == "" {
174
		return nil
175
	}
176
177
	if !(c.match != c.regex.MatchString(*value)) {
178
		return nil
179
	}
180
181
	return scope.
182
		BuildViolation(code.MatchingFailed, c.messageTemplate).
183
		SetParameter("{{ value }}", *value).
184
		CreateViolation()
185
}
186