Skip to content

Commit

Permalink
Min and Max added. (#35)
Browse files Browse the repository at this point in the history
Fixes #17  
Fixes #18
  • Loading branch information
cinar committed Jun 16, 2023
1 parent e71d09e commit 312945f
Show file tree
Hide file tree
Showing 9 changed files with 300 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ type Person struct {

This package currently provides the following checkers:

- [max](doc/checkers/max.md) checks if the given value is less than the given maximum.
- [max-length](doc/checkers/maxlength.md) checks if the length of the given value is less than the given maximum length.
- [min](doc/checkers/min.md) checks if the given value is greather than the given minimum.
- [min-length](doc/checkers/minlength.md) checks if the length of the given value is greather than the given minimum length.
- [required](doc/checkers/required.md) checks if the required value is provided.
- [same](doc/checkers/same.md) checks if the given value is equal to the value of the field with the given name.
16 changes: 16 additions & 0 deletions checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ const ResultValid Result = "VALID"

// makers provides mapping to maker function for the checkers.
var makers = map[string]MakeFunc{
CheckerMax: makeMax,
CheckerMaxLength: makeMaxLength,
CheckerMin: makeMin,
CheckerMinLength: makeMinLength,
CheckerRequired: makeRequired,
CheckerSame: makeSame,
Expand Down Expand Up @@ -120,3 +122,17 @@ func initCheckers(config string) []CheckFunc {

return checkers
}

// numberOf gives value's numerical value given that it is either an int or a float.
func numberOf(value reflect.Value) float64 {
switch value.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return float64(value.Int())

case reflect.Float32, reflect.Float64:
return value.Float()

default:
panic("expecting int or float")
}
}
28 changes: 28 additions & 0 deletions checker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,34 @@ func TestCheckNestedStruct(t *testing.T) {
}
}

func TestNumberOfInvalid(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Fail()
}
}()

s := "invalid"

numberOf(reflect.ValueOf(s))
}

func TestNumberOfInt(t *testing.T) {
n := 10

if numberOf(reflect.ValueOf(n)) != float64(n) {
t.Fail()
}
}

func TestNumberOfFloat(t *testing.T) {
n := float64(10.10)

if numberOf(reflect.ValueOf(n)) != n {
t.Fail()
}
}

func BenchmarkCheck(b *testing.B) {
type Address struct {
Street string `checkers:"required"`
Expand Down
30 changes: 30 additions & 0 deletions doc/checkers/max.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Max Checker

The ```max``` checker checks if the given ```int``` or ```float``` value is less than the given maximum. If the value is above the maximum, the checker will return the ```NOT_MAX``` result. Here is an example:

```golang
type Order struct {
Quantity int `checkers:"max:10"`
}

order := &Order{
Quantity: 5,
}

mistakes, valid := Check(order)
if !valid {
// Send the mistakes back to the user
}
```

In your custom checkers, you can call the ```max``` checker function ```IsMax``` to validate the user input. Here is an example:

```golang
quantity := 5

result := IsMax(quantity, 10 )

if result != ResultValid {
// Send the mistakes back to the user
}
```
30 changes: 30 additions & 0 deletions doc/checkers/min.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Min Checker

The ```min``` checker checks if the given ```int``` or ```float``` value is greather than the given minimum. If the value is below the minimum, the checker will return the ```NOT_MIN``` result. Here is an example:

```golang
type User struct {
Age int `checkers:"min:21"`
}

user := &User{
Age: 45,
}

mistakes, valid := Check(user)
if !valid {
// Send the mistakes back to the user
}
```

In your custom checkers, you can call the ```min``` checker function ```IsMin``` to validate the user input. Here is an example:

```golang
age := 45

result := IsMin(age, 21)

if result != ResultValid {
// Send the mistakes back to the user
}
```
40 changes: 40 additions & 0 deletions max.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package checker

import (
"reflect"
"strconv"
)

// CheckerMax is the name of the checker.
const CheckerMax = "max"

// ResultNotMax indicates that the given value is above the defined maximum.
const ResultNotMax = "NOT_MIN"

// IsMax checks if the given value is below than the given maximum.
func IsMax(value interface{}, max float64) Result {
return checkMax(reflect.Indirect(reflect.ValueOf(value)), reflect.ValueOf(nil), max)
}

// makeMax makes a checker function for the max checker.
func makeMax(config string) CheckFunc {
max, err := strconv.ParseFloat(config, 64)
if err != nil {
panic("unable to parse max")
}

return func(value, parent reflect.Value) Result {
return checkMax(value, parent, max)
}
}

// checkMax checks if the given value is less than the given maximum.
func checkMax(value, _ reflect.Value, max float64) Result {
n := numberOf(value)

if n > max {
return ResultNotMax
}

return ResultValid
}
57 changes: 57 additions & 0 deletions max_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package checker

import "testing"

func TestIsMaxValid(t *testing.T) {
n := 5

if IsMax(n, 10) != ResultValid {
t.Fail()
}
}

func TestCheckMaxInvalidConfig(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Fail()
}
}()

type Order struct {
Quantity int `checkers:"max:AB"`
}

order := &Order{}

Check(order)
}

func TestCheckMaxValid(t *testing.T) {
type Order struct {
Quantity int `checkers:"max:10"`
}

order := &Order{
Quantity: 5,
}

_, valid := Check(order)
if !valid {
t.Fail()
}
}

func TestCheckMaxInvalid(t *testing.T) {
type Order struct {
Quantity int `checkers:"max:10"`
}

order := &Order{
Quantity: 20,
}

_, valid := Check(order)
if valid {
t.Fail()
}
}
40 changes: 40 additions & 0 deletions min.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package checker

import (
"reflect"
"strconv"
)

// CheckerMin is the name of the checker.
const CheckerMin = "min"

// ResultNotMin indicates that the given value is below the defined minimum.
const ResultNotMin = "NOT_MIN"

// IsMin checks if the given value is above than the given minimum.
func IsMin(value interface{}, min float64) Result {
return checkMin(reflect.Indirect(reflect.ValueOf(value)), reflect.ValueOf(nil), min)
}

// makeMin makes a checker function for the min checker.
func makeMin(config string) CheckFunc {
min, err := strconv.ParseFloat(config, 64)
if err != nil {
panic("unable to parse min")
}

return func(value, parent reflect.Value) Result {
return checkMin(value, parent, min)
}
}

// checkMin checks if the given value is greather than the given minimum.
func checkMin(value, _ reflect.Value, min float64) Result {
n := numberOf(value)

if n < min {
return ResultNotMin
}

return ResultValid
}
57 changes: 57 additions & 0 deletions min_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package checker

import "testing"

func TestIsMinValid(t *testing.T) {
n := 45

if IsMin(n, 21) != ResultValid {
t.Fail()
}
}

func TestCheckMinInvalidConfig(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Fail()
}
}()

type User struct {
Age int `checkers:"min:AB"`
}

user := &User{}

Check(user)
}

func TestCheckMinValid(t *testing.T) {
type User struct {
Age int `checkers:"min:21"`
}

user := &User{
Age: 45,
}

_, valid := Check(user)
if !valid {
t.Fail()
}
}

func TestCheckMinInvalid(t *testing.T) {
type User struct {
Age int `checkers:"min:21"`
}

user := &User{
Age: 18,
}

_, valid := Check(user)
if valid {
t.Fail()
}
}

0 comments on commit 312945f

Please sign in to comment.