Skip to content

Commit

Permalink
Added Mac Address validator (#69)
Browse files Browse the repository at this point in the history
* Added Mac Address validator

* Fixed typo adress instead of address

* Fixed tests for mac address message error
  • Loading branch information
tiagoacardoso authored and thedevsaddam committed Jun 14, 2019
1 parent dde5f75 commit 3ec9f4b
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 32 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ Send request to the server using curl or postman: `curl GET "http://localhost:90
* `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)
* `email` The field under validation must have a valid email.
* `float` The field under validation must have a valid float number.
* `mac_address` The field under validation must have be a valid Mac Address.
* `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.
e.g: `min:3` may contains characters minimum length of 3 like `"john", "jane", "jane321"` but not `"mr", "xy"`
* `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.
Expand Down
65 changes: 33 additions & 32 deletions doc/BENCHMARK.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
Benchmarks
===================

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

| ➜ go test -run=XXX -bench=. -benchmem=true | | | | |
|--------------------------------------------|-----------|------------|-----------|--------------|
| Benchmark_IsAlpha-4 | 5000000 | 323 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsAlphaDash-4 | 3000000 | 415 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsAlphaNumeric-4 | 5000000 | 338 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsBoolean-4 | 100000000 | 10.6 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsCreditCard-4 | 3000000 | 543 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsCoordinate-4 | 2000000 | 950 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsCSSColor-4 | 5000000 | 300 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsDate-4 | 2000000 | 719 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsDateDDMMYY-4 | 3000000 | 481 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsEmail-4 | 1000000 | 1172 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsFloat-4 | 3000000 | 432 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsIn-4 | 200000000 | 7.34 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsJSON-4 | 1000000 | 1595 ns/op | 768 B/op | 12 allocs/op |
| Benchmark_IsNumeric-4 | 10000000 | 195 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsLatitude-4 | 3000000 | 523 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsLongitude-4 | 3000000 | 516 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsIP-4 | 1000000 | 1073 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsIPV4-4 | 3000000 | 580 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsIPV6-4 | 1000000 | 1288 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsMatchedRegex-4 | 200000 | 7133 ns/op | 5400 B/op | 66 allocs/op |
| Benchmark_IsURL-4 | 1000000 | 1159 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsUUID-4 | 2000000 | 832 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsUUID3-4 | 2000000 | 783 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsUUID4-4 | 2000000 | 899 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_IsUUID5-4 | 2000000 | 828 ns/op | 0 B/op | 0 allocs/op |
| BenchmarkRoller_Start-4 | 200000 | 6869 ns/op | 2467 B/op | 28 allocs/op |
| Benchmark_isContainRequiredField-4 | 300000000 | 4.23 ns/op | 0 B/op | 0 allocs/op |
| Benchmark_Validate-4 | 200000 | 9347 ns/op | 664 B/op | 28 allocs/op |
| ➜ go test -run=XXX -bench=. -benchmem=true | | | | |
|--------------------------------------------|------------|--------------|--------------|--------------|
|Benchmark_IsAlpha-8 | 10000000 | 205 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsAlphaDash-8 | 5000000 | 268 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsAlphaNumeric-8 | 10000000 | 182 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsBoolean-8 | 200000000 | 6.84 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsCreditCard-8 | 10000000 | 243 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsCoordinate-8 | 3000000 | 482 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsCSSColor-8 | 10000000 | 160 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsDate-8 | 3000000 | 531 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsDateDDMMYY-8 | 5000000 | 246 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsEmail-8 | 3000000 | 549 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsFloat-8 | 10000000 | 199 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsIn-8 | 5000000 | 3.77 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsJSON-8 | 2000000 | 956 ns/op | 640 B/op | 12 allocs/op |
|Benchmark_IsMacAddress-8 | 5000000 | 277 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsNumeric-8 | 20000000 | 110 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsLatitude-8 | 5000000 | 249 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsLongitude-8 | 5000000 | 250 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsIP-8 | 3000000 | 578 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsIPV4-8 | 5000000 | 286 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsIPV6-8 | 2000000 | 931 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsMatchedRegex-8 | 200000 | 5786 ns/op | 4465 B/op | 57 allocs/op |
|Benchmark_IsURL-8 | 2000000 | 866 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsUUID-8 | 3000000 | 455 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsUUID3-8 | 3000000 | 536 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsUUID4-8 | 3000000 | 411 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_IsUUID5-8 | 3000000 | 443 ns/op | 0 B/op | 0 allocs/op |
|BenchmarkRoller_Start-8 | 300000 | 4659 ns/op | 2468 B/op | 28 allocs/op |
|Benchmark_isContainRequiredField-8 | 1000000000 | 2.69 ns/op | 0 B/op | 0 allocs/op |
|Benchmark_Validate-8 | 200000 | 6742 ns/op | 727 B/op | 29 allocs/op |
5 changes: 5 additions & 0 deletions helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ func isNumeric(str string) bool {
return regexNumeric.MatchString(str)
}

// isMacAddres check the provided string is valid Mac Address or not
func isMacAddress(str string) bool {
return regexMacAddress.MatchString(str)
}

// isLatitude check the provided input string is a valid latitude or not
func isLatitude(str string) bool {
return regexLatitude.MatchString(str)
Expand Down
21 changes: 21 additions & 0 deletions helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ var (
_roleList = []string{"admin", "manager", "supervisor"}
_validJSONString = `{"FirstName": "Bob", "LastName": "Smith"}`
_invalidJSONString = `{"invalid json"}`
_macaddressList = inputs{
"fc:40:2e:f1:d3:6f": true,
"87:7a:45:f6:8b:ed": true,
"a5:91:91:80:d2:fd": true,
"1f:ce:44:46:24:b4": true,
"00:02:x2:34:72:a5": false,
}
_numericStringList = inputs{"12": true, "09": true, "878": true, "100": true, "a": false, "xyz": false, "1000000000000": true}
_latList = inputs{"30.297018": true, "40.044438": true, "a": false, "xyz": false}
_lonList = inputs{"-78.486328": true, "-104.0625": true, "a": false, "xyz": false}
Expand Down Expand Up @@ -301,6 +308,20 @@ func Benchmark_IsJSON(b *testing.B) {
}
}

func Test_IsMacAddress(t *testing.T) {
for n, s := range _macaddressList {
if isMacAddress(n) != s {
t.Error("IsMacAddress failed!")
}
}
}

func Benchmark_IsMacAddress(b *testing.B) {
for n := 0; n < b.N; n++ {
isMacAddress("00:02:02:34:72:a5")
}
}

func Test_IsNumeric(t *testing.T) {
for n, s := range _numericStringList {
if isNumeric(n) != s {
Expand Down
3 changes: 3 additions & 0 deletions regex_patterns.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ const (
Latitude string = "^(\\+|-)?(?:90(?:(?:\\.0{1,6})?)|(?:[0-9]|[1-8][0-9])(?:(?:\\.[0-9]{1,6})?))$"
// Longitude represents longitude regular expression
Longitude string = "^(\\+|-)?(?:180(?:(?:\\.0{1,6})?)|(?:[0-9]|[1-9][0-9]|1[0-7][0-9])(?:(?:\\.[0-9]{1,6})?))$"
// MacAddress represents regular expression for mac address
MacAddress string = "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$"
// Numeric represents regular expression for numeric
Numeric string = "^-?[0-9]+$"
// URL represents regular expression for url
Expand Down Expand Up @@ -66,6 +68,7 @@ var (
regexDigits = regexp.MustCompile(Digits)
regexEmail = regexp.MustCompile(Email)
regexFloat = regexp.MustCompile(Float)
regexMacAddress = regexp.MustCompile(MacAddress)
regexNumeric = regexp.MustCompile(Numeric)
regexLatitude = regexp.MustCompile(Latitude)
regexLongitude = regexp.MustCompile(Longitude)
Expand Down
13 changes: 13 additions & 0 deletions rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,19 @@ func init() {
return nil
})

// Numeric check if the value of the field is Numeric
AddCustomRule("mac_address", func(field string, rule string, message string, value interface{}) error {
str := toString(value)
err := fmt.Errorf("The %s field must be a valid Mac Address", field)
if message != "" {
err = errors.New(message)
}
if !isMacAddress(str) {
return err
}
return nil
})

// Numeric check if the value of the field is Numeric
AddCustomRule("numeric", func(field string, rule string, message string, value interface{}) error {
str := toString(value)
Expand Down
67 changes: 67 additions & 0 deletions rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1332,6 +1332,73 @@ func Test_Len_message(t *testing.T) {
}
}

func Test_MacAddress(t *testing.T) {
type user struct {
MacAddress string `json:"mac_address"`
}

postUser := user{MacAddress: "e4:2b:e8:d3:41:0f"}
var userObj user

body, _ := json.Marshal(postUser)
req, _ := http.NewRequest("POST", "http://www.example.com", bytes.NewReader(body))

rules := MapData{
"mac_address": []string{"mac_address"},
}

messages := MapData{
"mac_address": []string{"mac_address:custom_message"},
}

opts := Options{
Request: req,
Data: &userObj,
Rules: rules,
Messages: messages,
}

vd := New(opts)
validationErr := vd.ValidateJSON()
if len(validationErr) != 0 {
t.Error("Valid Mac Address validation failed!")
}
}

func Test_MacAddress_message(t *testing.T) {
type user struct {
MacAddress string `json:"mac_address"`
}

postUser := user{MacAddress: "invalid_mac_address"}
var userObj user

body, _ := json.Marshal(postUser)
req, _ := http.NewRequest("POST", "http://www.example.com", bytes.NewReader(body))

rules := MapData{
"mac_address": []string{"mac_address"},
}

messages := MapData{
"mac_address": []string{"mac_address:custom_message"},
}

opts := Options{
Request: req,
Data: &userObj,
Rules: rules,
Messages: messages,
}

vd := New(opts)
validationErr := vd.ValidateJSON()
if validationErr.Get("mac_address") != "custom_message" {
t.Error("Mac Address custom message failed!")
}
}


func Test_Numeric(t *testing.T) {
type user struct {
NID string `json:"nid"`
Expand Down

0 comments on commit 3ec9f4b

Please sign in to comment.