Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Mac Address validator #69

Merged
merged 3 commits into from
Jun 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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