Skip to content

Commit

Permalink
Adds support for 'Nil' and 'Empty' rules (go-ozzo#106)
Browse files Browse the repository at this point in the history
  • Loading branch information
samber authored Apr 26, 2020
1 parent 14a5440 commit c098b9a
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,8 @@ The following rules are provided in the `validation` package:
* `Required`: checks if a value is not empty (neither nil nor zero).
* `NotNil`: checks if a pointer value is not nil. Non-pointer values are considered valid.
* `NilOrNotEmpty`: checks if a value is a nil pointer or a non-empty value. This differs from `Required` in that it treats a nil pointer as valid.
* `Nil`: checks if a value is a nil pointer.
* `Empty`: checks if a value is empty. nil pointers are considered valid.
* `Skip`: this is a special rule used to indicate that all rules following it should be skipped (including the nested ones).
* `MultipleOf`: checks if the value is a multiple of the specified range.
* `Each(rules ...Rule)`: checks the elements within an iterable (map/slice/array) with other rules.
Expand Down
60 changes: 60 additions & 0 deletions absent.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2016 Qiang Xue. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package validation

var (
// ErrNil is the error that returns when a value is not nil.
ErrNil = NewError("validation_nil", "must be blank")
// ErrEmpty is the error that returns when a not nil value is not empty.
ErrEmpty = NewError("validation_empty", "must be blank")
)

// Nil is a validation rule that checks if a value is nil.
// It is the opposite of NotNil rule
var Nil = absentRule{err: ErrNil, condition: true, skipNil: false}

// Empty checks if a not nil value is empty.
var Empty = absentRule{err: ErrEmpty, condition: true, skipNil: true}

type absentRule struct {
condition bool
err Error
skipNil bool
}

// Validate checks if the given value is valid or not.
func (r absentRule) Validate(value interface{}) error {
if r.condition {
value, isNil := Indirect(value)
if r.skipNil == false && isNil == false {
return r.err
}
if isNil {
return nil
}
if !IsEmpty(value) {
return r.err
}
}
return nil
}

// When sets the condition that determines if the validation should be performed.
func (r absentRule) When(condition bool) absentRule {
r.condition = condition
return r
}

// Error sets the error message for the rule.
func (r absentRule) Error(message string) absentRule {
r.err = r.err.SetMessage(message)
return r
}

// ErrorObject sets the error struct for the rule.
func (r absentRule) ErrorObject(err Error) absentRule {
r.err = err
return r
}
104 changes: 104 additions & 0 deletions absent_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright 2016 Qiang Xue. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package validation

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestNil(t *testing.T) {
s1 := "123"
s2 := ""
var time1 time.Time
tests := []struct {
tag string
value interface{}
err string
}{
{"t1", 123, "must be blank"},
{"t2", "", "must be blank"},
{"t3", &s1, "must be blank"},
{"t4", &s2, "must be blank"},
{"t5", nil, ""},
{"t6", time1, "must be blank"},
}

for _, test := range tests {
r := Nil
err := r.Validate(test.value)
assertError(t, test.err, err, test.tag)
}
}

func TestEmpty(t *testing.T) {
s1 := "123"
s2 := ""
time1 := time.Now()
var time2 time.Time
tests := []struct {
tag string
value interface{}
err string
}{
{"t1", 123, "must be blank"},
{"t2", "", ""},
{"t3", &s1, "must be blank"},
{"t4", &s2, ""},
{"t5", nil, ""},
{"t6", time1, "must be blank"},
{"t7", time2, ""},
}

for _, test := range tests {
r := Empty
err := r.Validate(test.value)
assertError(t, test.err, err, test.tag)
}
}

func TestAbsentRule_When(t *testing.T) {
r := Nil.When(false)
err := Validate(42, r)
assert.Nil(t, err)

r = Nil.When(true)
err = Validate(42, r)
assert.Equal(t, ErrNil, err)
}

func Test_absentRule_Error(t *testing.T) {
r := Nil
assert.Equal(t, "must be blank", r.Validate("42").Error())
assert.False(t, r.skipNil)
r2 := r.Error("123")
assert.Equal(t, "must be blank", r.Validate("42").Error())
assert.False(t, r.skipNil)
assert.Equal(t, "123", r2.err.Message())
assert.False(t, r2.skipNil)

r = Empty
assert.Equal(t, "must be blank", r.Validate("42").Error())
assert.True(t, r.skipNil)
r2 = r.Error("123")
assert.Equal(t, "must be blank", r.Validate("42").Error())
assert.True(t, r.skipNil)
assert.Equal(t, "123", r2.err.Message())
assert.True(t, r2.skipNil)
}

func TestAbsentRule_Error(t *testing.T) {
r := Nil

err := NewError("code", "abc")
r = r.ErrorObject(err)

assert.Equal(t, err, r.err)
assert.Equal(t, err.Code(), r.err.Code())
assert.Equal(t, err.Message(), r.err.Message())
assert.NotEqual(t, err, Nil.err)
}

0 comments on commit c098b9a

Please sign in to comment.