diff --git a/v2/ip.go b/v2/ip.go new file mode 100644 index 0000000..09e1d6b --- /dev/null +++ b/v2/ip.go @@ -0,0 +1,40 @@ +// Copyright (c) 2023-2024 Onur Cinar. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +// https://github.com/cinar/checker + +package v2 + +import ( + "net" + "reflect" +) + +const ( + // nameIP is the name of the IP check. + nameIP = "ip" +) + +var ( + // ErrNotIP indicates that the given value is not a valid IP address. + ErrNotIP = NewCheckError("IP") +) + +// IsIP checks if the value is a valid IP address. +func IsIP(value string) (string, error) { + if net.ParseIP(value) == nil { + return value, ErrNotIP + } + return value, nil +} + +// checkIP checks if the value is a valid IP address. +func checkIP(value reflect.Value) (reflect.Value, error) { + _, err := IsIP(value.Interface().(string)) + return value, err +} + +// makeIP makes a checker function for the IP checker. +func makeIP(_ string) CheckFunc[reflect.Value] { + return checkIP +} diff --git a/v2/ip_test.go b/v2/ip_test.go new file mode 100644 index 0000000..5bd23c5 --- /dev/null +++ b/v2/ip_test.go @@ -0,0 +1,76 @@ +// Copyright (c) 2023-2024 Onur Cinar. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +// https://github.com/cinar/checker + +package v2_test + +import ( + "fmt" + "testing" + + v2 "github.com/cinar/checker/v2" +) + +func ExampleIsIP() { + _, err := v2.IsIP("192.168.1.1") + if err != nil { + fmt.Println(err) + } +} + +func TestIsIPInvalid(t *testing.T) { + _, err := v2.IsIP("invalid-ip") + if err == nil { + t.Fatal("expected error") + } +} + +func TestIsIPValid(t *testing.T) { + _, err := v2.IsIP("192.168.1.1") + if err != nil { + t.Fatal(err) + } +} + +func TestCheckIPNonString(t *testing.T) { + defer FailIfNoPanic(t, "expected panic") + + type Network struct { + Address int `checkers:"ip"` + } + + network := &Network{} + + v2.CheckStruct(network) +} + +func TestCheckIPInvalid(t *testing.T) { + type Network struct { + Address string `checkers:"ip"` + } + + network := &Network{ + Address: "invalid-ip", + } + + _, ok := v2.CheckStruct(network) + if ok { + t.Fatal("expected error") + } +} + +func TestCheckIPValid(t *testing.T) { + type Network struct { + Address string `checkers:"ip"` + } + + network := &Network{ + Address: "192.168.1.1", + } + + _, ok := v2.CheckStruct(network) + if !ok { + t.Fatal("expected valid") + } +} diff --git a/v2/ipv4.go b/v2/ipv4.go new file mode 100644 index 0000000..791bcf4 --- /dev/null +++ b/v2/ipv4.go @@ -0,0 +1,41 @@ +// Copyright (c) 2023-2024 Onur Cinar. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +// https://github.com/cinar/checker + +package v2 + +import ( + "net" + "reflect" +) + +const ( + // nameIPv4 is the name of the IPv4 check. + nameIPv4 = "ipv4" +) + +var ( + // ErrNotIPv4 indicates that the given value is not a valid IPv4 address. + ErrNotIPv4 = NewCheckError("IPv4") +) + +// IsIPv4 checks if the value is a valid IPv4 address. +func IsIPv4(value string) (string, error) { + ip := net.ParseIP(value) + if ip == nil || ip.To4() == nil { + return value, ErrNotIPv4 + } + return value, nil +} + +// checkIPv4 checks if the value is a valid IPv4 address. +func checkIPv4(value reflect.Value) (reflect.Value, error) { + _, err := IsIPv4(value.Interface().(string)) + return value, err +} + +// makeIPv4 makes a checker function for the IPv4 checker. +func makeIPv4(_ string) CheckFunc[reflect.Value] { + return checkIPv4 +} diff --git a/v2/ipv4_test.go b/v2/ipv4_test.go new file mode 100644 index 0000000..ba34feb --- /dev/null +++ b/v2/ipv4_test.go @@ -0,0 +1,76 @@ +// Copyright (c) 2023-2024 Onur Cinar. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +// https://github.com/cinar/checker + +package v2_test + +import ( + "fmt" + "testing" + + v2 "github.com/cinar/checker/v2" +) + +func ExampleIsIPv4() { + _, err := v2.IsIPv4("192.168.1.1") + if err != nil { + fmt.Println(err) + } +} + +func TestIsIPv4Invalid(t *testing.T) { + _, err := v2.IsIPv4("2001:db8::1") + if err == nil { + t.Fatal("expected error") + } +} + +func TestIsIPv4Valid(t *testing.T) { + _, err := v2.IsIPv4("192.168.1.1") + if err != nil { + t.Fatal(err) + } +} + +func TestCheckIPv4NonString(t *testing.T) { + defer FailIfNoPanic(t, "expected panic") + + type Network struct { + Address int `checkers:"ipv4"` + } + + network := &Network{} + + v2.CheckStruct(network) +} + +func TestCheckIPv4Invalid(t *testing.T) { + type Network struct { + Address string `checkers:"ipv4"` + } + + network := &Network{ + Address: "2001:db8::1", + } + + _, ok := v2.CheckStruct(network) + if ok { + t.Fatal("expected error") + } +} + +func TestCheckIPv4Valid(t *testing.T) { + type Network struct { + Address string `checkers:"ipv4"` + } + + network := &Network{ + Address: "192.168.1.1", + } + + _, ok := v2.CheckStruct(network) + if !ok { + t.Fatal("expected valid") + } +} diff --git a/v2/ipv6.go b/v2/ipv6.go new file mode 100644 index 0000000..2856166 --- /dev/null +++ b/v2/ipv6.go @@ -0,0 +1,40 @@ +// Copyright (c) 2023-2024 Onur Cinar. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +// https://github.com/cinar/checker + +package v2 + +import ( + "net" + "reflect" +) + +const ( + // nameIPv6 is the name of the IPv6 check. + nameIPv6 = "ipv6" +) + +var ( + // ErrNotIPv6 indicates that the given value is not a valid IPv6 address. + ErrNotIPv6 = NewCheckError("IPv6") +) + +// IsIPv6 checks if the value is a valid IPv6 address. +func IsIPv6(value string) (string, error) { + if net.ParseIP(value) == nil || net.ParseIP(value).To4() != nil { + return value, ErrNotIPv6 + } + return value, nil +} + +// checkIPv6 checks if the value is a valid IPv6 address. +func checkIPv6(value reflect.Value) (reflect.Value, error) { + _, err := IsIPv6(value.Interface().(string)) + return value, err +} + +// makeIPv6 makes a checker function for the IPv6 checker. +func makeIPv6(_ string) CheckFunc[reflect.Value] { + return checkIPv6 +} diff --git a/v2/ipv6_test.go b/v2/ipv6_test.go new file mode 100644 index 0000000..2a7ea58 --- /dev/null +++ b/v2/ipv6_test.go @@ -0,0 +1,76 @@ +// Copyright (c) 2023-2024 Onur Cinar. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +// https://github.com/cinar/checker + +package v2_test + +import ( + "fmt" + "testing" + + v2 "github.com/cinar/checker/v2" +) + +func ExampleIsIPv6() { + _, err := v2.IsIPv6("2001:db8::1") + if err != nil { + fmt.Println(err) + } +} + +func TestIsIPv6Invalid(t *testing.T) { + _, err := v2.IsIPv6("192.168.1.1") + if err == nil { + t.Fatal("expected error") + } +} + +func TestIsIPv6Valid(t *testing.T) { + _, err := v2.IsIPv6("2001:db8::1") + if err != nil { + t.Fatal(err) + } +} + +func TestCheckIPv6NonString(t *testing.T) { + defer FailIfNoPanic(t, "expected panic") + + type Network struct { + Address int `checkers:"ipv6"` + } + + network := &Network{} + + v2.CheckStruct(network) +} + +func TestCheckIPv6Invalid(t *testing.T) { + type Network struct { + Address string `checkers:"ipv6"` + } + + network := &Network{ + Address: "192.168.1.1", + } + + _, ok := v2.CheckStruct(network) + if ok { + t.Fatal("expected error") + } +} + +func TestCheckIPv6Valid(t *testing.T) { + type Network struct { + Address string `checkers:"ipv6"` + } + + network := &Network{ + Address: "2001:db8::1", + } + + _, ok := v2.CheckStruct(network) + if !ok { + t.Fatal("expected valid") + } +} diff --git a/v2/maker.go b/v2/maker.go index e4df7fb..f5ff1b8 100644 --- a/v2/maker.go +++ b/v2/maker.go @@ -22,6 +22,9 @@ var makers = map[string]MakeCheckFunc{ nameDigits: makeDigits, nameEmail: makeEmail, nameFQDN: makeFQDN, + nameIP: makeIP, + nameIPv4: makeIPv4, + nameIPv6: makeIPv6, nameMaxLen: makeMaxLen, nameMinLen: makeMinLen, nameRequired: makeRequired,