blob: 9b65909c00d992d13fe6977cfdd8a11563882b3e [file] [log] [blame]
package govalidator
import (
"fmt"
"strings"
"testing"
"time"
)
func init() {
CustomTypeTagMap.Set("customFalseValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool {
return false
}))
CustomTypeTagMap.Set("customTrueValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool {
return true
}))
}
func TestIsAlpha(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"\n", false},
{"\r", false},
{"Ⅸ", false},
{"", true},
{" fooo ", false},
{"abc!!!", false},
{"abc1", false},
{"abc〩", false},
{"abc", true},
{"소주", false},
{"ABC", true},
{"FoObAr", true},
{"소aBC", false},
{"소", false},
{"달기&Co.", false},
{"〩Hours", false},
{"\ufff0", false},
{"\u0070", true}, //UTF-8(ASCII): p
{"\u0026", false}, //UTF-8(ASCII): &
{"\u0030", false}, //UTF-8(ASCII): 0
{"123", false},
{"0123", false},
{"-00123", false},
{"0", false},
{"-0", false},
{"123.123", false},
{" ", false},
{".", false},
{"-1¾", false},
{"1¾", false},
{"〥〩", false},
{"모자", false},
{"ix", true},
{"۳۵۶۰", false},
{"1--", false},
{"1-1", false},
{"-", false},
{"--", false},
{"1++", false},
{"1+1", false},
{"+", false},
{"++", false},
{"+1", false},
}
for _, test := range tests {
actual := IsAlpha(test.param)
if actual != test.expected {
t.Errorf("Expected IsAlpha(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsUTFLetter(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"\n", false},
{"\r", false},
{"Ⅸ", false},
{"", true},
{" fooo ", false},
{"abc!!!", false},
{"abc1", false},
{"abc〩", false},
{"", true},
{"abc", true},
{"소주", true},
{"ABC", true},
{"FoObAr", true},
{"소aBC", true},
{"소", true},
{"달기&Co.", false},
{"〩Hours", false},
{"\ufff0", false},
{"\u0070", true}, //UTF-8(ASCII): p
{"\u0026", false}, //UTF-8(ASCII): &
{"\u0030", false}, //UTF-8(ASCII): 0
{"123", false},
{"0123", false},
{"-00123", false},
{"0", false},
{"-0", false},
{"123.123", false},
{" ", false},
{".", false},
{"-1¾", false},
{"1¾", false},
{"〥〩", false},
{"모자", true},
{"ix", true},
{"۳۵۶۰", false},
{"1--", false},
{"1-1", false},
{"-", false},
{"--", false},
{"1++", false},
{"1+1", false},
{"+", false},
{"++", false},
{"+1", false},
}
for _, test := range tests {
actual := IsUTFLetter(test.param)
if actual != test.expected {
t.Errorf("Expected IsUTFLetter(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsAlphanumeric(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"\n", false},
{"\r", false},
{"Ⅸ", false},
{"", true},
{" fooo ", false},
{"abc!!!", false},
{"abc123", true},
{"ABC111", true},
{"abc1", true},
{"abc〩", false},
{"abc", true},
{"소주", false},
{"ABC", true},
{"FoObAr", true},
{"소aBC", false},
{"소", false},
{"달기&Co.", false},
{"〩Hours", false},
{"\ufff0", false},
{"\u0070", true}, //UTF-8(ASCII): p
{"\u0026", false}, //UTF-8(ASCII): &
{"\u0030", true}, //UTF-8(ASCII): 0
{"123", true},
{"0123", true},
{"-00123", false},
{"0", true},
{"-0", false},
{"123.123", false},
{" ", false},
{".", false},
{"-1¾", false},
{"1¾", false},
{"〥〩", false},
{"모자", false},
{"ix", true},
{"۳۵۶۰", false},
{"1--", false},
{"1-1", false},
{"-", false},
{"--", false},
{"1++", false},
{"1+1", false},
{"+", false},
{"++", false},
{"+1", false},
}
for _, test := range tests {
actual := IsAlphanumeric(test.param)
if actual != test.expected {
t.Errorf("Expected IsAlphanumeric(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsUTFLetterNumeric(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"\n", false},
{"\r", false},
{"Ⅸ", true},
{"", true},
{" fooo ", false},
{"abc!!!", false},
{"abc1", true},
{"abc〩", true},
{"abc", true},
{"소주", true},
{"ABC", true},
{"FoObAr", true},
{"소aBC", true},
{"소", true},
{"달기&Co.", false},
{"〩Hours", true},
{"\ufff0", false},
{"\u0070", true}, //UTF-8(ASCII): p
{"\u0026", false}, //UTF-8(ASCII): &
{"\u0030", true}, //UTF-8(ASCII): 0
{"123", true},
{"0123", true},
{"-00123", false},
{"0", true},
{"-0", false},
{"123.123", false},
{" ", false},
{".", false},
{"-1¾", false},
{"1¾", true},
{"〥〩", true},
{"모자", true},
{"ix", true},
{"۳۵۶۰", true},
{"1--", false},
{"1-1", false},
{"-", false},
{"--", false},
{"1++", false},
{"1+1", false},
{"+", false},
{"++", false},
{"+1", false},
}
for _, test := range tests {
actual := IsUTFLetterNumeric(test.param)
if actual != test.expected {
t.Errorf("Expected IsUTFLetterNumeric(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsNumeric(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"\n", false},
{"\r", false},
{"Ⅸ", false},
{"", true},
{" fooo ", false},
{"abc!!!", false},
{"abc1", false},
{"abc〩", false},
{"abc", false},
{"소주", false},
{"ABC", false},
{"FoObAr", false},
{"소aBC", false},
{"소", false},
{"달기&Co.", false},
{"〩Hours", false},
{"\ufff0", false},
{"\u0070", false}, //UTF-8(ASCII): p
{"\u0026", false}, //UTF-8(ASCII): &
{"\u0030", true}, //UTF-8(ASCII): 0
{"123", true},
{"0123", true},
{"-00123", false},
{"+00123", false},
{"0", true},
{"-0", false},
{"123.123", false},
{" ", false},
{".", false},
{"12𐅪3", false},
{"-1¾", false},
{"1¾", false},
{"〥〩", false},
{"모자", false},
{"ix", false},
{"۳۵۶۰", false},
{"1--", false},
{"1-1", false},
{"-", false},
{"--", false},
{"1++", false},
{"1+1", false},
{"+", false},
{"++", false},
{"+1", false},
}
for _, test := range tests {
actual := IsNumeric(test.param)
if actual != test.expected {
t.Errorf("Expected IsNumeric(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsUTFNumeric(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"\n", false},
{"\r", false},
{"Ⅸ", true},
{"", true},
{" fooo ", false},
{"abc!!!", false},
{"abc1", false},
{"abc〩", false},
{"abc", false},
{"소주", false},
{"ABC", false},
{"FoObAr", false},
{"소aBC", false},
{"소", false},
{"달기&Co.", false},
{"〩Hours", false},
{"\ufff0", false},
{"\u0070", false}, //UTF-8(ASCII): p
{"\u0026", false}, //UTF-8(ASCII): &
{"\u0030", true}, //UTF-8(ASCII): 0
{"123", true},
{"0123", true},
{"-00123", true},
{"0", true},
{"-0", true},
{"--0", false},
{"-0-", false},
{"123.123", false},
{" ", false},
{".", false},
{"12𐅪3", true},
{"-1¾", true},
{"1¾", true},
{"〥〩", true},
{"모자", false},
{"ix", false},
{"۳۵۶۰", true},
{"1++", false},
{"1+1", false},
{"+", false},
{"++", false},
{"+1", true},
}
for _, test := range tests {
actual := IsUTFNumeric(test.param)
if actual != test.expected {
t.Errorf("Expected IsUTFNumeric(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsUTFDigit(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"\n", false},
{"\r", false},
{"Ⅸ", false},
{"", true},
{" fooo ", false},
{"abc!!!", false},
{"abc1", false},
{"abc〩", false},
{"abc", false},
{"소주", false},
{"ABC", false},
{"FoObAr", false},
{"소aBC", false},
{"소", false},
{"달기&Co.", false},
{"〩Hours", false},
{"\ufff0", false},
{"\u0070", false}, //UTF-8(ASCII): p
{"\u0026", false}, //UTF-8(ASCII): &
{"\u0030", true}, //UTF-8(ASCII): 0
{"123", true},
{"0123", true},
{"-00123", true},
{"0", true},
{"-0", true},
{"--0", false},
{"-0-", false},
{"123.123", false},
{" ", false},
{".", false},
{"12𐅪3", false},
{"1483920", true},
{"", true},
{"۳۵۶۰", true},
{"-29", true},
{"-1¾", false},
{"1¾", false},
{"〥〩", false},
{"모자", false},
{"ix", false},
{"۳۵۶۰", true},
{"1++", false},
{"1+1", false},
{"+", false},
{"++", false},
{"+1", true},
}
for _, test := range tests {
actual := IsUTFDigit(test.param)
if actual != test.expected {
t.Errorf("Expected IsUTFDigit(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsLowerCase(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", true},
{"abc123", true},
{"abc", true},
{"a b c", true},
{"abcß", true},
{"abcẞ", false},
{"ABCẞ", false},
{"tr竪s 端ber", true},
{"fooBar", false},
{"123ABC", false},
{"ABC123", false},
{"ABC", false},
{"S T R", false},
{"fooBar", false},
{"abacaba123", true},
}
for _, test := range tests {
actual := IsLowerCase(test.param)
if actual != test.expected {
t.Errorf("Expected IsLowerCase(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsUpperCase(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", true},
{"abc123", false},
{"abc", false},
{"a b c", false},
{"abcß", false},
{"abcẞ", false},
{"ABCẞ", true},
{"tr竪s 端ber", false},
{"fooBar", false},
{"123ABC", true},
{"ABC123", true},
{"ABC", true},
{"S T R", true},
{"fooBar", false},
{"abacaba123", false},
}
for _, test := range tests {
actual := IsUpperCase(test.param)
if actual != test.expected {
t.Errorf("Expected IsUpperCase(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestHasLowerCase(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", true},
{"abc123", true},
{"abc", true},
{"a b c", true},
{"abcß", true},
{"abcẞ", true},
{"ABCẞ", false},
{"tr竪s 端ber", true},
{"fooBar", true},
{"123ABC", false},
{"ABC123", false},
{"ABC", false},
{"S T R", false},
{"fooBar", true},
{"abacaba123", true},
{"FÒÔBÀŘ", false},
{"fòôbàř", true},
{"fÒÔBÀŘ", true},
}
for _, test := range tests {
actual := HasLowerCase(test.param)
if actual != test.expected {
t.Errorf("Expected HasLowerCase(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestHasUpperCase(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", true},
{"abc123", false},
{"abc", false},
{"a b c", false},
{"abcß", false},
{"abcẞ", false},
{"ABCẞ", true},
{"tr竪s 端ber", false},
{"fooBar", true},
{"123ABC", true},
{"ABC123", true},
{"ABC", true},
{"S T R", true},
{"fooBar", true},
{"abacaba123", false},
{"FÒÔBÀŘ", true},
{"fòôbàř", false},
{"Fòôbàř", true},
}
for _, test := range tests {
actual := HasUpperCase(test.param)
if actual != test.expected {
t.Errorf("Expected HasUpperCase(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsInt(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"-2147483648", true}, //Signed 32 Bit Min Int
{"2147483647", true}, //Signed 32 Bit Max Int
{"-2147483649", true}, //Signed 32 Bit Min Int - 1
{"2147483648", true}, //Signed 32 Bit Max Int + 1
{"4294967295", true}, //Unsigned 32 Bit Max Int
{"4294967296", true}, //Unsigned 32 Bit Max Int + 1
{"-9223372036854775808", true}, //Signed 64 Bit Min Int
{"9223372036854775807", true}, //Signed 64 Bit Max Int
{"-9223372036854775809", true}, //Signed 64 Bit Min Int - 1
{"9223372036854775808", true}, //Signed 64 Bit Max Int + 1
{"18446744073709551615", true}, //Unsigned 64 Bit Max Int
{"18446744073709551616", true}, //Unsigned 64 Bit Max Int + 1
{"", true},
{"123", true},
{"0", true},
{"-0", true},
{"+0", true},
{"01", false},
{"123.123", false},
{" ", false},
{"000", false},
}
for _, test := range tests {
actual := IsInt(test.param)
if actual != test.expected {
t.Errorf("Expected IsInt(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsHash(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
algo string
expected bool
}{
{"3ca25ae354e192b26879f651a51d92aa8a34d8d3", "sha1", true},
{"3ca25ae354e192b26879f651a51d34d8d3", "sha1", false},
{"3ca25ae354e192b26879f651a51d92aa8a34d8d3", "Tiger160", true},
{"3ca25ae354e192b26879f651a51d34d8d3", "ripemd160", false},
{"579282cfb65ca1f109b78536effaf621b853c9f7079664a3fbe2b519f435898c", "sha256", true},
{"579282cfb65ca1f109b78536effaf621b853c9f7079664a3fbe2b519f435898casfdsafsadfsdf", "sha256", false},
{"bf547c3fc5841a377eb1519c2890344dbab15c40ae4150b4b34443d2212e5b04aa9d58865bf03d8ae27840fef430b891", "sha384", true},
{"579282cfb65ca1f109b78536effaf621b853c9f7079664a3fbe2b519f435898casfdsafsadfsdf", "sha384", false},
{"45bc5fa8cb45ee408c04b6269e9f1e1c17090c5ce26ffeeda2af097735b29953ce547e40ff3ad0d120e5361cc5f9cee35ea91ecd4077f3f589b4d439168f91b9", "sha512", true},
{"579282cfb65ca1f109b78536effaf621b853c9f7079664a3fbe2b519f435898casfdsafsadfsdf", "sha512", false},
{"46fc0125a148788a3ac1d649566fc04eb84a746f1a6e4fa7", "tiger192", true},
{"46fc0125a148788a3ac1d649566fc04eb84a746f1a6$$%@^", "TIGER192", false},
{"46fc0125a148788a3ac1d649566fc04eb84a746f1a6$$%@^", "SOMEHASH", false},
}
for _, test := range tests {
actual := IsHash(test.param, test.algo)
if actual != test.expected {
t.Errorf("Expected IsHash(%q, %q) to be %v, got %v", test.param, test.algo, test.expected, actual)
}
}
}
func TestIsExistingEmail(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"foo@bar.com", true},
{"foo@bar.com.au", true},
{"foo+bar@bar.com", true},
{"foo@bar.coffee..coffee", false},
{"invalidemail@", false},
{"invalid.com", false},
{"@invalid.com", false},
{"NathAn.daVIeS@DomaIn.cOM", true},
{"NATHAN.DAVIES@DOMAIN.CO.UK", true},
}
for _, test := range tests {
actual := IsExistingEmail(test.param)
if actual != test.expected {
t.Errorf("Expected IsExistingEmail(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsEmail(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"foo@bar.com", true},
{"x@x.x", true},
{"foo@bar.com.au", true},
{"foo+bar@bar.com", true},
{"foo@bar.coffee", true},
{"foo@bar.coffee..coffee", false},
{"foo@bar.bar.coffee", true},
{"foo@bar.中文网", true},
{"invalidemail@", false},
{"invalid.com", false},
{"@invalid.com", false},
{"test|123@m端ller.com", true},
{"hans@m端ller.com", true},
{"hans.m端ller@test.com", true},
{"NathAn.daVIeS@DomaIn.cOM", true},
{"NATHAN.DAVIES@DOMAIN.CO.UK", true},
}
for _, test := range tests {
actual := IsEmail(test.param)
if actual != test.expected {
t.Errorf("Expected IsEmail(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsURL(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"http://foo.bar#com", true},
{"http://foobar.com", true},
{"https://foobar.com", true},
{"foobar.com", true},
{"http://foobar.coffee/", true},
{"http://foobar.中文网/", true},
{"http://foobar.org/", true},
{"http://foobar.ORG", true},
{"http://foobar.org:8080/", true},
{"ftp://foobar.ru/", true},
{"ftp.foo.bar", true},
{"http://user:pass@www.foobar.com/", true},
{"http://user:pass@www.foobar.com/path/file", true},
{"http://127.0.0.1/", true},
{"http://duckduckgo.com/?q=%2F", true},
{"http://localhost:3000/", true},
{"http://foobar.com/?foo=bar#baz=qux", true},
{"http://foobar.com?foo=bar", true},
{"http://www.xn--froschgrn-x9a.net/", true},
{"http://foobar.com/a-", true},
{"http://foobar.پاکستان/", true},
{"http://foobar.c_o_m", false},
{"http://_foobar.com", false},
{"http://foo_bar.com", true},
{"http://user:pass@foo_bar_bar.bar_foo.com", true},
{"", false},
{"xyz://foobar.com", false},
// {"invalid.", false}, is it false like "localhost."?
{".com", false},
{"rtmp://foobar.com", false},
{"http://localhost:3000/", true},
{"http://foobar.com#baz=qux", true},
{"http://foobar.com/t$-_.+!*\\'(),", true},
{"http://www.foobar.com/~foobar", true},
{"http://www.-foobar.com/", false},
{"http://www.foo---bar.com/", false},
{"http://r6---snnvoxuioq6.googlevideo.com", true},
{"mailto:someone@example.com", true},
{"irc://irc.server.org/channel", false},
{"irc://#channel@network", true},
{"/abs/test/dir", false},
{"./rel/test/dir", false},
{"http://foo^bar.org", false},
{"http://foo&*bar.org", false},
{"http://foo&bar.org", false},
{"http://foo bar.org", false},
{"http://foo.bar.org", true},
{"http://www.foo.bar.org", true},
{"http://www.foo.co.uk", true},
{"foo", false},
{"http://.foo.com", false},
{"http://,foo.com", false},
{",foo.com", false},
{"http://myservice.:9093/", true},
// according to issues #62 #66
{"https://pbs.twimg.com/profile_images/560826135676588032/j8fWrmYY_normal.jpeg", true},
// according to #125
{"http://prometheus-alertmanager.service.q:9093", true},
{"aio1_alertmanager_container-63376c45:9093", true},
{"https://www.logn-123-123.url.with.sigle.letter.d:12345/url/path/foo?bar=zzz#user", true},
{"http://me.example.com", true},
{"http://www.me.example.com", true},
{"https://farm6.static.flickr.com", true},
{"https://zh.wikipedia.org/wiki/Wikipedia:%E9%A6%96%E9%A1%B5", true},
{"google", false},
// According to #87
{"http://hyphenated-host-name.example.co.in", true},
{"http://cant-end-with-hyphen-.example.com", false},
{"http://-cant-start-with-hyphen.example.com", false},
{"http://www.domain-can-have-dashes.com", true},
{"http://m.abcd.com/test.html", true},
{"http://m.abcd.com/a/b/c/d/test.html?args=a&b=c", true},
{"http://[::1]:9093", true},
{"http://[::1]:909388", false},
{"1200::AB00:1234::2552:7777:1313", false},
{"http://[2001:db8:a0b:12f0::1]/index.html", true},
{"http://[1200:0000:AB00:1234:0000:2552:7777:1313]", true},
{"http://user:pass@[::1]:9093/a/b/c/?a=v#abc", true},
{"https://127.0.0.1/a/b/c?a=v&c=11d", true},
{"https://foo_bar.example.com", true},
{"http://foo_bar.example.com", true},
{"http://foo_bar_fizz_buzz.example.com", true},
{"http://_cant_start_with_underescore", false},
{"http://cant_end_with_underescore_", false},
{"foo_bar.example.com", true},
{"foo_bar_fizz_buzz.example.com", true},
{"http://hello_world.example.com", true},
// According to #212
{"foo_bar-fizz-buzz:1313", true},
{"foo_bar-fizz-buzz:13:13", false},
{"foo_bar-fizz-buzz://1313", false},
}
for _, test := range tests {
actual := IsURL(test.param)
if actual != test.expected {
t.Errorf("Expected IsURL(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsRequestURL(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"http://foo.bar/#com", true},
{"http://foobar.com", true},
{"https://foobar.com", true},
{"foobar.com", false},
{"http://foobar.coffee/", true},
{"http://foobar.中文网/", true},
{"http://foobar.org/", true},
{"http://foobar.org:8080/", true},
{"ftp://foobar.ru/", true},
{"http://user:pass@www.foobar.com/", true},
{"http://127.0.0.1/", true},
{"http://duckduckgo.com/?q=%2F", true},
{"http://localhost:3000/", true},
{"http://foobar.com/?foo=bar#baz=qux", true},
{"http://foobar.com?foo=bar", true},
{"http://www.xn--froschgrn-x9a.net/", true},
{"", false},
{"xyz://foobar.com", true},
{"invalid.", false},
{".com", false},
{"rtmp://foobar.com", true},
{"http://www.foo_bar.com/", true},
{"http://localhost:3000/", true},
{"http://foobar.com/#baz=qux", true},
{"http://foobar.com/t$-_.+!*\\'(),", true},
{"http://www.foobar.com/~foobar", true},
{"http://www.-foobar.com/", true},
{"http://www.foo---bar.com/", true},
{"mailto:someone@example.com", true},
{"irc://irc.server.org/channel", true},
{"/abs/test/dir", false},
{"./rel/test/dir", false},
}
for _, test := range tests {
actual := IsRequestURL(test.param)
if actual != test.expected {
t.Errorf("Expected IsRequestURL(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsRequestURI(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"http://foo.bar/#com", true},
{"http://foobar.com", true},
{"https://foobar.com", true},
{"foobar.com", false},
{"http://foobar.coffee/", true},
{"http://foobar.中文网/", true},
{"http://foobar.org/", true},
{"http://foobar.org:8080/", true},
{"ftp://foobar.ru/", true},
{"http://user:pass@www.foobar.com/", true},
{"http://127.0.0.1/", true},
{"http://duckduckgo.com/?q=%2F", true},
{"http://localhost:3000/", true},
{"http://foobar.com/?foo=bar#baz=qux", true},
{"http://foobar.com?foo=bar", true},
{"http://www.xn--froschgrn-x9a.net/", true},
{"xyz://foobar.com", true},
{"invalid.", false},
{".com", false},
{"rtmp://foobar.com", true},
{"http://www.foo_bar.com/", true},
{"http://localhost:3000/", true},
{"http://foobar.com/#baz=qux", true},
{"http://foobar.com/t$-_.+!*\\'(),", true},
{"http://www.foobar.com/~foobar", true},
{"http://www.-foobar.com/", true},
{"http://www.foo---bar.com/", true},
{"mailto:someone@example.com", true},
{"irc://irc.server.org/channel", true},
{"/abs/test/dir", true},
{"./rel/test/dir", false},
}
for _, test := range tests {
actual := IsRequestURI(test.param)
if actual != test.expected {
t.Errorf("Expected IsRequestURI(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsFloat(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{" ", false},
{"-.123", false},
{"abacaba", false},
{"1f", false},
{"-1f", false},
{"+1f", false},
{"123", true},
{"123.", true},
{"123.123", true},
{"-123.123", true},
{"+123.123", true},
{"0.123", true},
{"-0.123", true},
{"+0.123", true},
{".0", true},
{"01.123", true},
{"-0.22250738585072011e-307", true},
{"+0.22250738585072011e-307", true},
}
for _, test := range tests {
actual := IsFloat(test.param)
if actual != test.expected {
t.Errorf("Expected IsFloat(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsHexadecimal(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"abcdefg", false},
{"", false},
{"..", false},
{"deadBEEF", true},
{"ff0044", true},
}
for _, test := range tests {
actual := IsHexadecimal(test.param)
if actual != test.expected {
t.Errorf("Expected IsHexadecimal(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsHexcolor(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"#ff", false},
{"fff0", false},
{"#ff12FG", false},
{"CCccCC", true},
{"fff", true},
{"#f00", true},
}
for _, test := range tests {
actual := IsHexcolor(test.param)
if actual != test.expected {
t.Errorf("Expected IsHexcolor(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsRGBcolor(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"rgb(0,31,255)", true},
{"rgb(1,349,275)", false},
{"rgb(01,31,255)", false},
{"rgb(0.6,31,255)", false},
{"rgba(0,31,255)", false},
{"rgb(0, 31, 255)", true},
}
for _, test := range tests {
actual := IsRGBcolor(test.param)
if actual != test.expected {
t.Errorf("Expected IsRGBcolor(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsNull(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"abacaba", false},
{"", true},
}
for _, test := range tests {
actual := IsNull(test.param)
if actual != test.expected {
t.Errorf("Expected IsNull(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestHasWhitespaceOnly(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"abacaba", false},
{"", false},
{" ", true},
{" \r\n ", true},
{"\014\012\011\013\015", true},
{"\014\012\011\013 abc \015", false},
{"\f\n\t\v\r\f", true},
{"x\n\t\t\t\t", false},
{"\f\n\t \n\n\n \v\r\f", true},
}
for _, test := range tests {
actual := HasWhitespaceOnly(test.param)
if actual != test.expected {
t.Errorf("Expected HasWhitespaceOnly(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestHasWhitespace(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"abacaba", false},
{"", false},
{" ", true},
{" \r\n ", true},
{"\014\012\011\013\015", true},
{"\014\012\011\013 abc \015", true},
{"\f\n\t\v\r\f", true},
{"x\n\t\t\t\t", true},
{"\f\n\t \n\n\n \v\r\f", true},
}
for _, test := range tests {
actual := HasWhitespace(test.param)
if actual != test.expected {
t.Errorf("Expected HasWhitespace(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsDivisibleBy(t *testing.T) {
t.Parallel()
var tests = []struct {
param1 string
param2 string
expected bool
}{
{"4", "2", true},
{"100", "10", true},
{"", "1", true},
{"123", "foo", false},
{"123", "0", false},
}
for _, test := range tests {
actual := IsDivisibleBy(test.param1, test.param2)
if actual != test.expected {
t.Errorf("Expected IsDivisibleBy(%q, %q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
}
}
}
// This small example illustrate how to work with IsDivisibleBy function.
func ExampleIsDivisibleBy() {
println("1024 is divisible by 64: ", IsDivisibleBy("1024", "64"))
}
func TestIsByteLength(t *testing.T) {
t.Parallel()
var tests = []struct {
param1 string
param2 int
param3 int
expected bool
}{
{"abacaba", 100, -1, false},
{"abacaba", 1, 3, false},
{"abacaba", 1, 7, true},
{"abacaba", 0, 8, true},
{"\ufff0", 1, 1, false},
}
for _, test := range tests {
actual := IsByteLength(test.param1, test.param2, test.param3)
if actual != test.expected {
t.Errorf("Expected IsByteLength(%q, %q, %q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual)
}
}
}
func TestIsJSON(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"145", true},
{"asdf", false},
{"123:f00", false},
{"{\"Name\":\"Alice\",\"Body\":\"Hello\",\"Time\":1294706395881547000}", true},
{"{}", true},
{"{\"Key\":{\"Key\":{\"Key\":123}}}", true},
{"[]", true},
{"null", true},
}
for _, test := range tests {
actual := IsJSON(test.param)
if actual != test.expected {
t.Errorf("Expected IsJSON(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsMultibyte(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"abc", false},
{"123", false},
{"<>@;.-=", false},
{"ひらがな・カタカナ、.漢字", true},
{"あいうえお foobar", true},
{"test@example.com", true},
{"test@example.com", true},
{"1234abcDExyz", true},
{"カタカナ", true},
{"", true},
}
for _, test := range tests {
actual := IsMultibyte(test.param)
if actual != test.expected {
t.Errorf("Expected IsMultibyte(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsASCII(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", true},
{"foobar", false},
{"xyz098", false},
{"123456", false},
{"カタカナ", false},
{"foobar", true},
{"0987654321", true},
{"test@example.com", true},
{"1234abcDEF", true},
{"", true},
}
for _, test := range tests {
actual := IsASCII(test.param)
if actual != test.expected {
t.Errorf("Expected IsASCII(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsPrintableASCII(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", true},
{"foobar", false},
{"xyz098", false},
{"123456", false},
{"カタカナ", false},
{"foobar", true},
{"0987654321", true},
{"test@example.com", true},
{"1234abcDEF", true},
{"newline\n", false},
{"\x19test\x7F", false},
}
for _, test := range tests {
actual := IsPrintableASCII(test.param)
if actual != test.expected {
t.Errorf("Expected IsPrintableASCII(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsFullWidth(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", true},
{"abc", false},
{"abc123", false},
{"!\"#$%&()<>/+=-_? ~^|.,@`{}[]", false},
{"ひらがな・カタカナ、.漢字", true},
{"3ー0 a@com", true},
{"Fカタカナ゙ᆲ", true},
{"Good=Parts", true},
{"", true},
}
for _, test := range tests {
actual := IsFullWidth(test.param)
if actual != test.expected {
t.Errorf("Expected IsFullWidth(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsHalfWidth(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", true},
{"あいうえお", false},
{"0011", false},
{"!\"#$%&()<>/+=-_? ~^|.,@`{}[]", true},
{"l-btn_02--active", true},
{"abc123い", true},
{"カタカナ゙ᆲ←", true},
{"", true},
}
for _, test := range tests {
actual := IsHalfWidth(test.param)
if actual != test.expected {
t.Errorf("Expected IsHalfWidth(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsVariableWidth(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", true},
{"ひらがなカタカナ漢字ABCDE", true},
{"3ー0123", true},
{"Fカタカナ゙ᆲ", true},
{"", true},
{"Good=Parts", true},
{"abc", false},
{"abc123", false},
{"!\"#$%&()<>/+=-_? ~^|.,@`{}[]", false},
{"ひらがな・カタカナ、.漢字", false},
{"123456", false},
{"カタカナ゙ᆲ", false},
}
for _, test := range tests {
actual := IsVariableWidth(test.param)
if actual != test.expected {
t.Errorf("Expected IsVariableWidth(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsUUID(t *testing.T) {
t.Parallel()
// Tests without version
var tests = []struct {
param string
expected bool
}{
{"", false},
{"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false},
{"a987fbc9-4bed-3078-cf07-9141ba07c9f3xxx", false},
{"a987fbc94bed3078cf079141ba07c9f3", false},
{"934859", false},
{"987fbc9-4bed-3078-cf07a-9141ba07c9f3", false},
{"aaaaaaaa-1111-1111-aaag-111111111111", false},
{"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true},
}
for _, test := range tests {
actual := IsUUID(test.param)
if actual != test.expected {
t.Errorf("Expected IsUUID(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
// UUID ver. 3
tests = []struct {
param string
expected bool
}{
{"", false},
{"412452646", false},
{"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false},
{"a987fbc9-4bed-4078-8f07-9141ba07c9f3", false},
{"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true},
}
for _, test := range tests {
actual := IsUUIDv3(test.param)
if actual != test.expected {
t.Errorf("Expected IsUUIDv3(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
// UUID ver. 4
tests = []struct {
param string
expected bool
}{
{"", false},
{"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false},
{"a987fbc9-4bed-5078-af07-9141ba07c9f3", false},
{"934859", false},
{"57b73598-8764-4ad0-a76a-679bb6640eb1", true},
{"625e63f3-58f5-40b7-83a1-a72ad31acffb", true},
}
for _, test := range tests {
actual := IsUUIDv4(test.param)
if actual != test.expected {
t.Errorf("Expected IsUUIDv4(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
// UUID ver. 5
tests = []struct {
param string
expected bool
}{
{"", false},
{"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false},
{"9c858901-8a57-4791-81fe-4c455b099bc9", false},
{"a987fbc9-4bed-3078-cf07-9141ba07c9f3", false},
{"987fbc97-4bed-5078-af07-9141ba07c9f3", true},
{"987fbc97-4bed-5078-9f07-9141ba07c9f3", true},
}
for _, test := range tests {
actual := IsUUIDv5(test.param)
if actual != test.expected {
t.Errorf("Expected IsUUIDv5(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsCreditCard(t *testing.T) {
t.Parallel()
tests := []struct {
name string
number string
want bool
}{
{"empty", "", false},
{"not numbers", "credit card", false},
{"invalid luhn algorithm", "4220855426213389", false},
{"visa", "4220855426222389", true},
{"visa spaces", "4220 8554 2622 2389", true},
{"visa dashes", "4220-8554-2622-2389", true},
{"mastercard", "5139288802098206", true},
{"american express", "374953669708156", true},
{"discover", "6011464355444102", true},
{"jcb", "3548209662790989", true},
// below should be valid, do they respect international standards?
// is our validator logic not correct?
{"diners club international", "30190239451016", false},
{"rupay", "6521674451993089", false},
{"mir", "2204151414444676", false},
{"china unionPay", "624356436327468104", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsCreditCard(tt.number); got != tt.want {
t.Errorf("IsCreditCard(%v) = %v, want %v", tt.number, got, tt.want)
}
})
}
}
func TestIsISBN(t *testing.T) {
t.Parallel()
// Without version
var tests = []struct {
param string
expected bool
}{
{"", false},
{"foo", false},
{"3836221195", true},
{"1-61729-085-8", true},
{"3 423 21412 0", true},
{"3 401 01319 X", true},
{"9784873113685", true},
{"978-4-87311-368-5", true},
{"978 3401013190", true},
{"978-3-8362-2119-1", true},
}
for _, test := range tests {
actual := IsISBN(test.param, -1)
if actual != test.expected {
t.Errorf("Expected IsISBN(%q, -1) to be %v, got %v", test.param, test.expected, actual)
}
}
// ISBN 10
tests = []struct {
param string
expected bool
}{
{"", false},
{"foo", false},
{"3423214121", false},
{"978-3836221191", false},
{"3-423-21412-1", false},
{"3 423 21412 1", false},
{"3836221195", true},
{"1-61729-085-8", true},
{"3 423 21412 0", true},
{"3 401 01319 X", true},
}
for _, test := range tests {
actual := IsISBN10(test.param)
if actual != test.expected {
t.Errorf("Expected IsISBN10(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
// ISBN 13
tests = []struct {
param string
expected bool
}{
{"", false},
{"foo", false},
{"3-8362-2119-5", false},
{"01234567890ab", false},
{"978 3 8362 2119 0", false},
{"9784873113685", true},
{"978-4-87311-368-5", true},
{"978 3401013190", true},
{"978-3-8362-2119-1", true},
}
for _, test := range tests {
actual := IsISBN13(test.param)
if actual != test.expected {
t.Errorf("Expected IsISBN13(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsDataURI(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"data:image/png;base64,TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", true},
{"data:text/plain;base64,Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==", true},
{"image/gif;base64,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false},
{"data:image/gif;base64,MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw" +
"UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye" +
"rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619" +
"FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx" +
"QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ" +
"Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ" + "HQIDAQAB", true},
{"data:image/png;base64,12345", false},
{"", false},
{"data:text,:;base85,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false},
}
for _, test := range tests {
actual := IsDataURI(test.param)
if actual != test.expected {
t.Errorf("Expected IsDataURI(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsMagnetURI(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"magnet:?xt=urn:btih:06E2A9683BF4DA92C73A661AC56F0ECC9C63C5B4&dn=helloword2000&tr=udp://helloworld:1337/announce", true},
{"magnet:?xt=urn:btih:3E30322D5BFC7444B7B1D8DD42404B75D0531DFB&dn=world&tr=udp://world.com:1337", true},
{"magnet:?xt=urn:btih:4ODKSDJBVMSDSNJVBCBFYFBKNRU875DW8D97DWC6&dn=helloworld&tr=udp://helloworld.com:1337", true},
{"magnet:?xt=urn:btih:1GSHJVBDVDVJFYEHKFHEFIO8573898434JBFEGHD&dn=foo&tr=udp://foo.com:1337", true},
{"magnet:?xt=urn:btih:MCJDCYUFHEUD6E2752T7UJNEKHSUGEJFGTFHVBJS&dn=bar&tr=udp://bar.com:1337", true},
{"magnet:?xt=urn:btih:LAKDHWDHEBFRFVUFJENBYYTEUY837562JH2GEFYH&dn=foobar&tr=udp://foobar.com:1337", true},
{"magnet:?xt=urn:btih:MKCJBHCBJDCU725TGEB3Y6RE8EJ2U267UNJFGUID&dn=test&tr=udp://test.com:1337", true},
{"magnet:?xt=urn:btih:UHWY2892JNEJ2GTEYOMDNU67E8ICGICYE92JDUGH&dn=baz&tr=udp://baz.com:1337", true},
{"magnet:?xt=urn:btih:HS263FG8U3GFIDHWD7829BYFCIXB78XIHG7CWCUG&dn=foz&tr=udp://foz.com:1337", true},
{"", false},
{":?xt=urn:btih:06E2A9683BF4DA92C73A661AC56F0ECC9C63C5B4&dn=helloword2000&tr=udp://helloworld:1337/announce", false},
{"magnett:?xt=urn:btih:3E30322D5BFC7444B7B1D8DD42404B75D0531DFB&dn=world&tr=udp://world.com:1337", false},
{"xt=urn:btih:4ODKSDJBVMSDSNJVBCBFYFBKNRU875DW8D97DWC6&dn=helloworld&tr=udp://helloworld.com:1337", false},
{"magneta:?xt=urn:btih:1GSHJVBDVDVJFYEHKFHEFIO8573898434JBFEGHD&dn=foo&tr=udp://foo.com:1337", false},
{"magnet:?xt=uarn:btih:MCJDCYUFHEUD6E2752T7UJNEKHSUGEJFGTFHVBJS&dn=bar&tr=udp://bar.com:1337", false},
{"magnet:?xt=urn:btihz&dn=foobar&tr=udp://foobar.com:1337", false},
{"magnet:?xat=urn:btih:MKCJBHCBJDCU725TGEB3Y6RE8EJ2U267UNJFGUID&dn=test&tr=udp://test.com:1337", false},
{"magnet::?xt=urn:btih:UHWY2892JNEJ2GTEYOMDNU67E8ICGICYE92JDUGH&dn=baz&tr=udp://baz.com:1337", false},
{"magnet:?xt:btih:HS263FG8U3GFIDHWD7829BYFCIXB78XIHG7CWCUG&dn=foz&tr=udp://foz.com:1337", false},
}
for _, test := range tests {
actual := IsMagnetURI(test.param)
if actual != test.expected {
t.Errorf("Expected IsMagnetURI(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsBase64(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", true},
{"Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==", true},
{"U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", true},
{"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw" +
"UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye" +
"rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619" +
"FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx" +
"QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ" +
"Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ" + "HQIDAQAB", true},
{"12345", false},
{"", false},
{"Vml2YW11cyBmZXJtZtesting123", false},
}
for _, test := range tests {
actual := IsBase64(test.param)
if actual != test.expected {
t.Errorf("Expected IsBase64(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsISO3166Alpha2(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"ABCD", false},
{"A", false},
{"AC", false},
{"AP", false},
{"GER", false},
{"NU", true},
{"DE", true},
{"JP", true},
{"JPN", false},
{"ZWE", false},
{"GER", false},
{"DEU", false},
}
for _, test := range tests {
actual := IsISO3166Alpha2(test.param)
if actual != test.expected {
t.Errorf("Expected IsISO3166Alpha2(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsISO3166Alpha3(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"ABCD", false},
{"A", false},
{"AC", false},
{"AP", false},
{"NU", false},
{"DE", false},
{"JP", false},
{"ZWE", true},
{"JPN", true},
{"GER", false},
{"DEU", true},
}
for _, test := range tests {
actual := IsISO3166Alpha3(test.param)
if actual != test.expected {
t.Errorf("Expected IsISO3166Alpha3(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsISO693Alpha2(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"abcd", false},
{"a", false},
{"ac", false},
{"ap", false},
{"de", true},
{"DE", false},
{"mk", true},
{"mac", false},
{"sw", true},
{"SW", false},
{"ger", false},
{"deu", false},
}
for _, test := range tests {
actual := IsISO693Alpha2(test.param)
if actual != test.expected {
t.Errorf("Expected IsISO693Alpha2(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsISO693Alpha3b(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"abcd", false},
{"a", false},
{"ac", false},
{"ap", false},
{"de", false},
{"DE", false},
{"mkd", false},
{"mac", true},
{"sw", false},
{"SW", false},
{"ger", true},
{"deu", false},
}
for _, test := range tests {
actual := IsISO693Alpha3b(test.param)
if actual != test.expected {
t.Errorf("Expected IsISO693Alpha3b(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsIP(t *testing.T) {
t.Parallel()
// Without version
var tests = []struct {
param string
expected bool
}{
{"", false},
{"127.0.0.1", true},
{"0.0.0.0", true},
{"255.255.255.255", true},
{"1.2.3.4", true},
{"::1", true},
{"2001:db8:0000:1:1:1:1:1", true},
{"300.0.0.0", false},
}
for _, test := range tests {
actual := IsIP(test.param)
if actual != test.expected {
t.Errorf("Expected IsIP(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
// IPv4
tests = []struct {
param string
expected bool
}{
{"", false},
{"127.0.0.1", true},
{"0.0.0.0", true},
{"255.255.255.255", true},
{"1.2.3.4", true},
{"::1", false},
{"2001:db8:0000:1:1:1:1:1", false},
{"300.0.0.0", false},
}
for _, test := range tests {
actual := IsIPv4(test.param)
if actual != test.expected {
t.Errorf("Expected IsIPv4(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
// IPv6
tests = []struct {
param string
expected bool
}{
{"", false},
{"127.0.0.1", false},
{"0.0.0.0", false},
{"255.255.255.255", false},
{"1.2.3.4", false},
{"::1", true},
{"2001:db8:0000:1:1:1:1:1", true},
{"300.0.0.0", false},
}
for _, test := range tests {
actual := IsIPv6(test.param)
if actual != test.expected {
t.Errorf("Expected IsIPv6(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsPort(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"1", true},
{"65535", true},
{"0", false},
{"65536", false},
{"65538", false},
}
for _, test := range tests {
actual := IsPort(test.param)
if actual != test.expected {
t.Errorf("Expected IsPort(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsDNSName(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"localhost", true},
{"a.bc", true},
{"a.b.", true},
{"a.b..", false},
{"localhost.local", true},
{"localhost.localdomain.intern", true},
{"l.local.intern", true},
{"ru.link.n.svpncloud.com", true},
{"-localhost", false},
{"localhost.-localdomain", false},
{"localhost.localdomain.-int", false},
{"_localhost", true},
{"localhost._localdomain", true},
{"localhost.localdomain._int", true},
{"lÖcalhost", false},
{"localhost.lÖcaldomain", false},
{"localhost.localdomain.üntern", false},
{"__", true},
{"localhost/", false},
{"127.0.0.1", false},
{"[::1]", false},
{"50.50.50.50", false},
{"localhost.localdomain.intern:65535", false},
{"漢字汉字", false},
{"www.jubfvq1v3p38i51622y0dvmdk1mymowjyeu26gbtw9andgynj1gg8z3msb1kl5z6906k846pj3sulm4kiyk82ln5teqj9nsht59opr0cs5ssltx78lfyvml19lfq1wp4usbl0o36cmiykch1vywbttcus1p9yu0669h8fj4ll7a6bmop505908s1m83q2ec2qr9nbvql2589adma3xsq2o38os2z3dmfh2tth4is4ixyfasasasefqwe4t2ub2fz1rme.de", false},
}
for _, test := range tests {
actual := IsDNSName(test.param)
if actual != test.expected {
t.Errorf("Expected IsDNS(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsHost(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"localhost", true},
{"localhost.localdomain", true},
{"2001:db8:0000:1:1:1:1:1", true},
{"::1", true},
{"play.golang.org", true},
{"localhost.localdomain.intern:65535", false},
{"-[::1]", false},
{"-localhost", false},
{".localhost", false},
}
for _, test := range tests {
actual := IsHost(test.param)
if actual != test.expected {
t.Errorf("Expected IsHost(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsDialString(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"localhost.local:1", true},
{"localhost.localdomain:9090", true},
{"localhost.localdomain.intern:65535", true},
{"127.0.0.1:30000", true},
{"[::1]:80", true},
{"[1200::AB00:1234::2552:7777:1313]:22", false},
{"-localhost:1", false},
{"localhost.-localdomain:9090", false},
{"localhost.localdomain.-int:65535", false},
{"localhost.loc:100000", false},
{"漢字汉字:2", false},
{"www.jubfvq1v3p38i51622y0dvmdk1mymowjyeu26gbtw9andgynj1gg8z3msb1kl5z6906k846pj3sulm4kiyk82ln5teqj9nsht59opr0cs5ssltx78lfyvml19lfq1wp4usbl0o36cmiykch1vywbttcus1p9yu0669h8fj4ll7a6bmop505908s1m83q2ec2qr9nbvql2589adma3xsq2o38os2z3dmfh2tth4is4ixyfasasasefqwe4t2ub2fz1rme.de:20000", false},
}
for _, test := range tests {
actual := IsDialString(test.param)
if actual != test.expected {
t.Errorf("Expected IsDialString(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsMAC(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"3D:F2:C9:A6:B3:4F", true},
{"3D-F2-C9-A6-B3:4F", false},
{"123", false},
{"", false},
{"abacaba", false},
}
for _, test := range tests {
actual := IsMAC(test.param)
if actual != test.expected {
t.Errorf("Expected IsMAC(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestFilePath(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
osType int
}{
{"c:\\" + strings.Repeat("a", 32767), true, Win}, //See http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath
{"c:\\" + strings.Repeat("a", 32768), false, Win},
{"c:\\path\\file (x86)\bar", true, Win},
{"c:\\path\\file", true, Win},
{"c:\\path\\file:exe", false, Unknown},
{"C:\\", true, Win},
{"c:\\path\\file\\", true, Win},
{"c:/path/file/", false, Unknown},
{"/path/file/", true, Unix},
{"/path/file:SAMPLE/", true, Unix},
{"/path/file:/.txt", true, Unix},
{"/path", true, Unix},
{"/path/__bc/file.txt", true, Unix},
{"/path/a--ac/file.txt", true, Unix},
{"/_path/file.txt", true, Unix},
{"/path/__bc/file.txt", true, Unix},
{"/path/a--ac/file.txt", true, Unix},
{"/__path/--file.txt", true, Unix},
{"/path/a bc", true, Unix},
}
for _, test := range tests {
actual, osType := IsFilePath(test.param)
if actual != test.expected || osType != test.osType {
t.Errorf("Expected IsFilePath(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsLatitude(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"-90.000", true},
{"+90", true},
{"47.1231231", true},
{"+99.9", false},
{"108", false},
}
for _, test := range tests {
actual := IsLatitude(test.param)
if actual != test.expected {
t.Errorf("Expected IsLatitude(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsLongitude(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"-180.000", true},
{"180.1", false},
{"+73.234", true},
{"+382.3811", false},
{"23.11111111", true},
}
for _, test := range tests {
actual := IsLongitude(test.param)
if actual != test.expected {
t.Errorf("Expected IsLongitude(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsSSN(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"00-90-8787", false},
{"66690-76", false},
{"191 60 2869", true},
{"191-60-2869", true},
}
for _, test := range tests {
actual := IsSSN(test.param)
if actual != test.expected {
t.Errorf("Expected IsSSN(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsMongoID(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"507f1f77bcf86cd799439011", true},
{"507f1f77bcf86cd7994390", false},
{"507f1f77bcf86cd79943901z", false},
{"507f1f77bcf86cd799439011 ", false},
{"", false},
}
for _, test := range tests {
actual := IsMongoID(test.param)
if actual != test.expected {
t.Errorf("Expected IsMongoID(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsSemver(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"v1.0.0", true},
{"1.0.0", true},
{"1.1.01", false},
{"1.01.0", false},
{"01.1.0", false},
{"v1.1.01", false},
{"v1.01.0", false},
{"v01.1.0", false},
{"1.0.0-alpha", true},
{"1.0.0-alpha.1", true},
{"1.0.0-0.3.7", true},
{"1.0.0-0.03.7", false},
{"1.0.0-00.3.7", false},
{"1.0.0-x.7.z.92", true},
{"1.0.0-alpha+001", true},
{"1.0.0+20130313144700", true},
{"1.0.0-beta+exp.sha.5114f85", true},
{"1.0.0-beta+exp.sha.05114f85", true},
{"1.0.0-+beta", false},
{"1.0.0-b+-9+eta", false},
{"v+1.8.0-b+-9+eta", false},
}
for _, test := range tests {
actual := IsSemver(test.param)
if actual != test.expected {
t.Errorf("Expected IsSemver(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsTime(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
format string
expected bool
}{
{"2016-12-31 11:00", time.RFC3339, false},
{"2016-12-31 11:00:00", time.RFC3339, false},
{"2016-12-31T11:00", time.RFC3339, false},
{"2016-12-31T11:00:00", time.RFC3339, false},
{"2016-12-31T11:00:00Z", time.RFC3339, true},
{"2016-12-31T11:00:00+01:00", time.RFC3339, true},
{"2016-12-31T11:00:00-01:00", time.RFC3339, true},
{"2016-12-31T11:00:00.05Z", time.RFC3339, true},
{"2016-12-31T11:00:00.05-01:00", time.RFC3339, true},
{"2016-12-31T11:00:00.05+01:00", time.RFC3339, true},
{"2016-12-31T11:00:00", RF3339WithoutZone, true},
{"2016-12-31T11:00:00Z", RF3339WithoutZone, false},
{"2016-12-31T11:00:00+01:00", RF3339WithoutZone, false},
{"2016-12-31T11:00:00-01:00", RF3339WithoutZone, false},
{"2016-12-31T11:00:00.05Z", RF3339WithoutZone, false},
{"2016-12-31T11:00:00.05-01:00", RF3339WithoutZone, false},
{"2016-12-31T11:00:00.05+01:00", RF3339WithoutZone, false},
}
for _, test := range tests {
actual := IsTime(test.param, test.format)
if actual != test.expected {
t.Errorf("Expected IsTime(%q, time.RFC3339) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsRFC3339(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"2016-12-31 11:00", false},
{"2016-12-31 11:00:00", false},
{"2016-12-31T11:00", false},
{"2016-12-31T11:00:00", false},
{"2016-12-31T11:00:00Z", true},
{"2016-12-31T11:00:00+01:00", true},
{"2016-12-31T11:00:00-01:00", true},
{"2016-12-31T11:00:00.05Z", true},
{"2016-12-31T11:00:00.05-01:00", true},
{"2016-12-31T11:00:00.05+01:00", true},
}
for _, test := range tests {
actual := IsRFC3339(test.param)
if actual != test.expected {
t.Errorf("Expected IsRFC3339(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestIsISO4217(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"", false},
{"ABCD", false},
{"A", false},
{"ZZZ", false},
{"usd", false},
{"USD", true},
}
for _, test := range tests {
actual := IsISO4217(test.param)
if actual != test.expected {
t.Errorf("Expected IsISO4217(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestByteLength(t *testing.T) {
t.Parallel()
var tests = []struct {
value string
min string
max string
expected bool
}{
{"123456", "0", "100", true},
{"1239999", "0", "0", false},
{"1239asdfasf99", "100", "200", false},
{"1239999asdff29", "10", "30", true},
{"你", "0", "1", false},
}
for _, test := range tests {
actual := ByteLength(test.value, test.min, test.max)
if actual != test.expected {
t.Errorf("Expected ByteLength(%s, %s, %s) to be %v, got %v", test.value, test.min, test.max, test.expected, actual)
}
}
}
func TestRuneLength(t *testing.T) {
t.Parallel()
var tests = []struct {
value string
min string
max string
expected bool
}{
{"123456", "0", "100", true},
{"1239999", "0", "0", false},
{"1239asdfasf99", "100", "200", false},
{"1239999asdff29", "10", "30", true},
{"你", "0", "1", true},
}
for _, test := range tests {
actual := RuneLength(test.value, test.min, test.max)
if actual != test.expected {
t.Errorf("Expected RuneLength(%s, %s, %s) to be %v, got %v", test.value, test.min, test.max, test.expected, actual)
}
}
}
func TestStringLength(t *testing.T) {
t.Parallel()
var tests = []struct {
value string
min string
max string
expected bool
}{
{"123456", "0", "100", true},
{"1239999", "0", "0", false},
{"1239asdfasf99", "100", "200", false},
{"1239999asdff29", "10", "30", true},
{"あいうえお", "0", "5", true},
{"あいうえおか", "0", "5", false},
{"あいうえお", "0", "0", false},
{"あいうえ", "5", "10", false},
}
for _, test := range tests {
actual := StringLength(test.value, test.min, test.max)
if actual != test.expected {
t.Errorf("Expected StringLength(%s, %s, %s) to be %v, got %v", test.value, test.min, test.max, test.expected, actual)
}
}
}
func TestIsIn(t *testing.T) {
t.Parallel()
var tests = []struct {
value string
params []string
expected bool
}{
{"PRESENT", []string{"PRESENT"}, true},
{"PRESENT", []string{"PRESENT", "PRÉSENTE", "NOTABSENT"}, true},
{"PRÉSENTE", []string{"PRESENT", "PRÉSENTE", "NOTABSENT"}, true},
{"PRESENT", []string{}, false},
{"PRESENT", nil, false},
{"ABSENT", []string{"PRESENT", "PRÉSENTE", "NOTABSENT"}, false},
{"", []string{"PRESENT", "PRÉSENTE", "NOTABSENT"}, false},
}
for _, test := range tests {
actual := IsIn(test.value, test.params...)
if actual != test.expected {
t.Errorf("Expected IsIn(%s, %v) to be %v, got %v", test.value, test.params, test.expected, actual)
}
}
}
type Address struct {
Street string `valid:"-"`
Zip string `json:"zip" valid:"numeric,required"`
}
type User struct {
Name string `valid:"required"`
Email string `valid:"required,email"`
Password string `valid:"required"`
Age int `valid:"required,numeric,@#\u0000"`
Home *Address
Work []Address
}
type UserValid struct {
Name string `valid:"required"`
Email string `valid:"required,email"`
Password string `valid:"required"`
Age int `valid:"required"`
Home *Address
Work []Address `valid:"required"`
}
type PrivateStruct struct {
privateField string `valid:"required,alpha,d_k"`
NonZero int
ListInt []int
ListString []string `valid:"alpha"`
Work [2]Address
Home Address
Map map[string]Address
}
type NegationStruct struct {
NotInt string `valid:"!int"`
Int string `valid:"int"`
}
type LengthStruct struct {
Length string `valid:"length(10|20)"`
}
type StringLengthStruct struct {
Length string `valid:"stringlength(10|20)"`
}
type StringMatchesStruct struct {
StringMatches string `valid:"matches(^[0-9]{3}$)"`
}
// TODO: this testcase should be fixed
// type StringMatchesComplexStruct struct {
// StringMatches string `valid:"matches(^\\$\\([\"']\\w+[\"']\\)$)"`
// }
type IsInStruct struct {
IsIn string `valid:"in(PRESENT|PRÉSENTE|NOTABSENT)"`
}
type Post struct {
Title string `valid:"alpha,required"`
Message string `valid:"ascii"`
AuthorIP string `valid:"ipv4"`
}
type MissingValidationDeclarationStruct struct {
Name string ``
Email string `valid:"required,email"`
}
type FieldRequiredByDefault struct {
Email string `valid:"email"`
}
type MultipleFieldsRequiredByDefault struct {
Url string `valid:"url"`
Email string `valid:"email"`
}
type FieldsRequiredByDefaultButExemptStruct struct {
Name string `valid:"-"`
Email string `valid:"email"`
}
type FieldsRequiredByDefaultButExemptOrOptionalStruct struct {
Name string `valid:"-"`
Email string `valid:"optional,email"`
}
type MessageWithSeveralFieldsStruct struct {
Title string `valid:"length(1|10)"`
Body string `valid:"length(1|10)"`
}
func TestValidateMissingValidationDeclarationStruct(t *testing.T) {
var tests = []struct {
param MissingValidationDeclarationStruct
expected bool
}{
{MissingValidationDeclarationStruct{}, false},
{MissingValidationDeclarationStruct{Name: "TEST", Email: "test@example.com"}, false},
}
SetFieldsRequiredByDefault(true)
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
SetFieldsRequiredByDefault(false)
}
func TestFieldRequiredByDefault(t *testing.T) {
var tests = []struct {
param FieldRequiredByDefault
expected bool
}{
{FieldRequiredByDefault{}, false},
}
SetFieldsRequiredByDefault(true)
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
SetFieldsRequiredByDefault(false)
}
func TestMultipleFieldsRequiredByDefault(t *testing.T) {
var tests = []struct {
param MultipleFieldsRequiredByDefault
expected bool
}{
{MultipleFieldsRequiredByDefault{}, false},
}
SetFieldsRequiredByDefault(true)
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
SetFieldsRequiredByDefault(false)
}
func TestFieldsRequiredByDefaultButExemptStruct(t *testing.T) {
var tests = []struct {
param FieldsRequiredByDefaultButExemptStruct
expected bool
}{
{FieldsRequiredByDefaultButExemptStruct{}, false},
{FieldsRequiredByDefaultButExemptStruct{Name: "TEST"}, false},
{FieldsRequiredByDefaultButExemptStruct{Email: ""}, false},
{FieldsRequiredByDefaultButExemptStruct{Email: "test@example.com"}, true},
}
SetFieldsRequiredByDefault(true)
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
SetFieldsRequiredByDefault(false)
}
func TestFieldsRequiredByDefaultButExemptOrOptionalStruct(t *testing.T) {
var tests = []struct {
param FieldsRequiredByDefaultButExemptOrOptionalStruct
expected bool
}{
{FieldsRequiredByDefaultButExemptOrOptionalStruct{}, true},
{FieldsRequiredByDefaultButExemptOrOptionalStruct{Name: "TEST"}, true},
{FieldsRequiredByDefaultButExemptOrOptionalStruct{Email: ""}, true},
{FieldsRequiredByDefaultButExemptOrOptionalStruct{Email: "test@example.com"}, true},
{FieldsRequiredByDefaultButExemptOrOptionalStruct{Email: "test@example"}, false},
}
SetFieldsRequiredByDefault(true)
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
SetFieldsRequiredByDefault(false)
}
func TestInvalidValidator(t *testing.T) {
type InvalidStruct struct {
Field int `valid:"someInvalidValidator"`
}
invalidStruct := InvalidStruct{1}
if valid, err := ValidateStruct(&invalidStruct); valid || err == nil ||
err.Error() != `Field: The following validator is invalid or can't be applied to the field: "someInvalidValidator"` {
t.Errorf("Got an unexpected result for struct with invalid validator: %t %s", valid, err)
}
}
func TestCustomValidator(t *testing.T) {
type ValidStruct struct {
Field int `valid:"customTrueValidator"`
}
type InvalidStruct struct {
Field int `valid:"customFalseValidator~Value: %s Custom validator error: %s"`
}
type StructWithCustomAndBuiltinValidator struct {
Field int `valid:"customTrueValidator,required"`
}
if valid, err := ValidateStruct(&ValidStruct{Field: 1}); !valid || err != nil {
t.Errorf("Got an unexpected result for struct with custom always true validator: %t %s", valid, err)
}
if valid, err := ValidateStruct(&InvalidStruct{Field: 1}); valid || err == nil || err.Error() != "Value: 1 Custom validator error: customFalseValidator" {
fmt.Println(err)
t.Errorf("Got an unexpected result for struct with custom always false validator: %t %s", valid, err)
}
mixedStruct := StructWithCustomAndBuiltinValidator{}
if valid, err := ValidateStruct(&mixedStruct); valid || err == nil || err.Error() != "Field: non zero value required" {
t.Errorf("Got an unexpected result for invalid struct with custom and built-in validators: %t %s", valid, err)
}
mixedStruct.Field = 1
if valid, err := ValidateStruct(&mixedStruct); !valid || err != nil {
t.Errorf("Got an unexpected result for valid struct with custom and built-in validators: %t %s", valid, err)
}
}
type CustomByteArray [6]byte
type StructWithCustomByteArray struct {
ID CustomByteArray `valid:"customByteArrayValidator,customMinLengthValidator"`
Email string `valid:"email"`
CustomMinLength int `valid:"-"`
}
func TestStructWithCustomByteArray(t *testing.T) {
t.Parallel()
// add our custom byte array validator that fails when the byte array is pristine (all zeroes)
CustomTypeTagMap.Set("customByteArrayValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool {
switch v := o.(type) {
case StructWithCustomByteArray:
if len(v.Email) > 0 {
if v.Email != "test@example.com" {
t.Errorf("v.Email should have been 'test@example.com' but was '%s'", v.Email)
}
}
default:
t.Errorf("Context object passed to custom validator should have been a StructWithCustomByteArray but was %T (%+v)", o, o)
}
switch v := i.(type) {
case CustomByteArray:
for _, e := range v { // check if v is empty, i.e. all zeroes
if e != 0 {
return true
}
}
}
return false
}))
CustomTypeTagMap.Set("customMinLengthValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool {
switch v := o.(type) {
case StructWithCustomByteArray:
return len(v.ID) >= v.CustomMinLength
}
return false
}))
testCustomByteArray := CustomByteArray{'1', '2', '3', '4', '5', '6'}
var tests = []struct {
param StructWithCustomByteArray
expected bool
}{
{StructWithCustomByteArray{}, false},
{StructWithCustomByteArray{Email: "test@example.com"}, false},
{StructWithCustomByteArray{ID: testCustomByteArray, Email: "test@example.com"}, true},
{StructWithCustomByteArray{ID: testCustomByteArray, Email: "test@example.com", CustomMinLength: 7}, false},
}
SetFieldsRequiredByDefault(true)
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
SetFieldsRequiredByDefault(false)
}
func TestValidateNegationStruct(t *testing.T) {
var tests = []struct {
param NegationStruct
expected bool
}{
{NegationStruct{"a1", "11"}, true},
{NegationStruct{"email@email.email", "11"}, true},
{NegationStruct{"123456----", "11"}, true},
{NegationStruct{"::1", "11"}, true},
{NegationStruct{"123.123", "11"}, true},
{NegationStruct{"a1", "a1"}, false},
{NegationStruct{"11", "a1"}, false},
{NegationStruct{"11", "11"}, false},
}
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
}
func TestLengthStruct(t *testing.T) {
var tests = []struct {
param interface{}
expected bool
}{
{LengthStruct{"11111"}, false},
{LengthStruct{"11111111111111111110000000000000000"}, false},
{LengthStruct{"11dfffdf0099"}, true},
}
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
}
func TestStringLengthStruct(t *testing.T) {
var tests = []struct {
param interface{}
expected bool
}{
{StringLengthStruct{"11111"}, false},
{StringLengthStruct{"11111111111111111110000000000000000"}, false},
{StringLengthStruct{"11dfffdf0099"}, true},
{StringLengthStruct{"あいうえお"}, false},
{StringLengthStruct{"あいうえおかきくけこ"}, true},
{StringLengthStruct{"あいうえおかきくけこさしすせそたちつてと"}, true},
{StringLengthStruct{"あいうえおかきくけこさしすせそたちつてとな"}, false},
}
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
}
func TestStringMatchesStruct(t *testing.T) {
var tests = []struct {
param interface{}
expected bool
}{
{StringMatchesStruct{"123"}, true},
{StringMatchesStruct{"123456"}, false},
{StringMatchesStruct{"123abcd"}, false},
}
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
}
func TestIsInStruct(t *testing.T) {
var tests = []struct {
param interface{}
expected bool
}{
{IsInStruct{"PRESENT"}, true},
{IsInStruct{""}, true},
{IsInStruct{" "}, false},
{IsInStruct{"ABSENT"}, false},
}
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
}
func TestRequiredIsInStruct(t *testing.T) {
type RequiredIsInStruct struct {
IsIn string `valid:"in(PRESENT|PRÉSENTE|NOTABSENT),required"`
}
var tests = []struct {
param interface{}
expected bool
}{
{RequiredIsInStruct{"PRESENT"}, true},
{RequiredIsInStruct{""}, false},
{RequiredIsInStruct{" "}, false},
{RequiredIsInStruct{"ABSENT"}, false},
}
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
}
func TestEmptyRequiredIsInStruct(t *testing.T) {
type EmptyRequiredIsInStruct struct {
IsIn string `valid:"in(),required"`
}
var tests = []struct {
param interface{}
expected bool
}{
{EmptyRequiredIsInStruct{"PRESENT"}, false},
{EmptyRequiredIsInStruct{""}, false},
{EmptyRequiredIsInStruct{" "}, false},
{EmptyRequiredIsInStruct{"ABSENT"}, false},
}
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
}
func TestEmptyStringPtr(t *testing.T) {
type EmptyIsInStruct struct {
IsIn *string `valid:"length(3|5),required"`
}
var empty = ""
var valid = "123"
var invalid = "123456"
var tests = []struct {
param interface{}
expected bool
expectedErr string
}{
{EmptyIsInStruct{&empty}, false, "IsIn: non zero value required"},
{EmptyIsInStruct{nil}, true, ""},
{EmptyIsInStruct{&valid}, true, ""},
{EmptyIsInStruct{&invalid}, false, "IsIn: 123456 does not validate as length(3|5)"},
}
SetNilPtrAllowedByRequired(true)
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
}
if err != nil {
if err.Error() != test.expectedErr {
t.Errorf("Got Error on ValidateStruct(%q). Expected: %s Actual: %s", test.param, test.expectedErr, err)
}
} else if test.expectedErr != "" {
t.Errorf("Expected error on ValidateStruct(%q).", test.param)
}
}
SetNilPtrAllowedByRequired(false)
}
func TestNestedStruct(t *testing.T) {
type EvenMoreNestedStruct struct {
Bar string `valid:"length(3|5)"`
}
type NestedStruct struct {
Foo string `valid:"length(3|5),required"`
EvenMoreNested EvenMoreNestedStruct
SliceEvenMoreNested []EvenMoreNestedStruct
MapEvenMoreNested map[string]EvenMoreNestedStruct
}
type OuterStruct struct {
Nested NestedStruct
}
var tests = []struct {
param interface{}
expected bool
expectedErr string
}{
{OuterStruct{
Nested: NestedStruct{
Foo: "",
},
}, false, "Nested.Foo: non zero value required"},
{OuterStruct{
Nested: NestedStruct{
Foo: "123",
},
}, true, ""},
{OuterStruct{
Nested: NestedStruct{
Foo: "123456",
},
}, false, "Nested.Foo: 123456 does not validate as length(3|5)"},
{OuterStruct{
Nested: NestedStruct{
Foo: "123",
EvenMoreNested: EvenMoreNestedStruct{
Bar: "123456",
},
},
}, false, "Nested.EvenMoreNested.Bar: 123456 does not validate as length(3|5)"},
{OuterStruct{
Nested: NestedStruct{
Foo: "123",
SliceEvenMoreNested: []EvenMoreNestedStruct{
EvenMoreNestedStruct{
Bar: "123456",
},
},
},
}, false, "Nested.SliceEvenMoreNested.0.Bar: 123456 does not validate as length(3|5)"},
{OuterStruct{
Nested: NestedStruct{
Foo: "123",
MapEvenMoreNested: map[string]EvenMoreNestedStruct{
"Foo": EvenMoreNestedStruct{
Bar: "123456",
},
},
},
}, false, "Nested.MapEvenMoreNested.Foo.Bar: 123456 does not validate as length(3|5)"},
}
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
}
if err != nil {
if err.Error() != test.expectedErr {
t.Errorf("Got Error on ValidateStruct(%q). Expected: %s Actual: %s", test.param, test.expectedErr, err)
}
} else if test.expectedErr != "" {
t.Errorf("Expected error on ValidateStruct(%q).", test.param)
}
}
}
func TestFunkyIsInStruct(t *testing.T) {
type FunkyIsInStruct struct {
IsIn string `valid:"in(PRESENT|| |PRÉSENTE|NOTABSENT)"`
}
var tests = []struct {
param interface{}
expected bool
}{
{FunkyIsInStruct{"PRESENT"}, true},
{FunkyIsInStruct{""}, true},
{FunkyIsInStruct{" "}, true},
{FunkyIsInStruct{"ABSENT"}, false},
}
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
}
// TODO: test case broken
// func TestStringMatchesComplexStruct(t *testing.T) {
// var tests = []struct {
// param interface{}
// expected bool
// }{
// {StringMatchesComplexStruct{"$()"}, false},
// {StringMatchesComplexStruct{"$('AZERTY')"}, true},
// {StringMatchesComplexStruct{`$("AZERTY")`}, true},
// {StringMatchesComplexStruct{`$("")`}, false},
// {StringMatchesComplexStruct{"AZERTY"}, false},
// {StringMatchesComplexStruct{"$AZERTY"}, false},
// }
// for _, test := range tests {
// actual, err := ValidateStruct(test.param)
// if actual != test.expected {
// t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
// if err != nil {
// t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
// }
// }
// }
// }
func TestValidateStruct(t *testing.T) {
var tests = []struct {
param interface{}
expected bool
}{
{User{"John", "john@yahoo.com", "123G#678", 20, &Address{"Street", "ABC456D89"}, []Address{{"Street", "123456"}, {"Street", "123456"}}}, false},
{User{"John", "john!yahoo.com", "12345678", 20, &Address{"Street", "ABC456D89"}, []Address{{"Street", "ABC456D89"}, {"Street", "123456"}}}, false},
{User{"John", "", "12345", 0, &Address{"Street", "123456789"}, []Address{{"Street", "ABC456D89"}, {"Street", "123456"}}}, false},
{UserValid{"John", "john@yahoo.com", "123G#678", 20, &Address{"Street", "123456"}, []Address{{"Street", "123456"}, {"Street", "123456"}}}, true},
{UserValid{"John", "john!yahoo.com", "12345678", 20, &Address{"Street", "ABC456D89"}, []Address{}}, false},
{UserValid{"John", "john@yahoo.com", "12345678", 20, &Address{"Street", "123456xxx"}, []Address{{"Street", "123456"}, {"Street", "123456"}}}, false},
{UserValid{"John", "john!yahoo.com", "12345678", 20, &Address{"Street", "ABC456D89"}, []Address{{"Street", "ABC456D89"}, {"Street", "123456"}}}, false},
{UserValid{"John", "", "12345", 0, &Address{"Street", "123456789"}, []Address{{"Street", "ABC456D89"}, {"Street", "123456"}}}, false},
{nil, true},
{User{"John", "john@yahoo.com", "123G#678", 0, &Address{"Street", "123456"}, []Address{}}, false},
{"im not a struct", false},
}
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
TagMap["d_k"] = Validator(func(str string) bool {
return str == "d_k"
})
result, err := ValidateStruct(PrivateStruct{"d_k", 0, []int{1, 2}, []string{"hi", "super"}, [2]Address{{"Street", "123456"},
{"Street", "123456"}}, Address{"Street", "123456"}, map[string]Address{"address": {"Street", "123456"}}})
if !result {
t.Log("Case ", 6, ": expected ", true, " when result is ", result)
t.Error(err)
t.FailNow()
}
}
type testByteArray [8]byte
type testByteMap map[byte]byte
type testByteSlice []byte
type testStringStringMap map[string]string
type testStringIntMap map[string]int
func TestRequired(t *testing.T) {
testString := "foobar"
testEmptyString := ""
var tests = []struct {
param interface{}
expected bool
}{
{
struct {
Pointer *string `valid:"required"`
}{},
false,
},
{
struct {
Pointer *string `valid:"required"`
}{
Pointer: &testEmptyString,
},
false,
},
{
struct {
Pointer *string `valid:"required"`
}{
Pointer: &testString,
},
true,
},
{
struct {
Addr Address `valid:"required"`
}{},
false,
},
{
struct {
Addr Address `valid:"required"`
}{
Addr: Address{"", "123"},
},
true,
},
{
struct {
Pointer *Address `valid:"required"`
}{},
false,
},
{
struct {
Pointer *Address `valid:"required"`
}{
Pointer: &Address{"", "123"},
},
true,
},
{
struct {
TestByteArray testByteArray `valid:"required"`
}{},
false,
},
{
struct {
TestByteArray testByteArray `valid:"required"`
}{
testByteArray{},
},
false,
},
{
struct {
TestByteArray testByteArray `valid:"required"`
}{
testByteArray{'1', '2', '3', '4', '5', '6', '7', 'A'},
},
true,
},
{
struct {
TestByteMap testByteMap `valid:"required"`
}{},
false,
},
{
struct {
TestByteSlice testByteSlice `valid:"required"`
}{},
false,
},
{
struct {
TestStringStringMap testStringStringMap `valid:"required"`
}{
testStringStringMap{"test": "test"},
},
true,
},
{
struct {
TestIntMap testStringIntMap `valid:"required"`
}{
testStringIntMap{"test": 42},
},
true,
},
}
for _, test := range tests {
actual, err := ValidateStruct(test.param)
if actual != test.expected {
t.Errorf("Expected ValidateStruct(%q) to be %v, got %v", test.param, test.expected, actual)
if err != nil {
t.Errorf("Got Error on ValidateStruct(%q): %s", test.param, err)
}
}
}
}
func TestErrorByField(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected string
}{
{"message", ""},
{"Message", ""},
{"title", ""},
{"Title", "My123 does not validate as alpha"},
{"AuthorIP", "123 does not validate as ipv4"},
}
post := &Post{"My123", "duck13126", "123"}
_, err := ValidateStruct(post)
for _, test := range tests {
actual := ErrorByField(err, test.param)
if actual != test.expected {
t.Errorf("Expected ErrorByField(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestErrorsByField(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected string
}{
{"Title", "My123 does not validate as alpha"},
{"AuthorIP", "123 does not validate as ipv4"},
}
post := &Post{Title: "My123", Message: "duck13126", AuthorIP: "123"}
_, err := ValidateStruct(post)
errs := ErrorsByField(err)
if len(errs) != 2 {
t.Errorf("There should only be 2 errors but got %v", len(errs))
}
for _, test := range tests {
if actual, ok := errs[test.param]; !ok || actual != test.expected {
t.Errorf("Expected ErrorsByField(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
tests = []struct {
param string
expected string
}{
{"Title", ";:;message;:; does not validate as length(1|10)"},
{"Body", ";:;message;:; does not validate as length(1|10)"},
}
message := &MessageWithSeveralFieldsStruct{Title: ";:;message;:;", Body: ";:;message;:;"}
_, err = ValidateStruct(message)
errs = ErrorsByField(err)
if len(errs) != 2 {
t.Errorf("There should only be 2 errors but got %v", len(errs))
}
for _, test := range tests {
if actual, ok := errs[test.param]; !ok || actual != test.expected {
t.Errorf("Expected ErrorsByField(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
tests = []struct {
param string
expected string
}{
{"CustomField", "An error occurred"},
}
err = Error{"CustomField", fmt.Errorf("An error occurred"), false, "hello", []string{}}
errs = ErrorsByField(err)
if len(errs) != 1 {
t.Errorf("There should only be 1 errors but got %v", len(errs))
}
for _, test := range tests {
if actual, ok := errs[test.param]; !ok || actual != test.expected {
t.Errorf("Expected ErrorsByField(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
type StructWithCustomValidation struct {
Email string `valid:"email"`
ID string `valid:"falseValidation"`
}
CustomTypeTagMap.Set("falseValidation", CustomTypeValidator(func(i interface{}, o interface{}) bool {
return false
}))
tests = []struct {
param string
expected string
}{
{"Email", "My123 does not validate as email"},
{"ID", "duck13126 does not validate as falseValidation"},
}
s := &StructWithCustomValidation{Email: "My123", ID: "duck13126"}
_, err = ValidateStruct(s)
errs = ErrorsByField(err)
if len(errs) != 2 {
t.Errorf("There should only be 2 errors but got %v", len(errs))
}
for _, test := range tests {
if actual, ok := errs[test.param]; !ok || actual != test.expected {
t.Errorf("Expected ErrorsByField(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestValidateStructPointers(t *testing.T) {
// Struct which uses pointers for values
type UserWithPointers struct {
Name *string `valid:"-"`
Email *string `valid:"email"`
FavoriteFood *string `valid:"length(0|32)"`
Nerd *bool `valid:"-"`
}
var tests = []struct {
param string
expected string
}{
{"Name", ""},
{"Email", "invalid does not validate as email"},
{"FavoriteFood", ""},
{"Nerd", ""},
}
name := "Herman"
email := "invalid"
food := "Pizza"
nerd := true
user := &UserWithPointers{&name, &email, &food, &nerd}
_, err := ValidateStruct(user)
for _, test := range tests {
actual := ErrorByField(err, test.param)
if actual != test.expected {
t.Errorf("Expected ErrorByField(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func ExampleValidateStruct() {
type Post struct {
Title string `valid:"alphanum,required"`
Message string `valid:"duck,ascii"`
AuthorIP string `valid:"ipv4"`
}
post := &Post{"My Example Post", "duck", "123.234.54.3"}
//Add your own struct validation tags
TagMap["duck"] = Validator(func(str string) bool {
return str == "duck"
})
result, err := ValidateStruct(post)
if err != nil {
println("error: " + err.Error())
}
println(result)
}
func TestValidateStructParamValidatorInt(t *testing.T) {
type Test1 struct {
Int int `valid:"range(1|10)"`
Int8 int8 `valid:"range(1|10)"`
Int16 int16 `valid:"range(1|10)"`
Int32 int32 `valid:"range(1|10)"`
Int64 int64 `valid:"range(1|10)"`
Uint uint `valid:"range(1|10)"`
Uint8 uint8 `valid:"range(1|10)"`
Uint16 uint16 `valid:"range(1|10)"`
Uint32 uint32 `valid:"range(1|10)"`
Uint64 uint64 `valid:"range(1|10)"`
Float32 float32 `valid:"range(1|10)"`
Float64 float64 `valid:"range(1|10)"`
}
test1Ok := &Test1{5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}
test1NotOk := &Test1{11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11}
_, err := ValidateStruct(test1Ok)
if err != nil {
t.Errorf("Test failed: %s", err)
}
_, err = ValidateStruct(test1NotOk)
if err == nil {
t.Errorf("Test failed: nil")
}
type Test2 struct {
Int int `valid:"in(1|10)"`
Int8 int8 `valid:"in(1|10)"`
Int16 int16 `valid:"in(1|10)"`
Int32 int32 `valid:"in(1|10)"`
Int64 int64 `valid:"in(1|10)"`
Uint uint `valid:"in(1|10)"`
Uint8 uint8 `valid:"in(1|10)"`
Uint16 uint16 `valid:"in(1|10)"`
Uint32 uint32 `valid:"in(1|10)"`
Uint64 uint64 `valid:"in(1|10)"`
Float32 float32 `valid:"in(1|10)"`
Float64 float64 `valid:"in(1|10)"`
}
test2Ok1 := &Test2{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
test2Ok2 := &Test2{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}
test2NotOk := &Test2{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}
_, err = ValidateStruct(test2Ok1)
if err != nil {
t.Errorf("Test failed: %s", err)
}
_, err = ValidateStruct(test2Ok2)
if err != nil {
t.Errorf("Test failed: %s", err)
}
_, err = ValidateStruct(test2NotOk)
if err == nil {
t.Errorf("Test failed: nil")
}
type Test3 struct {
Int int `valid:"in(1|10),int"`
Int8 int8 `valid:"in(1|10),int8"`
Int16 int16 `valid:"in(1|10),int16"`
Int32 int32 `valid:"in(1|10),int32"`
Int64 int64 `valid:"in(1|10),int64"`
Uint uint `valid:"in(1|10),uint"`
Uint8 uint8 `valid:"in(1|10),uint8"`
Uint16 uint16 `valid:"in(1|10),uint16"`
Uint32 uint32 `valid:"in(1|10),uint32"`
Uint64 uint64 `valid:"in(1|10),uint64"`
Float32 float32 `valid:"in(1|10),float32"`
Float64 float64 `valid:"in(1|10),float64"`
}
test3Ok1 := &Test2{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
test3Ok2 := &Test2{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}
test3NotOk := &Test2{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}
_, err = ValidateStruct(test3Ok1)
if err != nil {
t.Errorf("Test failed: %s", err)
}
_, err = ValidateStruct(test3Ok2)
if err != nil {
t.Errorf("Test failed: %s", err)
}
_, err = ValidateStruct(test3NotOk)
if err == nil {
t.Errorf("Test failed: nil")
}
}
func TestValidateStructUpperAndLowerCaseWithNumTypeCheck(t *testing.T) {
type StructCapital struct {
Total float32 `valid:"float,required"`
}
structCapital := &StructCapital{53.3535}
_, err := ValidateStruct(structCapital)
if err != nil {
t.Errorf("Test failed: nil")
fmt.Println(err)
}
type StructLower struct {
total float32 `valid:"float,required"`
}
structLower := &StructLower{53.3535}
_, err = ValidateStruct(structLower)
if err != nil {
t.Errorf("Test failed: nil")
fmt.Println(err)
}
}
func TestIsCIDR(t *testing.T) {
t.Parallel()
var tests = []struct {
param string
expected bool
}{
{"193.168.3.20/7", true},
{"2001:db8::/32", true},
{"2001:0db8:85a3:0000:0000:8a2e:0370:7334/64", true},
{"193.138.3.20/60", false},
{"500.323.2.23/43", false},
{"", false},
}
for _, test := range tests {
actual := IsCIDR(test.param)
if actual != test.expected {
t.Errorf("Expected IsCIDR(%q) to be %v, got %v", test.param, test.expected, actual)
}
}
}
func TestOptionalCustomValidators(t *testing.T) {
CustomTypeTagMap.Set("f2", CustomTypeValidator(func(i interface{}, o interface{}) bool {
return false
}))
var val struct {
WithCustomError string `valid:"f2~boom,optional"`
WithoutCustomError string `valid:"f2,optional"`
OptionalFirst string `valid:"optional,f2"`
}
ok, err := ValidateStruct(val)
if err != nil {
t.Errorf("Expected nil err with optional validation, got %v", err)
}
if !ok {
t.Error("Expected validation to return true, got false")
}
}
func TestJSONValidator(t *testing.T) {
var val struct {
WithJSONName string `json:"with_json_name" valid:"-,required"`
WithoutJSONName string `valid:"-,required"`
WithJSONOmit string `json:"with_other_json_name,omitempty" valid:"-,required"`
WithJSONOption string `json:",omitempty" valid:"-,required"`
WithEmptyJSONName string `json:"-" valid:"-,required"`
}
_, err := ValidateStruct(val)
if err == nil {
t.Error("Expected error but got no error")
}
if Contains(err.Error(), "WithJSONName") {
t.Errorf("Expected error message to contain with_json_name but actual error is: %s", err.Error())
}
if !Contains(err.Error(), "WithoutJSONName") {
t.Errorf("Expected error message to contain WithoutJSONName but actual error is: %s", err.Error())
}
if Contains(err.Error(), "omitempty") {
t.Errorf("Expected error message to not contain ',omitempty' but actual error is: %s", err.Error())
}
if !Contains(err.Error(), "WithEmptyJSONName") {
t.Errorf("Expected error message to contain WithEmptyJSONName but actual error is: %s", err.Error())
}
}
func TestValidatorIncludedInError(t *testing.T) {
post := Post{
Title: "",
Message: "👍",
AuthorIP: "xyz",
}
validatorMap := map[string]string{
"Title": "required",
"Message": "ascii",
"AuthorIP": "ipv4",
}
ok, errors := ValidateStruct(post)
if ok {
t.Errorf("expected validation to fail %v", ok)
}
for _, e := range errors.(Errors) {
casted := e.(Error)
if validatorMap[casted.Name] != casted.Validator {
t.Errorf("expected validator for %s to be %s, but was %s", casted.Name, validatorMap[casted.Name], casted.Validator)
}
}
// check to make sure that validators with arguments (like length(1|10)) don't include the arguments
// in the validator name
message := MessageWithSeveralFieldsStruct{
Title: "",
Body: "asdfasdfasdfasdfasdf",
}
validatorMap = map[string]string{
"Title": "length",
"Body": "length",
}
ok, errors = ValidateStruct(message)
if ok {
t.Errorf("expected validation to fail, %v", ok)
}
for _, e := range errors.(Errors) {
casted := e.(Error)
if validatorMap[casted.Name] != casted.Validator {
t.Errorf("expected validator for %s to be %s, but was %s", casted.Name, validatorMap[casted.Name], casted.Validator)
}
}
// make sure validators with custom messages don't show up in the validator string
type CustomMessage struct {
Text string `valid:"length(1|10)~Custom message"`
}
cs := CustomMessage{Text: "asdfasdfasdfasdf"}
ok, errors = ValidateStruct(&cs)
if ok {
t.Errorf("expected validation to fail, %v", ok)
}
validator := errors.(Errors)[0].(Error).Validator
if validator != "length" {
t.Errorf("expected validator for Text to be length, but was %s", validator)
}
}
func TestIsRsaPublicKey(t *testing.T) {
var tests = []struct {
rsastr string
keylen int
expected bool
}{
{`fubar`, 2048, false},
{`MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvncDCeibmEkabJLmFec7x9y86RP6dIvkVxxbQoOJo06E+p7tH6vCmiGHKnuu
XwKYLq0DKUE3t/HHsNdowfD9+NH8caLzmXqGBx45/Dzxnwqz0qYq7idK+Qff34qrk/YFoU7498U1Ee7PkKb7/VE9BmMEcI3uoKbeXCbJRI
HoTp8bUXOpNTSUfwUNwJzbm2nsHo2xu6virKtAZLTsJFzTUmRd11MrWCvj59lWzt1/eIMN+ekjH8aXeLOOl54CL+kWp48C+V9BchyKCShZ
B7ucimFvjHTtuxziXZQRO7HlcsBOa0WwvDJnRnskdyoD31s4F4jpKEYBJNWTo63v6lUvbQIDAQAB`, 2048, true},
{`MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvncDCeibmEkabJLmFec7x9y86RP6dIvkVxxbQoOJo06E+p7tH6vCmiGHKnuu
XwKYLq0DKUE3t/HHsNdowfD9+NH8caLzmXqGBx45/Dzxnwqz0qYq7idK+Qff34qrk/YFoU7498U1Ee7PkKb7/VE9BmMEcI3uoKbeXCbJRI
HoTp8bUXOpNTSUfwUNwJzbm2nsHo2xu6virKtAZLTsJFzTUmRd11MrWCvj59lWzt1/eIMN+ekjH8aXeLOOl54CL+kWp48C+V9BchyKCShZ
B7ucimFvjHTtuxziXZQRO7HlcsBOa0WwvDJnRnskdyoD31s4F4jpKEYBJNWTo63v6lUvbQIDAQAB`, 1024, false},
{`-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvncDCeibmEkabJLmFec7
x9y86RP6dIvkVxxbQoOJo06E+p7tH6vCmiGHKnuuXwKYLq0DKUE3t/HHsNdowfD9
+NH8caLzmXqGBx45/Dzxnwqz0qYq7idK+Qff34qrk/YFoU7498U1Ee7PkKb7/VE9
BmMEcI3uoKbeXCbJRIHoTp8bUXOpNTSUfwUNwJzbm2nsHo2xu6virKtAZLTsJFzT
UmRd11MrWCvj59lWzt1/eIMN+ekjH8aXeLOOl54CL+kWp48C+V9BchyKCShZB7uc
imFvjHTtuxziXZQRO7HlcsBOa0WwvDJnRnskdyoD31s4F4jpKEYBJNWTo63v6lUv
bQIDAQAB
-----END PUBLIC KEY-----`, 2048, true},
{`-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvncDCeibmEkabJLmFec7
x9y86RP6dIvkVxxbQoOJo06E+p7tH6vCmiGHKnuuXwKYLq0DKUE3t/HHsNdowfD9
+NH8caLzmXqGBx45/Dzxnwqz0qYq7idK+Qff34qrk/YFoU7498U1Ee7PkKb7/VE9
BmMEcI3uoKbeXCbJRIHoTp8bUXOpNTSUfwUNwJzbm2nsHo2xu6virKtAZLTsJFzT
UmRd11MrWCvj59lWzt1/eIMN+ekjH8aXeLOOl54CL+kWp48C+V9BchyKCShZB7uc
imFvjHTtuxziXZQRO7HlcsBOa0WwvDJnRnskdyoD31s4F4jpKEYBJNWTo63v6lUv
bQIDAQAB
-----END PUBLIC KEY-----`, 4096, false},
}
for i, test := range tests {
actual := IsRsaPublicKey(test.rsastr, test.keylen)
if actual != test.expected {
t.Errorf("Expected TestIsRsaPublicKey(%d, %d) to be %v, got %v", i, test.keylen, test.expected, actual)
}
}
}