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

Gte and Lte checks are added. #161

Merged
merged 1 commit into from
Dec 31, 2024
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
40 changes: 39 additions & 1 deletion DOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ Package v2 Checker is a Go library for validating user input through checker rul
- [func IsDiscoverCreditCard\(number string\) \(string, error\)](<#IsDiscoverCreditCard>)
- [func IsEmail\(value string\) \(string, error\)](<#IsEmail>)
- [func IsFQDN\(value string\) \(string, error\)](<#IsFQDN>)
- [func IsGte\[T cmp.Ordered\]\(value, n T\) \(T, error\)](<#IsGte>)
- [func IsHex\(value string\) \(string, error\)](<#IsHex>)
- [func IsIP\(value string\) \(string, error\)](<#IsIP>)
- [func IsIPv4\(value string\) \(string, error\)](<#IsIPv4>)
- [func IsIPv6\(value string\) \(string, error\)](<#IsIPv6>)
- [func IsISBN\(value string\) \(string, error\)](<#IsISBN>)
- [func IsJcbCreditCard\(number string\) \(string, error\)](<#IsJcbCreditCard>)
- [func IsLUHN\(value string\) \(string, error\)](<#IsLUHN>)
- [func IsLte\[T cmp.Ordered\]\(value, n T\) \(T, error\)](<#IsLte>)
- [func IsMAC\(value string\) \(string, error\)](<#IsMAC>)
- [func IsMasterCardCreditCard\(number string\) \(string, error\)](<#IsMasterCardCreditCard>)
- [func IsRegexp\(expression, value string\) \(string, error\)](<#IsRegexp>)
Expand Down Expand Up @@ -80,6 +82,24 @@ const (

## Variables

<a name="ErrGte"></a>

```go
var (
// ErrGte indicates that the value is not greater than or equal to the given value.
ErrGte = NewCheckError("NOT_GTE")
)
```

<a name="ErrLte"></a>

```go
var (
// ErrLte indicates that the value is not less than or equal to the given value.
ErrLte = NewCheckError("NOT_LTE")
)
```

<a name="ErrMaxLen"></a>

```go
Expand Down Expand Up @@ -707,6 +727,15 @@ func main() {
</p>
</details>

<a name="IsGte"></a>
## func [IsGte](<https://github.com/cinar/checker/blob/main/gte.go#L25>)

```go
func IsGte[T cmp.Ordered](value, n T) (T, error)
```

IsGte checks if the value is greater than or equal to the given value.

<a name="IsHex"></a>
## func [IsHex](<https://github.com/cinar/checker/blob/main/hex.go#L23>)

Expand Down Expand Up @@ -944,6 +973,15 @@ func main() {
</p>
</details>

<a name="IsLte"></a>
## func [IsLte](<https://github.com/cinar/checker/blob/main/lte.go#L25>)

```go
func IsLte[T cmp.Ordered](value, n T) (T, error)
```

IsLte checks if the value is less than or equal to the given value.

<a name="IsMAC"></a>
## func [IsMAC](<https://github.com/cinar/checker/blob/main/mac.go#L24>)

Expand Down Expand Up @@ -1173,7 +1211,7 @@ func RegisterLocale(locale string, messages map[string]string)
RegisterLocale registers the localized error messages for the given locale.

<a name="RegisterMaker"></a>
## func [RegisterMaker](<https://github.com/cinar/checker/blob/main/maker.go#L51>)
## func [RegisterMaker](<https://github.com/cinar/checker/blob/main/maker.go#L53>)

```go
func RegisterMaker(name string, maker MakeCheckFunc)
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,13 @@ type Person struct {
- [`digits`](DOC.md#IsDigits): Ensures the string contains only digits.
- [`email`](DOC.md#IsEmail): Ensures the string is a valid email address.
- [`fqdn`](DOC.md#IsFQDN): Ensures the string is a valid fully qualified domain name.
- [`hex`](DOC.md#IsHex): Ensures the string contains only hex digits.
- [`gte`](DOC.md#IsGte): Ensures the value is greater than or equal to the specified number.
- [`hex`](DOC.md#IsHex): Ensures the string contains only hexadecimal digits.
- [`ip`](DOC.md#IsIP): Ensures the string is a valid IP address.
- [`ipv4`](DOC.md#IsIPv4): Ensures the string is a valid IPv4 address.
- [`ipv6`](DOC.md#IsIPv6): Ensures the string is a valid IPv6 address.
- [`isbn`](DOC.md#IsISBN): Ensures the string is a valid ISBN.
- [`lte`](DOC.md#ISLte): Ensures the value is less than or equal to the specified number.
- [`luhn`](DOC.md#IsLUHN): Ensures the string is a valid LUHN number.
- [`mac`](DOC.md#IsMAC): Ensures the string is a valid MAC address.
- [`max-len`](DOC.md#func-maxlen): Ensures the length of the given value (string, slice, or map) is at most n.
Expand Down
67 changes: 67 additions & 0 deletions gte.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// 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 (
"cmp"
"reflect"
"strconv"
)

const (
// nameGte is the name of the greater than or equal to check.
nameGte = "gte"
)

var (
// ErrGte indicates that the value is not greater than or equal to the given value.
ErrGte = NewCheckError("NOT_GTE")
)

// IsGte checks if the value is greater than or equal to the given value.
func IsGte[T cmp.Ordered](value, n T) (T, error) {
if cmp.Compare(value, n) < 0 {
return value, newGteError(n)
}

return value, nil
}

// makeGte creates a greater than or equal to check function from a string parameter.
// Panics if the parameter cannot be parsed as a number.
func makeGte(params string) CheckFunc[reflect.Value] {
n, err := strconv.ParseFloat(params, 64)
if err != nil {
panic("unable to parse params as float")
}

return func(value reflect.Value) (reflect.Value, error) {
v := reflect.Indirect(value)

switch {
case v.CanInt():
_, err := IsGte(float64(v.Int()), n)
return v, err

case v.CanFloat():
_, err := IsGte(v.Float(), n)
return v, err

default:
panic("value is not numeric")
}
}
}

// newGteError creates a new greater than or equal to error with the given value.
func newGteError[T cmp.Ordered](n T) error {
return NewCheckErrorWithData(
ErrGte.Code,
map[string]interface{}{
"n": n,
},
)
}
139 changes: 139 additions & 0 deletions gte_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// 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 (
"errors"
"testing"

v2 "github.com/cinar/checker/v2"
)

func TestGteIntSuccess(t *testing.T) {
value := 4

result, err := v2.IsGte(value, 4)
if result != value {
t.Fatalf("result (%d) is not the original value (%d)", result, value)
}

if err != nil {
t.Fatal(err)
}
}

func TestGteIntError(t *testing.T) {
value := 4

result, err := v2.IsGte(value, 5)
if result != value {
t.Fatalf("result (%d) is not the original value (%d)", result, value)
}

if err == nil {
t.Fatal("expected error")
}

message := "Value cannot be less than 5."

if err.Error() != message {
t.Fatalf("expected %s actual %s", message, err.Error())
}
}

func TestReflectGteIntError(t *testing.T) {
type Person struct {
Age int `checkers:"gte:18"`
}

person := &Person{
Age: 16,
}

errs, ok := v2.CheckStruct(person)
if ok {
t.Fatalf("expected errors")
}

if !errors.Is(errs["Age"], v2.ErrGte) {
t.Fatalf("expected ErrGte")
}
}

func TestReflectGteIntInvalidGte(t *testing.T) {
defer FailIfNoPanic(t, "expected panic")

type Person struct {
Age int `checkers:"gte:abcd"`
}

person := &Person{
Age: 16,
}

v2.CheckStruct(person)
}

func TestReflectGteIntInvalidType(t *testing.T) {
defer FailIfNoPanic(t, "expected panic")

type Person struct {
Age string `checkers:"gte:18"`
}

person := &Person{
Age: "18",
}

v2.CheckStruct(person)
}

func TestReflectGteFloatError(t *testing.T) {
type Person struct {
Weight float64 `checkers:"gte:165.0"`
}

person := &Person{
Weight: 150,
}

errs, ok := v2.CheckStruct(person)
if ok {
t.Fatalf("expected errors")
}

if !errors.Is(errs["Weight"], v2.ErrGte) {
t.Fatalf("expected ErrGte")
}
}

func TestReflectGteFloatInvalidGte(t *testing.T) {
defer FailIfNoPanic(t, "expected panic")

type Person struct {
Weight float64 `checkers:"gte:abcd"`
}

person := &Person{
Weight: 170,
}

v2.CheckStruct(person)
}

func TestReflectGteFloatInvalidType(t *testing.T) {
defer FailIfNoPanic(t, "expected panic")

type Person struct {
Weight string `checkers:"gte:165.0"`
}

person := &Person{
Weight: "170",
}

v2.CheckStruct(person)
}
2 changes: 2 additions & 0 deletions locales/DOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ var EnUSMessages = map[string]string{
"NOT_DIGITS": "Can only contain digits.",
"NOT_EMAIL": "Not a valid email address.",
"NOT_FQDN": "Not a fully qualified domain name (FQDN).",
"NOT_GTE": "Value cannot be less than {{ .n }}.",
"NOT_HEX": "Can only contain hexadecimal characters.",
"NOT_IP": "Not a valid IP address.",
"NOT_IPV4": "Not a valid IPv4 address.",
"NOT_IPV6": "Not a valid IPv6 address.",
"NOT_ISBN": "Not a valid ISBN number.",
"NOT_LTE": "Value cannot be less than {{ .n }}.",
"NOT_LUHN": "Not a valid LUHN number.",
"NOT_MAC": "Not a valid MAC address.",
"NOT_MAX_LEN": "Value cannot be greater than {{ .max }}.",
Expand Down
2 changes: 2 additions & 0 deletions locales/en_us.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ var EnUSMessages = map[string]string{
"NOT_DIGITS": "Can only contain digits.",
"NOT_EMAIL": "Not a valid email address.",
"NOT_FQDN": "Not a fully qualified domain name (FQDN).",
"NOT_GTE": "Value cannot be less than {{ .n }}.",
"NOT_HEX": "Can only contain hexadecimal characters.",
"NOT_IP": "Not a valid IP address.",
"NOT_IPV4": "Not a valid IPv4 address.",
"NOT_IPV6": "Not a valid IPv6 address.",
"NOT_ISBN": "Not a valid ISBN number.",
"NOT_LTE": "Value cannot be less than {{ .n }}.",
"NOT_LUHN": "Not a valid LUHN number.",
"NOT_MAC": "Not a valid MAC address.",
"NOT_MAX_LEN": "Value cannot be greater than {{ .max }}.",
Expand Down
Loading
Loading