Skip to content

Commit 3ec9f4b

Browse files
tiagoacardosothedevsaddam
authored andcommitted
Added Mac Address validator (#69)
* Added Mac Address validator * Fixed typo adress instead of address * Fixed tests for mac address message error
1 parent dde5f75 commit 3ec9f4b

7 files changed

+143
-32
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ Send request to the server using curl or postman: `curl GET "http://localhost:90
150150
* `not_in:foo,bar` The field under validation must have one value except foo,bar. e.g: `not_in:admin,manager,user` must not contain the values (admin or manager or user)
151151
* `email` The field under validation must have a valid email.
152152
* `float` The field under validation must have a valid float number.
153+
* `mac_address` The field under validation must have be a valid Mac Address.
153154
* `min:numeric` The field under validation must have a min length of characters for string, items length for slice/map, value for integer or float.
154155
e.g: `min:3` may contains characters minimum length of 3 like `"john", "jane", "jane321"` but not `"mr", "xy"`
155156
* `max:numeric` The field under validation must have a max length of characters for string, items length for slice/map, value for integer or float.

doc/BENCHMARK.md

+33-32
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,37 @@
11
Benchmarks
22
===================
33

4-
Machine: Mac Book Pro-2015 2.7GHz 8GB
5-
Go version: go1.8.1 darwin/amd64
4+
Machine: XPS 13 9370 (07E6)
5+
Go version: go version go1.12.6 linux/amd64
66

7-
| ➜ go test -run=XXX -bench=. -benchmem=true | | | | |
8-
|--------------------------------------------|-----------|------------|-----------|--------------|
9-
| Benchmark_IsAlpha-4 | 5000000 | 323 ns/op | 0 B/op | 0 allocs/op |
10-
| Benchmark_IsAlphaDash-4 | 3000000 | 415 ns/op | 0 B/op | 0 allocs/op |
11-
| Benchmark_IsAlphaNumeric-4 | 5000000 | 338 ns/op | 0 B/op | 0 allocs/op |
12-
| Benchmark_IsBoolean-4 | 100000000 | 10.6 ns/op | 0 B/op | 0 allocs/op |
13-
| Benchmark_IsCreditCard-4 | 3000000 | 543 ns/op | 0 B/op | 0 allocs/op |
14-
| Benchmark_IsCoordinate-4 | 2000000 | 950 ns/op | 0 B/op | 0 allocs/op |
15-
| Benchmark_IsCSSColor-4 | 5000000 | 300 ns/op | 0 B/op | 0 allocs/op |
16-
| Benchmark_IsDate-4 | 2000000 | 719 ns/op | 0 B/op | 0 allocs/op |
17-
| Benchmark_IsDateDDMMYY-4 | 3000000 | 481 ns/op | 0 B/op | 0 allocs/op |
18-
| Benchmark_IsEmail-4 | 1000000 | 1172 ns/op | 0 B/op | 0 allocs/op |
19-
| Benchmark_IsFloat-4 | 3000000 | 432 ns/op | 0 B/op | 0 allocs/op |
20-
| Benchmark_IsIn-4 | 200000000 | 7.34 ns/op | 0 B/op | 0 allocs/op |
21-
| Benchmark_IsJSON-4 | 1000000 | 1595 ns/op | 768 B/op | 12 allocs/op |
22-
| Benchmark_IsNumeric-4 | 10000000 | 195 ns/op | 0 B/op | 0 allocs/op |
23-
| Benchmark_IsLatitude-4 | 3000000 | 523 ns/op | 0 B/op | 0 allocs/op |
24-
| Benchmark_IsLongitude-4 | 3000000 | 516 ns/op | 0 B/op | 0 allocs/op |
25-
| Benchmark_IsIP-4 | 1000000 | 1073 ns/op | 0 B/op | 0 allocs/op |
26-
| Benchmark_IsIPV4-4 | 3000000 | 580 ns/op | 0 B/op | 0 allocs/op |
27-
| Benchmark_IsIPV6-4 | 1000000 | 1288 ns/op | 0 B/op | 0 allocs/op |
28-
| Benchmark_IsMatchedRegex-4 | 200000 | 7133 ns/op | 5400 B/op | 66 allocs/op |
29-
| Benchmark_IsURL-4 | 1000000 | 1159 ns/op | 0 B/op | 0 allocs/op |
30-
| Benchmark_IsUUID-4 | 2000000 | 832 ns/op | 0 B/op | 0 allocs/op |
31-
| Benchmark_IsUUID3-4 | 2000000 | 783 ns/op | 0 B/op | 0 allocs/op |
32-
| Benchmark_IsUUID4-4 | 2000000 | 899 ns/op | 0 B/op | 0 allocs/op |
33-
| Benchmark_IsUUID5-4 | 2000000 | 828 ns/op | 0 B/op | 0 allocs/op |
34-
| BenchmarkRoller_Start-4 | 200000 | 6869 ns/op | 2467 B/op | 28 allocs/op |
35-
| Benchmark_isContainRequiredField-4 | 300000000 | 4.23 ns/op | 0 B/op | 0 allocs/op |
36-
| Benchmark_Validate-4 | 200000 | 9347 ns/op | 664 B/op | 28 allocs/op |
7+
| ➜ go test -run=XXX -bench=. -benchmem=true | | | | |
8+
|--------------------------------------------|------------|--------------|--------------|--------------|
9+
|Benchmark_IsAlpha-8 | 10000000 | 205 ns/op | 0 B/op | 0 allocs/op |
10+
|Benchmark_IsAlphaDash-8 | 5000000 | 268 ns/op | 0 B/op | 0 allocs/op |
11+
|Benchmark_IsAlphaNumeric-8 | 10000000 | 182 ns/op | 0 B/op | 0 allocs/op |
12+
|Benchmark_IsBoolean-8 | 200000000 | 6.84 ns/op | 0 B/op | 0 allocs/op |
13+
|Benchmark_IsCreditCard-8 | 10000000 | 243 ns/op | 0 B/op | 0 allocs/op |
14+
|Benchmark_IsCoordinate-8 | 3000000 | 482 ns/op | 0 B/op | 0 allocs/op |
15+
|Benchmark_IsCSSColor-8 | 10000000 | 160 ns/op | 0 B/op | 0 allocs/op |
16+
|Benchmark_IsDate-8 | 3000000 | 531 ns/op | 0 B/op | 0 allocs/op |
17+
|Benchmark_IsDateDDMMYY-8 | 5000000 | 246 ns/op | 0 B/op | 0 allocs/op |
18+
|Benchmark_IsEmail-8 | 3000000 | 549 ns/op | 0 B/op | 0 allocs/op |
19+
|Benchmark_IsFloat-8 | 10000000 | 199 ns/op | 0 B/op | 0 allocs/op |
20+
|Benchmark_IsIn-8 | 5000000 | 3.77 ns/op | 0 B/op | 0 allocs/op |
21+
|Benchmark_IsJSON-8 | 2000000 | 956 ns/op | 640 B/op | 12 allocs/op |
22+
|Benchmark_IsMacAddress-8 | 5000000 | 277 ns/op | 0 B/op | 0 allocs/op |
23+
|Benchmark_IsNumeric-8 | 20000000 | 110 ns/op | 0 B/op | 0 allocs/op |
24+
|Benchmark_IsLatitude-8 | 5000000 | 249 ns/op | 0 B/op | 0 allocs/op |
25+
|Benchmark_IsLongitude-8 | 5000000 | 250 ns/op | 0 B/op | 0 allocs/op |
26+
|Benchmark_IsIP-8 | 3000000 | 578 ns/op | 0 B/op | 0 allocs/op |
27+
|Benchmark_IsIPV4-8 | 5000000 | 286 ns/op | 0 B/op | 0 allocs/op |
28+
|Benchmark_IsIPV6-8 | 2000000 | 931 ns/op | 0 B/op | 0 allocs/op |
29+
|Benchmark_IsMatchedRegex-8 | 200000 | 5786 ns/op | 4465 B/op | 57 allocs/op |
30+
|Benchmark_IsURL-8 | 2000000 | 866 ns/op | 0 B/op | 0 allocs/op |
31+
|Benchmark_IsUUID-8 | 3000000 | 455 ns/op | 0 B/op | 0 allocs/op |
32+
|Benchmark_IsUUID3-8 | 3000000 | 536 ns/op | 0 B/op | 0 allocs/op |
33+
|Benchmark_IsUUID4-8 | 3000000 | 411 ns/op | 0 B/op | 0 allocs/op |
34+
|Benchmark_IsUUID5-8 | 3000000 | 443 ns/op | 0 B/op | 0 allocs/op |
35+
|BenchmarkRoller_Start-8 | 300000 | 4659 ns/op | 2468 B/op | 28 allocs/op |
36+
|Benchmark_isContainRequiredField-8 | 1000000000 | 2.69 ns/op | 0 B/op | 0 allocs/op |
37+
|Benchmark_Validate-8 | 200000 | 6742 ns/op | 727 B/op | 29 allocs/op |

helper.go

+5
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ func isNumeric(str string) bool {
9797
return regexNumeric.MatchString(str)
9898
}
9999

100+
// isMacAddres check the provided string is valid Mac Address or not
101+
func isMacAddress(str string) bool {
102+
return regexMacAddress.MatchString(str)
103+
}
104+
100105
// isLatitude check the provided input string is a valid latitude or not
101106
func isLatitude(str string) bool {
102107
return regexLatitude.MatchString(str)

helper_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ var (
8181
_roleList = []string{"admin", "manager", "supervisor"}
8282
_validJSONString = `{"FirstName": "Bob", "LastName": "Smith"}`
8383
_invalidJSONString = `{"invalid json"}`
84+
_macaddressList = inputs{
85+
"fc:40:2e:f1:d3:6f": true,
86+
"87:7a:45:f6:8b:ed": true,
87+
"a5:91:91:80:d2:fd": true,
88+
"1f:ce:44:46:24:b4": true,
89+
"00:02:x2:34:72:a5": false,
90+
}
8491
_numericStringList = inputs{"12": true, "09": true, "878": true, "100": true, "a": false, "xyz": false, "1000000000000": true}
8592
_latList = inputs{"30.297018": true, "40.044438": true, "a": false, "xyz": false}
8693
_lonList = inputs{"-78.486328": true, "-104.0625": true, "a": false, "xyz": false}
@@ -301,6 +308,20 @@ func Benchmark_IsJSON(b *testing.B) {
301308
}
302309
}
303310

311+
func Test_IsMacAddress(t *testing.T) {
312+
for n, s := range _macaddressList {
313+
if isMacAddress(n) != s {
314+
t.Error("IsMacAddress failed!")
315+
}
316+
}
317+
}
318+
319+
func Benchmark_IsMacAddress(b *testing.B) {
320+
for n := 0; n < b.N; n++ {
321+
isMacAddress("00:02:02:34:72:a5")
322+
}
323+
}
324+
304325
func Test_IsNumeric(t *testing.T) {
305326
for n, s := range _numericStringList {
306327
if isNumeric(n) != s {

regex_patterns.go

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ const (
3939
Latitude string = "^(\\+|-)?(?:90(?:(?:\\.0{1,6})?)|(?:[0-9]|[1-8][0-9])(?:(?:\\.[0-9]{1,6})?))$"
4040
// Longitude represents longitude regular expression
4141
Longitude string = "^(\\+|-)?(?:180(?:(?:\\.0{1,6})?)|(?:[0-9]|[1-9][0-9]|1[0-7][0-9])(?:(?:\\.[0-9]{1,6})?))$"
42+
// MacAddress represents regular expression for mac address
43+
MacAddress string = "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$"
4244
// Numeric represents regular expression for numeric
4345
Numeric string = "^-?[0-9]+$"
4446
// URL represents regular expression for url
@@ -66,6 +68,7 @@ var (
6668
regexDigits = regexp.MustCompile(Digits)
6769
regexEmail = regexp.MustCompile(Email)
6870
regexFloat = regexp.MustCompile(Float)
71+
regexMacAddress = regexp.MustCompile(MacAddress)
6972
regexNumeric = regexp.MustCompile(Numeric)
7073
regexLatitude = regexp.MustCompile(Latitude)
7174
regexLongitude = regexp.MustCompile(Longitude)

rules.go

+13
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,19 @@ func init() {
852852
return nil
853853
})
854854

855+
// Numeric check if the value of the field is Numeric
856+
AddCustomRule("mac_address", func(field string, rule string, message string, value interface{}) error {
857+
str := toString(value)
858+
err := fmt.Errorf("The %s field must be a valid Mac Address", field)
859+
if message != "" {
860+
err = errors.New(message)
861+
}
862+
if !isMacAddress(str) {
863+
return err
864+
}
865+
return nil
866+
})
867+
855868
// Numeric check if the value of the field is Numeric
856869
AddCustomRule("numeric", func(field string, rule string, message string, value interface{}) error {
857870
str := toString(value)

rules_test.go

+67
Original file line numberDiff line numberDiff line change
@@ -1332,6 +1332,73 @@ func Test_Len_message(t *testing.T) {
13321332
}
13331333
}
13341334

1335+
func Test_MacAddress(t *testing.T) {
1336+
type user struct {
1337+
MacAddress string `json:"mac_address"`
1338+
}
1339+
1340+
postUser := user{MacAddress: "e4:2b:e8:d3:41:0f"}
1341+
var userObj user
1342+
1343+
body, _ := json.Marshal(postUser)
1344+
req, _ := http.NewRequest("POST", "http://www.example.com", bytes.NewReader(body))
1345+
1346+
rules := MapData{
1347+
"mac_address": []string{"mac_address"},
1348+
}
1349+
1350+
messages := MapData{
1351+
"mac_address": []string{"mac_address:custom_message"},
1352+
}
1353+
1354+
opts := Options{
1355+
Request: req,
1356+
Data: &userObj,
1357+
Rules: rules,
1358+
Messages: messages,
1359+
}
1360+
1361+
vd := New(opts)
1362+
validationErr := vd.ValidateJSON()
1363+
if len(validationErr) != 0 {
1364+
t.Error("Valid Mac Address validation failed!")
1365+
}
1366+
}
1367+
1368+
func Test_MacAddress_message(t *testing.T) {
1369+
type user struct {
1370+
MacAddress string `json:"mac_address"`
1371+
}
1372+
1373+
postUser := user{MacAddress: "invalid_mac_address"}
1374+
var userObj user
1375+
1376+
body, _ := json.Marshal(postUser)
1377+
req, _ := http.NewRequest("POST", "http://www.example.com", bytes.NewReader(body))
1378+
1379+
rules := MapData{
1380+
"mac_address": []string{"mac_address"},
1381+
}
1382+
1383+
messages := MapData{
1384+
"mac_address": []string{"mac_address:custom_message"},
1385+
}
1386+
1387+
opts := Options{
1388+
Request: req,
1389+
Data: &userObj,
1390+
Rules: rules,
1391+
Messages: messages,
1392+
}
1393+
1394+
vd := New(opts)
1395+
validationErr := vd.ValidateJSON()
1396+
if validationErr.Get("mac_address") != "custom_message" {
1397+
t.Error("Mac Address custom message failed!")
1398+
}
1399+
}
1400+
1401+
13351402
func Test_Numeric(t *testing.T) {
13361403
type user struct {
13371404
NID string `json:"nid"`

0 commit comments

Comments
 (0)