Compare commits
10 Commits
ad75934954
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 8fab67ff77 | |||
| dff0caf40b | |||
| b8c82f3529 | |||
| 45298c462a | |||
| 38b1cf53d8 | |||
| c1d7c423a7 | |||
| 5b0e0ca1ec | |||
| 15b4c91cf0 | |||
| a9c1184d6b | |||
| 4c99b5a654 |
@@ -0,0 +1,47 @@
|
|||||||
|
name: Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: ^1.21.0
|
||||||
|
|
||||||
|
- name: Display Go version
|
||||||
|
run: go version
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: go get
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: go test -v
|
||||||
|
|
||||||
|
notify:
|
||||||
|
name: Send Discord workflow notification
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: test
|
||||||
|
steps:
|
||||||
|
- name: Send notification
|
||||||
|
uses: annybs/action-notify-discord@v1
|
||||||
|
if: ${{ always() }}
|
||||||
|
with:
|
||||||
|
repository: ${{ github.repository }}
|
||||||
|
result: ${{ needs.test.result }}
|
||||||
|
run-id: ${{ github.run_id }}
|
||||||
|
run-number: ${{ github.run_number }}
|
||||||
|
webhook-url: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
|
workflow: ${{ github.workflow }}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
go.sum
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
# MIT License
|
||||||
|
|
||||||
|
Copyright © 2024 Aneurin Barker Snook a@aneur.in
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
https://mit-license.org/
|
||||||
@@ -2,34 +2,6 @@
|
|||||||
|
|
||||||
A suite of straightforward validation functions. You put something in, you get back `nil` or an error.
|
A suite of straightforward validation functions. You put something in, you get back `nil` or an error.
|
||||||
|
|
||||||
## Error handling
|
|
||||||
|
|
||||||
You can use `errors.Is()` to ascertain the type of errors thrown by validation functions. This may be helpful to control side effects, particularly if using multiple validators and returning early (similar to a strongly-typed try-catch). For example:
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/annybs/go/validate"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
v := validate.Equal("a")
|
|
||||||
if err := v("b"); err != nil {
|
|
||||||
if errors.Is(err, validate.ErrNotEqual) {
|
|
||||||
fmt.Println("failed successfully")
|
|
||||||
} else {
|
|
||||||
fmt.Println("failed unsuccessfully")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
See [LICENSE.md](../LICENSE.md)
|
See [LICENSE.md](./LICENSE.md)
|
||||||
|
|||||||
+24
-21
@@ -2,40 +2,43 @@ package validate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAll(t *testing.T) {
|
func ExampleAll() {
|
||||||
type TestCase[T any] struct {
|
testAll := All(MinLength(4), Chars("0123456789abcdef"))
|
||||||
Input T
|
fmt.Println(testAll("invalid input"))
|
||||||
F func(T) error
|
// Output: contains disallowed characters
|
||||||
Err error
|
}
|
||||||
}
|
|
||||||
|
|
||||||
f := All(
|
func TestAll(t *testing.T) {
|
||||||
|
testAll := All(
|
||||||
MinLength(4),
|
MinLength(4),
|
||||||
MaxLength(8),
|
MaxLength(8),
|
||||||
Chars("0123456789abcdef"),
|
Chars("0123456789abcdef"),
|
||||||
In("abcd", "abcdef", "12345678"),
|
In("abcd", "abcdef", "12345678"),
|
||||||
)
|
)
|
||||||
|
|
||||||
testCases := []TestCase[string]{
|
testCases := map[string]error{
|
||||||
{Input: "abcd", F: f},
|
"abcd": nil,
|
||||||
{Input: "abcdef", F: f},
|
"abcdef": nil,
|
||||||
{Input: "12345678", F: f},
|
"12345678": nil,
|
||||||
{Input: "abc", F: f, Err: ErrMustBeLonger},
|
|
||||||
{Input: "abcdef012", F: f, Err: ErrMustBeShorter},
|
"abc": ErrMustBeLonger.With(4),
|
||||||
{Input: "abcdefgh", F: f, Err: ErrDisallowedChars},
|
"abcdef012": ErrMustBeShorter.With(8),
|
||||||
{Input: "01abcd", F: f, Err: ErrValueNotAllowed},
|
"abcdefgh": ErrDisallowedChars,
|
||||||
|
"01abcd": ErrValueNotAllowed,
|
||||||
}
|
}
|
||||||
|
|
||||||
for n, tc := range testCases {
|
for input, want := range testCases {
|
||||||
t.Logf("(%d) Testing %q", n, tc.Input)
|
t.Run(input, func(t *testing.T) {
|
||||||
|
got := testAll(input)
|
||||||
|
|
||||||
err := tc.F(tc.Input)
|
if !errors.Is(got, want) {
|
||||||
|
t.Error("got", got)
|
||||||
if !errors.Is(err, tc.Err) {
|
t.Error("want", want)
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Validation error.
|
|
||||||
var (
|
var (
|
||||||
ErrDisallowedChars = NewError("contains disallowed characters")
|
ErrDisallowedChars = NewError("contains disallowed characters")
|
||||||
)
|
)
|
||||||
|
|||||||
+37
-36
@@ -2,59 +2,60 @@ package validate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ExampleChars() {
|
||||||
|
testChars := Chars("0123456789abcdef")
|
||||||
|
fmt.Println(testChars("invalid input"))
|
||||||
|
// Output: contains disallowed characters
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleExceptChars() {
|
||||||
|
testExceptChars := Chars("0123456789abcdef")
|
||||||
|
fmt.Println(testExceptChars("invalid input"))
|
||||||
|
// Output: contains disallowed characters
|
||||||
|
}
|
||||||
|
|
||||||
func TestChars(t *testing.T) {
|
func TestChars(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[string]map[string]error{
|
||||||
Input string
|
"0123456789abcdef": {"abcd1234": nil, "abcd 1234": ErrDisallowedChars, "ghijklmno": ErrDisallowedChars},
|
||||||
C string
|
|
||||||
Err error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hexRange := "0123456789abcdef"
|
for setup, values := range testCases {
|
||||||
|
testChars := Chars(setup)
|
||||||
|
|
||||||
testCases := []TestCase{
|
for input, want := range values {
|
||||||
{Input: "abcd1234", C: hexRange},
|
t.Run(input, func(t *testing.T) {
|
||||||
{Input: "abcd 1234", C: hexRange, Err: ErrDisallowedChars},
|
got := testChars(input)
|
||||||
{Input: "ghijklmno", C: hexRange, Err: ErrDisallowedChars},
|
|
||||||
|
if !errors.Is(got, want) {
|
||||||
|
t.Error("got", got)
|
||||||
|
t.Error("want", want)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
for n, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %q against %q", n, tc.Input, tc.C)
|
|
||||||
|
|
||||||
f := Chars(tc.C)
|
|
||||||
err := f(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExceptChars(t *testing.T) {
|
func TestExceptChars(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[string]map[string]error{
|
||||||
Input string
|
"0123456789abcdef": {"abcd1234": ErrDisallowedChars, "abcd 1234": ErrDisallowedChars, "ghijklmno": nil},
|
||||||
C string
|
|
||||||
Err error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hexRange := "0123456789abcdef"
|
for setup, values := range testCases {
|
||||||
|
testExceptChars := ExceptChars(setup)
|
||||||
|
|
||||||
testCases := []TestCase{
|
for input, want := range values {
|
||||||
{Input: "abcd1234", C: hexRange, Err: ErrDisallowedChars},
|
t.Run(input, func(t *testing.T) {
|
||||||
{Input: "abcd 1234", C: hexRange, Err: ErrDisallowedChars},
|
got := testExceptChars(input)
|
||||||
{Input: "ghijklmno", C: hexRange},
|
|
||||||
|
if !errors.Is(got, want) {
|
||||||
|
t.Error("got", got)
|
||||||
|
t.Error("want", want)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
for n, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %q against %q", n, tc.Input, tc.C)
|
|
||||||
|
|
||||||
f := ExceptChars(tc.C)
|
|
||||||
err := f(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Validation error.
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidEmail = NewError("invalid email address")
|
ErrInvalidEmail = NewError("invalid email address")
|
||||||
)
|
)
|
||||||
|
|||||||
+33
-15
@@ -2,27 +2,45 @@ package validate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ExampleEmail() {
|
||||||
|
fmt.Println(Email("not an email"))
|
||||||
|
// Output: invalid email address
|
||||||
|
}
|
||||||
|
|
||||||
|
func FuzzEmail(f *testing.F) {
|
||||||
|
want := ErrInvalidEmail
|
||||||
|
|
||||||
|
f.Fuzz(func(t *testing.T, input string) {
|
||||||
|
got := Email(input)
|
||||||
|
|
||||||
|
if !errors.Is(got, want) {
|
||||||
|
t.Error("got", got)
|
||||||
|
t.Error("want", want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestEmail(t *testing.T) {
|
func TestEmail(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[string]error{
|
||||||
Input string
|
"test@example.com": nil,
|
||||||
Err error
|
"firstname.lastname@some-website.co.uk": nil,
|
||||||
|
|
||||||
|
"not an email": ErrInvalidEmail,
|
||||||
|
"testexample.com": ErrInvalidEmail,
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
for input, want := range testCases {
|
||||||
{Input: "test@example.com"},
|
t.Run(input, func(t *testing.T) {
|
||||||
{Input: "testexample.com", Err: ErrInvalidEmail},
|
got := Email(input)
|
||||||
}
|
|
||||||
|
if !errors.Is(got, want) {
|
||||||
for n, tc := range testCases {
|
t.Error("got", got)
|
||||||
t.Logf("(%d) Testing %q", n, tc.Input)
|
t.Error("want", want)
|
||||||
|
|
||||||
err := Email(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-43
@@ -2,55 +2,29 @@ package validate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEqualInt(t *testing.T) {
|
func TestEqual(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[string]map[string]error{
|
||||||
I int
|
"abc": {"abc": nil, "def": ErrNotEqual.With("abc"), "xyz": ErrNotEqual.With("abc")},
|
||||||
C int
|
"def": {"abc": ErrNotEqual.With("def"), "def": nil, "xyz": ErrNotEqual.With("def")},
|
||||||
Err error
|
"xyz": {"abc": ErrNotEqual.With("xyz"), "def": ErrNotEqual.With("xyz"), "xyz": nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
for setup, values := range testCases {
|
||||||
{I: 1, C: 1},
|
testEqual := Equal(setup)
|
||||||
{I: 5 ^ 3, C: 5 ^ 3},
|
|
||||||
{I: 10, C: 15, Err: ErrNotEqual},
|
for input, want := range values {
|
||||||
|
t.Run(fmt.Sprintf("%s/%s", setup, input), func(t *testing.T) {
|
||||||
|
got := testEqual(input)
|
||||||
|
|
||||||
|
if !errors.Is(got, want) {
|
||||||
|
t.Error("got", got)
|
||||||
|
t.Error("want", want)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
for i, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %d against %d", i, tc.I, tc.C)
|
|
||||||
|
|
||||||
f := Equal(tc.C)
|
|
||||||
err := f(tc.I)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEqualStr(t *testing.T) {
|
|
||||||
type TestCase struct {
|
|
||||||
I string
|
|
||||||
C string
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
testCases := []TestCase{
|
|
||||||
{I: "abc", C: "abc"},
|
|
||||||
{I: "def ghi 123", C: "def ghi 123"},
|
|
||||||
{I: "jkl", C: "mno", Err: ErrNotEqual},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %s against %s", i, tc.I, tc.C)
|
|
||||||
|
|
||||||
f := Equal(tc.C)
|
|
||||||
err := f(tc.I)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-28
@@ -2,48 +2,48 @@ package validate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestErrorIs(t *testing.T) {
|
func TestErrorIs(t *testing.T) {
|
||||||
type TestCase struct {
|
type TestCase struct {
|
||||||
Err error
|
A error
|
||||||
Target error
|
B error
|
||||||
Is bool
|
Want bool
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
testCases := []TestCase{
|
||||||
// Is any validation error
|
// Want any validation error
|
||||||
{Err: Err, Target: Err, Is: true},
|
{A: Err, B: Err, Want: true},
|
||||||
{Err: ErrDisallowedChars, Target: Err, Is: true},
|
{A: ErrDisallowedChars, B: Err, Want: true},
|
||||||
{Err: ErrMustBeGreater, Target: Err, Is: true},
|
{A: ErrMustBeGreater, B: Err, Want: true},
|
||||||
|
|
||||||
// Is specific validation error
|
// Want specific validation error
|
||||||
{Err: ErrDisallowedChars, Target: ErrDisallowedChars, Is: true},
|
{A: ErrDisallowedChars, B: ErrDisallowedChars, Want: true},
|
||||||
{Err: ErrMustBeGreater, Target: ErrMustBeGreater, Is: true},
|
{A: ErrMustBeGreater, B: ErrMustBeGreater, Want: true},
|
||||||
|
|
||||||
// Is not specific validation error
|
// Want not specific validation error
|
||||||
{Err: Err, Target: ErrDisallowedChars},
|
{A: Err, B: ErrDisallowedChars},
|
||||||
{Err: Err, Target: ErrMustBeGreater},
|
{A: Err, B: ErrMustBeGreater},
|
||||||
{Err: ErrMustBeGreater, Target: ErrDisallowedChars},
|
{A: ErrMustBeGreater, B: ErrDisallowedChars},
|
||||||
{Err: ErrDisallowedChars, Target: ErrMustBeGreater},
|
{A: ErrDisallowedChars, B: ErrMustBeGreater},
|
||||||
|
|
||||||
// Is not any other error
|
// Want not any other error
|
||||||
{Err: ErrDisallowedChars, Target: errors.New("contains disallowed characters")},
|
{A: ErrDisallowedChars, B: errors.New("contains disallowed characters")},
|
||||||
{Err: ErrMustBeGreater, Target: errors.New("must be greater than %v")},
|
{A: ErrMustBeGreater, B: errors.New("must be greater than %v")},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range testCases {
|
for _, testCase := range testCases {
|
||||||
t.Logf("(%d) Testing %v against %v", i, tc.Err, tc.Target)
|
a, b, want := testCase.A, testCase.B, testCase.Want
|
||||||
|
|
||||||
if errors.Is(tc.Err, tc.Target) {
|
t.Run(fmt.Sprintf("%v/%v", a, b), func(t *testing.T) {
|
||||||
if !tc.Is {
|
got := errors.Is(a, b)
|
||||||
t.Errorf("%v should not equal %v", tc.Err, tc.Target)
|
|
||||||
}
|
if got != want {
|
||||||
} else {
|
t.Error("got", got)
|
||||||
if tc.Is {
|
t.Error("want", want)
|
||||||
t.Errorf("%v should equal %v", tc.Err, tc.Target)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module github.com/annybs/go/validate
|
module code.aneur.in/go/validate
|
||||||
|
|
||||||
go 1.21
|
go 1.21
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package validate
|
package validate
|
||||||
|
|
||||||
// Validation error.
|
|
||||||
var (
|
var (
|
||||||
ErrValueNotAllowed = NewError("not allowed")
|
ErrValueNotAllowed = NewError("not allowed")
|
||||||
)
|
)
|
||||||
|
|||||||
+24
-46
@@ -2,59 +2,37 @@ package validate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInInt(t *testing.T) {
|
func ExampleIn() {
|
||||||
type TestCase struct {
|
testIn := In("abc", "def", "xyz")
|
||||||
Input int
|
fmt.Println(testIn("123"))
|
||||||
A []int
|
// Output: not allowed
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
allow := []int{1, 23, 456}
|
|
||||||
testCases := []TestCase{
|
|
||||||
{Input: 1, A: allow},
|
|
||||||
{Input: 23, A: allow},
|
|
||||||
{Input: 456, A: allow},
|
|
||||||
{Input: 789, A: allow, Err: ErrValueNotAllowed},
|
|
||||||
}
|
|
||||||
|
|
||||||
for n, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %d against %v", n, tc.Input, tc.A)
|
|
||||||
|
|
||||||
f := In(tc.A...)
|
|
||||||
err := f(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInString(t *testing.T) {
|
func TestIn(t *testing.T) {
|
||||||
type TestCase struct {
|
testIn := In("abc", "def", "xyz")
|
||||||
Input string
|
|
||||||
A []string
|
testCases := map[string]error{
|
||||||
Err error
|
"abc": nil,
|
||||||
|
"def": nil,
|
||||||
|
"xyz": nil,
|
||||||
|
|
||||||
|
"abcd": ErrValueNotAllowed,
|
||||||
|
"123": ErrValueNotAllowed,
|
||||||
|
"": ErrValueNotAllowed,
|
||||||
}
|
}
|
||||||
|
|
||||||
allow := []string{"abcd", "ef", "1234"}
|
for input, want := range testCases {
|
||||||
testCases := []TestCase{
|
t.Run(input, func(t *testing.T) {
|
||||||
{Input: "abcd", A: allow},
|
got := testIn(input)
|
||||||
{Input: "ef", A: allow},
|
|
||||||
{Input: "1234", A: allow},
|
if !errors.Is(got, want) {
|
||||||
{Input: "5678", A: allow, Err: ErrValueNotAllowed},
|
t.Error("got", got)
|
||||||
}
|
t.Error("want", want)
|
||||||
|
|
||||||
for n, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %q against %v", n, tc.Input, tc.A)
|
|
||||||
|
|
||||||
f := In(tc.A...)
|
|
||||||
err := f(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
package validate
|
package validate
|
||||||
|
|
||||||
// Validation error.
|
|
||||||
var (
|
var (
|
||||||
ErrMustBeLonger = NewError("must be at least %d characters")
|
ErrMustBeLonger = NewError("must contain at least %d characters")
|
||||||
ErrMustBeShorter = NewError("must be no more than %d characters")
|
ErrMustBeShorter = NewError("must contain no more than %d characters")
|
||||||
)
|
)
|
||||||
|
|
||||||
// MaxLength validates the length of a string as being less than or equal to a given maximum.
|
// MaxLength validates the length of a string as being less than or equal to a given maximum.
|
||||||
|
|||||||
+39
-36
@@ -2,57 +2,60 @@ package validate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ExampleMaxLength() {
|
||||||
|
testMaxLength := MaxLength(8)
|
||||||
|
fmt.Println(testMaxLength("this string is too long"))
|
||||||
|
// Output: must contain no more than 8 characters
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleMinLength() {
|
||||||
|
testMinLength := MinLength(8)
|
||||||
|
fmt.Println(testMinLength("2short"))
|
||||||
|
// Output: must contain at least 8 characters
|
||||||
|
}
|
||||||
|
|
||||||
func TestMaxLength(t *testing.T) {
|
func TestMaxLength(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[int]map[string]error{
|
||||||
Input string
|
8: {"abcd": nil, "abcdefgh": nil, "abcd efg": nil, "abcdefghi": ErrMustBeShorter.With(8)},
|
||||||
L int
|
|
||||||
Err error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
for setup, values := range testCases {
|
||||||
{Input: "abcd", L: 8},
|
testMaxLength := MaxLength(setup)
|
||||||
{Input: "abcdefgh", L: 8},
|
|
||||||
{Input: "abcd efg", L: 8},
|
for input, want := range values {
|
||||||
{Input: "abcdefghi", L: 8, Err: ErrMustBeShorter},
|
t.Run(fmt.Sprintf("%d/%s", setup, input), func(t *testing.T) {
|
||||||
|
got := testMaxLength(input)
|
||||||
|
|
||||||
|
if !errors.Is(got, want) {
|
||||||
|
t.Error("got", got)
|
||||||
|
t.Error("want", want)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
for n, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %q against maximum length of %d", n, tc.Input, tc.L)
|
|
||||||
|
|
||||||
f := MaxLength(tc.L)
|
|
||||||
err := f(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMinLength(t *testing.T) {
|
func TestMinLength(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[int]map[string]error{
|
||||||
Input string
|
8: {"abcd": ErrMustBeLonger.With(8), "abcdefgh": nil, "abcd efg": nil, "abcdefghi": nil},
|
||||||
L int
|
|
||||||
Err error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
for setup, values := range testCases {
|
||||||
{Input: "abcd", L: 8, Err: ErrMustBeLonger},
|
testMinLength := MinLength(setup)
|
||||||
{Input: "abcdefgh", L: 8},
|
|
||||||
{Input: "abcd efg", L: 8},
|
for input, want := range values {
|
||||||
{Input: "abcdefghi", L: 8},
|
t.Run(fmt.Sprintf("%d/%s", setup, input), func(t *testing.T) {
|
||||||
|
got := testMinLength(input)
|
||||||
|
|
||||||
|
if !errors.Is(got, want) {
|
||||||
|
t.Error("got", got)
|
||||||
|
t.Error("want", want)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
for n, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %q against minimum length of %d", n, tc.Input, tc.L)
|
|
||||||
|
|
||||||
f := MinLength(tc.L)
|
|
||||||
err := f(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package validate
|
package validate
|
||||||
|
|
||||||
// Validation error.
|
|
||||||
var (
|
var (
|
||||||
ErrMustBeGreater = NewError("must be greater than %v")
|
ErrMustBeGreater = NewError("must be greater than %v")
|
||||||
ErrMustBeGreaterOrEqual = NewError("must be greater than or equal to %v")
|
ErrMustBeGreaterOrEqual = NewError("must be greater than or equal to %v")
|
||||||
|
|||||||
+121
-114
@@ -2,167 +2,174 @@ package validate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ExampleMax() {
|
||||||
|
testMax := Max(10, true)
|
||||||
|
fmt.Println(testMax(10))
|
||||||
|
// Output: must be less than 10
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleMin() {
|
||||||
|
testMin := Min(10, false)
|
||||||
|
fmt.Println(testMin(5))
|
||||||
|
// Output: must be greater than or equal to 10
|
||||||
|
}
|
||||||
|
|
||||||
func TestMax(t *testing.T) {
|
func TestMax(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[int]map[bool]map[int]error{
|
||||||
Input int
|
10: {
|
||||||
N int
|
true: {0: nil, 1: nil, 2: nil, 10: ErrMustBeLess.With(10), 100: ErrMustBeLess.With(10)},
|
||||||
Excl bool
|
false: {0: nil, 1: nil, 2: nil, 10: nil, 100: ErrMustBeLessOrEqual.With(10)},
|
||||||
Err error
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
for setup, subSetup := range testCases {
|
||||||
{Input: 10, N: 0, Err: ErrMustBeLessOrEqual},
|
for excl, values := range subSetup {
|
||||||
{Input: 10, N: 10},
|
testMax := Max(setup, excl)
|
||||||
{Input: 10, N: 15},
|
|
||||||
{Input: 10, N: 10, Excl: true, Err: ErrMustBeLess},
|
for input, want := range values {
|
||||||
|
t.Run(fmt.Sprintf("%d/%v/%d", setup, excl, input), func(t *testing.T) {
|
||||||
|
got := testMax(input)
|
||||||
|
|
||||||
|
if !errors.Is(got, want) {
|
||||||
|
t.Error("got", got)
|
||||||
|
t.Error("want", want)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for n, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %d against maximum of %d", n, tc.Input, tc.N)
|
|
||||||
|
|
||||||
f := Max(tc.N, tc.Excl)
|
|
||||||
err := f(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMaxFloat32(t *testing.T) {
|
func TestMaxFloat32(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[float32]map[bool]map[float32]error{
|
||||||
Input float32
|
10: {
|
||||||
N float32
|
true: {0: nil, 1: nil, 2: nil, 10: ErrMustBeLess.With(10), 100: ErrMustBeLess.With(10)},
|
||||||
Excl bool
|
false: {0: nil, 1: nil, 2: nil, 10: nil, 100: ErrMustBeLessOrEqual.With(10)},
|
||||||
Err error
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
for setup, subSetup := range testCases {
|
||||||
{Input: 10, N: 0, Err: ErrMustBeLessOrEqual},
|
for excl, values := range subSetup {
|
||||||
{Input: 10, N: 10},
|
testMax := MaxFloat32(setup, excl)
|
||||||
{Input: 10, N: 15},
|
|
||||||
{Input: 10, N: 10, Excl: true, Err: ErrMustBeLess},
|
for input, want := range values {
|
||||||
|
t.Run(fmt.Sprintf("%f/%v/%f", setup, excl, input), func(t *testing.T) {
|
||||||
|
got := testMax(input)
|
||||||
|
|
||||||
|
if !errors.Is(got, want) {
|
||||||
|
t.Error("got", got)
|
||||||
|
t.Error("want", want)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for n, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %g against maximum of %g", n, tc.Input, tc.N)
|
|
||||||
|
|
||||||
f := MaxFloat32(tc.N, tc.Excl)
|
|
||||||
err := f(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMaxFloat64(t *testing.T) {
|
func TestMaxFloat64(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[float64]map[bool]map[float64]error{
|
||||||
Input float64
|
10: {
|
||||||
N float64
|
true: {0: nil, 1: nil, 2: nil, 10: ErrMustBeLess.With(10), 100: ErrMustBeLess.With(10)},
|
||||||
Excl bool
|
false: {0: nil, 1: nil, 2: nil, 10: nil, 100: ErrMustBeLessOrEqual.With(10)},
|
||||||
Err error
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
for setup, subSetup := range testCases {
|
||||||
{Input: 10, N: 0, Err: ErrMustBeLessOrEqual},
|
for excl, values := range subSetup {
|
||||||
{Input: 10, N: 10},
|
testMax := MaxFloat64(setup, excl)
|
||||||
{Input: 10, N: 15},
|
|
||||||
{Input: 10, N: 10, Excl: true, Err: ErrMustBeLess},
|
for input, want := range values {
|
||||||
|
t.Run(fmt.Sprintf("%f/%v/%f", setup, excl, input), func(t *testing.T) {
|
||||||
|
got := testMax(input)
|
||||||
|
|
||||||
|
if !errors.Is(got, want) {
|
||||||
|
t.Error("got", got)
|
||||||
|
t.Error("want", want)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for n, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %g against maximum of %g", n, tc.Input, tc.N)
|
|
||||||
|
|
||||||
f := MaxFloat64(tc.N, tc.Excl)
|
|
||||||
err := f(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMin(t *testing.T) {
|
func TestMin(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[int]map[bool]map[int]error{
|
||||||
Input int
|
10: {
|
||||||
N int
|
true: {0: ErrMustBeGreater.With(10), 1: ErrMustBeGreater.With(10), 2: ErrMustBeGreater.With(10), 10: ErrMustBeGreater.With(10), 100: nil},
|
||||||
Excl bool
|
false: {0: ErrMustBeGreaterOrEqual.With(10), 1: ErrMustBeGreaterOrEqual.With(10), 2: ErrMustBeGreaterOrEqual.With(10), 10: nil, 100: nil},
|
||||||
Err error
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
for setup, subSetup := range testCases {
|
||||||
{Input: 10, N: 0},
|
for excl, values := range subSetup {
|
||||||
{Input: 10, N: 10},
|
testMin := Min(setup, excl)
|
||||||
{Input: 10, N: 15, Err: ErrMustBeGreaterOrEqual},
|
|
||||||
{Input: 10, N: 10, Excl: true, Err: ErrMustBeGreater},
|
for input, want := range values {
|
||||||
|
t.Run(fmt.Sprintf("%d/%v/%d", setup, excl, input), func(t *testing.T) {
|
||||||
|
got := testMin(input)
|
||||||
|
|
||||||
|
if !errors.Is(got, want) {
|
||||||
|
t.Error("got", got)
|
||||||
|
t.Error("want", want)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for n, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %d against minimum of %d", n, tc.Input, tc.N)
|
|
||||||
|
|
||||||
f := Min(tc.N, tc.Excl)
|
|
||||||
err := f(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMinFloat32(t *testing.T) {
|
func TestMinFloat32(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[float32]map[bool]map[float32]error{
|
||||||
Input float32
|
10: {
|
||||||
N float32
|
true: {0: ErrMustBeGreater.With(10), 1: ErrMustBeGreater.With(10), 2: ErrMustBeGreater.With(10), 10: ErrMustBeGreater.With(10), 100: nil},
|
||||||
Excl bool
|
false: {0: ErrMustBeGreaterOrEqual.With(10), 1: ErrMustBeGreaterOrEqual.With(10), 2: ErrMustBeGreaterOrEqual.With(10), 10: nil, 100: nil},
|
||||||
Err error
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
for setup, subSetup := range testCases {
|
||||||
{Input: 10, N: 0},
|
for excl, values := range subSetup {
|
||||||
{Input: 10, N: 10},
|
testMin := MinFloat32(setup, excl)
|
||||||
{Input: 10, N: 15, Err: ErrMustBeGreaterOrEqual},
|
|
||||||
{Input: 10, N: 10, Excl: true, Err: ErrMustBeGreater},
|
for input, want := range values {
|
||||||
|
t.Run(fmt.Sprintf("%f/%v/%f", setup, excl, input), func(t *testing.T) {
|
||||||
|
got := testMin(input)
|
||||||
|
|
||||||
|
if !errors.Is(got, want) {
|
||||||
|
t.Error("got", got)
|
||||||
|
t.Error("want", want)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for n, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %g against minimum of %g", n, tc.Input, tc.N)
|
|
||||||
|
|
||||||
f := MinFloat32(tc.N, tc.Excl)
|
|
||||||
err := f(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMinFloat64(t *testing.T) {
|
func TestMinFloat64(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[float64]map[bool]map[float64]error{
|
||||||
Input float64
|
10: {
|
||||||
N float64
|
true: {0: ErrMustBeGreater.With(10), 1: ErrMustBeGreater.With(10), 2: ErrMustBeGreater.With(10), 10: ErrMustBeGreater.With(10), 100: nil},
|
||||||
Excl bool
|
false: {0: ErrMustBeGreaterOrEqual.With(10), 1: ErrMustBeGreaterOrEqual.With(10), 2: ErrMustBeGreaterOrEqual.With(10), 10: nil, 100: nil},
|
||||||
Err error
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
for setup, subSetup := range testCases {
|
||||||
{Input: 10, N: 0},
|
for excl, values := range subSetup {
|
||||||
{Input: 10, N: 10},
|
testMin := MinFloat64(setup, excl)
|
||||||
{Input: 10, N: 15, Err: ErrMustBeGreaterOrEqual},
|
|
||||||
{Input: 10, N: 10, Excl: true, Err: ErrMustBeGreater},
|
for input, want := range values {
|
||||||
|
t.Run(fmt.Sprintf("%f/%v/%f", setup, excl, input), func(t *testing.T) {
|
||||||
|
got := testMin(input)
|
||||||
|
|
||||||
|
if !errors.Is(got, want) {
|
||||||
|
t.Error("got", got)
|
||||||
|
t.Error("want", want)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for n, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %g against minimum of %g", n, tc.Input, tc.N)
|
|
||||||
|
|
||||||
f := MinFloat64(tc.N, tc.Excl)
|
|
||||||
err := f(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package validate
|
package validate
|
||||||
|
|
||||||
// Validation error.
|
|
||||||
var (
|
var (
|
||||||
ErrMustHaveMoreItems = NewError("must have at least %d items")
|
ErrMustHaveMoreItems = NewError("must have at least %d items")
|
||||||
ErrMustHaveFewerItems = NewError("must have no more than %d items")
|
ErrMustHaveFewerItems = NewError("must have no more than %d items")
|
||||||
@@ -10,7 +9,7 @@ var (
|
|||||||
func MaxSize[T any](l int) func([]T) error {
|
func MaxSize[T any](l int) func([]T) error {
|
||||||
return func(value []T) error {
|
return func(value []T) error {
|
||||||
if len(value) > l {
|
if len(value) > l {
|
||||||
return ErrMustHaveFewerItems
|
return ErrMustHaveFewerItems.With(l)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -20,7 +19,7 @@ func MaxSize[T any](l int) func([]T) error {
|
|||||||
func MinSize[T any](l int) func([]T) error {
|
func MinSize[T any](l int) func([]T) error {
|
||||||
return func(value []T) error {
|
return func(value []T) error {
|
||||||
if len(value) < l {
|
if len(value) < l {
|
||||||
return ErrMustHaveMoreItems
|
return ErrMustHaveMoreItems.With(l)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+53
-30
@@ -2,55 +2,78 @@ package validate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ExampleMaxSize() {
|
||||||
|
testMaxSize := MaxSize[string](3)
|
||||||
|
fmt.Println(testMaxSize([]string{"abc", "def", "ghi", "jkl"}))
|
||||||
|
// Output: must have no more than 3 items
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleMinSize() {
|
||||||
|
testMaxSize := MinSize[string](3)
|
||||||
|
fmt.Println(testMaxSize([]string{"abc", "def"}))
|
||||||
|
// Output: must have at least 3 items
|
||||||
|
}
|
||||||
|
|
||||||
func TestMaxSize(t *testing.T) {
|
func TestMaxSize(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[int]map[int]error{
|
||||||
Input []int
|
0: {0: nil, 1: ErrMustHaveFewerItems.With(0), 2: ErrMustHaveFewerItems.With(0), 10: ErrMustHaveFewerItems.With(0)},
|
||||||
L int
|
1: {0: nil, 1: nil, 2: ErrMustHaveFewerItems.With(1), 10: ErrMustHaveFewerItems.With(1)},
|
||||||
Err error
|
2: {0: nil, 1: nil, 2: nil, 10: ErrMustHaveFewerItems.With(2)},
|
||||||
|
10: {0: nil, 1: nil, 2: nil, 10: nil},
|
||||||
|
100: {0: nil, 1: nil, 2: nil, 10: nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
for max, values := range testCases {
|
||||||
{Input: []int{1, 2, 3, 4}, L: 8},
|
testMaxSize := MaxSize[int](max)
|
||||||
{Input: []int{1, 2, 3, 4, 5, 6, 7, 8}, L: 8},
|
|
||||||
{Input: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, L: 8, Err: ErrMustHaveFewerItems},
|
for l, want := range values {
|
||||||
|
t.Run(fmt.Sprintf("%d/%d", max, l), func(t *testing.T) {
|
||||||
|
input := []int{}
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
input = append(input, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
for n, tc := range testCases {
|
got := testMaxSize(input)
|
||||||
t.Logf("(%d) Testing %q against maximum length of %d", n, tc.Input, tc.L)
|
|
||||||
|
|
||||||
f := MaxSize[int](tc.L)
|
if !errors.Is(got, want) {
|
||||||
err := f(tc.Input)
|
t.Error("got", got)
|
||||||
|
t.Error("want", want)
|
||||||
if !errors.Is(err, tc.Err) {
|
}
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMinSize(t *testing.T) {
|
func TestMinSize(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[int]map[int]error{
|
||||||
Input []int
|
0: {0: nil, 1: nil, 2: nil, 10: nil},
|
||||||
L int
|
1: {0: ErrMustHaveMoreItems.With(1), 1: nil, 2: nil, 10: nil},
|
||||||
Err error
|
2: {0: ErrMustHaveMoreItems.With(2), 1: ErrMustHaveMoreItems.With(2), 2: nil, 10: nil},
|
||||||
|
10: {0: ErrMustHaveMoreItems.With(10), 1: ErrMustHaveMoreItems.With(10), 2: ErrMustHaveMoreItems.With(10), 10: nil},
|
||||||
|
100: {0: ErrMustHaveMoreItems.With(100), 1: ErrMustHaveMoreItems.With(100), 2: ErrMustHaveMoreItems.With(100), 10: ErrMustHaveMoreItems.With(100)},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
for min, values := range testCases {
|
||||||
{Input: []int{1, 2, 3, 4}, L: 8, Err: ErrMustHaveMoreItems},
|
testMinSize := MinSize[int](min)
|
||||||
{Input: []int{1, 2, 3, 4, 5, 6, 7, 8}, L: 8},
|
|
||||||
{Input: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, L: 8},
|
for l, want := range values {
|
||||||
|
t.Run(fmt.Sprintf("%d/%d", min, l), func(t *testing.T) {
|
||||||
|
input := []int{}
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
input = append(input, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
for n, tc := range testCases {
|
got := testMinSize(input)
|
||||||
t.Logf("(%d) Testing %q against minimum length of %d", n, tc.Input, tc.L)
|
|
||||||
|
|
||||||
f := MinSize[int](tc.L)
|
if !errors.Is(got, want) {
|
||||||
err := f(tc.Input)
|
t.Error("got", got)
|
||||||
|
t.Error("want", want)
|
||||||
if !errors.Is(err, tc.Err) {
|
}
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package validate
|
|||||||
|
|
||||||
import "net/url"
|
import "net/url"
|
||||||
|
|
||||||
// Validation error.
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidURL Error = NewError("invalid URL")
|
ErrInvalidURL Error = NewError("invalid URL")
|
||||||
)
|
)
|
||||||
|
|||||||
+21
-18
@@ -2,30 +2,33 @@ package validate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ExampleURL() {
|
||||||
|
fmt.Println(URL("not a url"))
|
||||||
|
// Output: invalid URL
|
||||||
|
}
|
||||||
|
|
||||||
func TestURL(t *testing.T) {
|
func TestURL(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[string]error{
|
||||||
Input string
|
"http://example.com": nil,
|
||||||
Err error
|
"http://subdomain.example.com": nil,
|
||||||
|
"http://www.example.com/some-page.html": nil,
|
||||||
|
|
||||||
|
"not a url": ErrInvalidURL,
|
||||||
|
"subdomain.com": ErrInvalidURL,
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
for input, want := range testCases {
|
||||||
{Input: "http://example.com"},
|
t.Run(input, func(t *testing.T) {
|
||||||
{Input: "http://subdomain.example.com"},
|
got := URL(input)
|
||||||
{Input: "http://www.example.com/some-page.html"},
|
|
||||||
{Input: "subdomain.com", Err: ErrInvalidURL},
|
if !errors.Is(got, want) {
|
||||||
{Input: "not a url", Err: ErrInvalidURL},
|
t.Error("got", got)
|
||||||
}
|
t.Error("want", want)
|
||||||
|
|
||||||
for n, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %q", n, tc.Input)
|
|
||||||
|
|
||||||
err := URL(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Validation error.
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidUUID = NewError("invalid UUID")
|
ErrInvalidUUID = NewError("invalid UUID")
|
||||||
)
|
)
|
||||||
|
|||||||
+23
-20
@@ -2,32 +2,35 @@ package validate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ExampleUUID() {
|
||||||
|
fmt.Println(UUID("not a uuid"))
|
||||||
|
// Output: invalid UUID
|
||||||
|
}
|
||||||
|
|
||||||
func TestUUID(t *testing.T) {
|
func TestUUID(t *testing.T) {
|
||||||
type TestCase struct {
|
testCases := map[string]error{
|
||||||
Input string
|
"00000000-0000-0000-0000-000000000000": nil,
|
||||||
Err error
|
"01234567-89ab-cdef-0123-456789abcdef": nil,
|
||||||
|
"abcdef01-2345-6789-abcd-ef0123456789": nil,
|
||||||
|
|
||||||
|
"not a uuid": ErrInvalidUUID,
|
||||||
|
"00000000-00-0000-0000-00000000000000": ErrInvalidUUID,
|
||||||
|
"00000000000000000000000000000000": ErrInvalidUUID,
|
||||||
|
"01234567-89ab-cdef-ghij-klmnopqrstuv": ErrInvalidUUID,
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []TestCase{
|
for input, want := range testCases {
|
||||||
{Input: "00000000-0000-0000-0000-000000000000"},
|
t.Run(input, func(t *testing.T) {
|
||||||
{Input: "01234567-89ab-cdef-0123-456789abcdef"},
|
got := UUID(input)
|
||||||
{Input: "abcdef01-2345-6789-abcd-ef0123456789"},
|
|
||||||
{Input: "Not a UUID", Err: ErrInvalidUUID},
|
if !errors.Is(got, want) {
|
||||||
{Input: "00000000-00-0000-0000-00000000000000", Err: ErrInvalidUUID},
|
t.Error("got", got)
|
||||||
{Input: "00000000000000000000000000000000", Err: ErrInvalidUUID},
|
t.Error("want", want)
|
||||||
{Input: "01234567-89ab-cdef-ghij-klmnopqrstuv", Err: ErrInvalidUUID},
|
|
||||||
}
|
|
||||||
|
|
||||||
for n, tc := range testCases {
|
|
||||||
t.Logf("(%d) Testing %q", n, tc.Input)
|
|
||||||
|
|
||||||
err := UUID(tc.Input)
|
|
||||||
|
|
||||||
if !errors.Is(err, tc.Err) {
|
|
||||||
t.Errorf("Expected error %v, got %v", tc.Err, err)
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user