├── port.go
├── creditcard.go
├── go.mod
├── url.go
├── uuid.go
├── mac.go
├── internal
├── regexes
│ ├── mac.go
│ ├── uuid.go
│ ├── func.go
│ ├── domain.go
│ ├── hashes.go
│ └── url.go
├── test
│ ├── types.go
│ ├── port_test.go
│ ├── mac_test.go
│ ├── creditcard_test.go
│ ├── uuid_test.go
│ ├── luhn_test.go
│ ├── domain_test.go
│ ├── hashes_test.go
│ ├── ip_test.go
│ └── url_test.go
└── utilities
│ └── utilities.go
├── go.sum
├── .gitignore
├── domain.go
├── .github
└── workflows
│ └── go.yml
├── luhn.go
├── hashes.go
├── CHANGELOG.md
├── LICENSE
├── README.md
└── ip.go
/port.go:
--------------------------------------------------------------------------------
1 | package golidators
2 |
3 | // Port function for validating ports
4 | func Port(port int) bool {
5 | return 1 <= port && port <= 65535
6 | }
7 |
--------------------------------------------------------------------------------
/creditcard.go:
--------------------------------------------------------------------------------
1 | package golidators
2 |
3 | // CreditCard validate credit card number with Luhn
4 | func CreditCard(number int) bool {
5 | return Luhn(number)
6 | }
7 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/eredotpkfr/golidators
2 |
3 | go 1.23
4 |
5 | require golang.org/x/net v0.33.0
6 |
7 | require golang.org/x/text v0.21.0 // indirect
8 |
--------------------------------------------------------------------------------
/url.go:
--------------------------------------------------------------------------------
1 | package golidators
2 |
3 | import "github.com/eredotpkfr/golidators/internal/regexes"
4 |
5 | // Url function for validating URL's
6 | func Url(url string) bool {
7 | return regexes.URLRegex.MatchString(url)
8 | }
9 |
--------------------------------------------------------------------------------
/uuid.go:
--------------------------------------------------------------------------------
1 | package golidators
2 |
3 | import "github.com/eredotpkfr/golidators/internal/regexes"
4 |
5 | // Uuid function for validating UUID
6 | func Uuid(uuid string) bool {
7 | return regexes.UUIDRegex.MatchString(uuid)
8 | }
9 |
--------------------------------------------------------------------------------
/mac.go:
--------------------------------------------------------------------------------
1 | package golidators
2 |
3 | import "github.com/eredotpkfr/golidators/internal/regexes"
4 |
5 | // Mac function for validating MAC Addresses
6 | func Mac(macAddr string) bool {
7 | return regexes.MacRegex.MatchString(macAddr)
8 | }
9 |
--------------------------------------------------------------------------------
/internal/regexes/mac.go:
--------------------------------------------------------------------------------
1 | package regexes
2 |
3 | import rgx "regexp"
4 |
5 | const macPattern string = "^(?:[0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$"
6 |
7 | // MacRegex for validating MAC Addresses
8 | var MacRegex = rgx.MustCompile(makeCaseInsensitive(macPattern))
9 |
--------------------------------------------------------------------------------
/internal/regexes/uuid.go:
--------------------------------------------------------------------------------
1 | package regexes
2 |
3 | import rgx "regexp"
4 |
5 | const uuidPattern = "^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$"
6 |
7 | // UUIDRegex for validating UUID data
8 | var UUIDRegex = rgx.MustCompile(makeCaseInsensitive(uuidPattern))
9 |
--------------------------------------------------------------------------------
/internal/regexes/func.go:
--------------------------------------------------------------------------------
1 | package regexes
2 |
3 | // Ignore case prefix pattern for regex patterns
4 | const ignoreCase string = "(?i)"
5 |
6 | // Add ignoreCase flag any regex pattern
7 | func makeCaseInsensitive(pattern string) string {
8 | return ignoreCase + pattern
9 | }
10 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
2 | golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
3 | golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
4 | golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, built with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | # Dependency directories (remove the comment below to include it)
15 | # vendor/
16 |
--------------------------------------------------------------------------------
/internal/regexes/domain.go:
--------------------------------------------------------------------------------
1 | package regexes
2 |
3 | import rgx "regexp"
4 |
5 | const domainPattern string = "^(?:[a-zA-Z0-9]" +
6 | "(?:[a-zA-Z0-9-_]{0,61}[A-Za-z0-9])?\\.)" +
7 | "+[A-Za-z0-9][A-Za-z0-9-_]{0,61}" +
8 | "[A-Za-z]$"
9 |
10 | // DomainRegex for validating domains
11 | var DomainRegex = rgx.MustCompile(makeCaseInsensitive(domainPattern))
12 |
--------------------------------------------------------------------------------
/domain.go:
--------------------------------------------------------------------------------
1 | package golidators
2 |
3 | import (
4 | "github.com/eredotpkfr/golidators/internal/regexes"
5 | "golang.org/x/net/idna"
6 | )
7 |
8 | // Domain function for validating domains
9 | func Domain(domain string) bool {
10 | var idnap *idna.Profile = idna.New()
11 | domain, err := idnap.ToASCII(domain)
12 |
13 | if err != nil {
14 | return false
15 | }
16 |
17 | return regexes.DomainRegex.MatchString(domain)
18 | }
19 |
--------------------------------------------------------------------------------
/internal/test/types.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | // IntTestRecord for store int test data
4 | type IntTestRecord struct {
5 | TargetValue int
6 | Expected bool
7 | }
8 |
9 | // IntTestRecordWithIntReturn for store int test data
10 | type IntTestRecordWithIntReturn struct {
11 | TargetValue int
12 | Expected int
13 | }
14 |
15 | // StrTestRecord for store string test data
16 | type StrTestRecord struct {
17 | TargetValue string
18 | Expected bool
19 | }
20 |
--------------------------------------------------------------------------------
/internal/test/port_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/eredotpkfr/golidators"
7 | )
8 |
9 | var PortCases = [5]IntTestRecord{
10 | {12, true},
11 | {80, true},
12 | {443, true},
13 | {99999, false},
14 | {65536, false},
15 | }
16 |
17 | func TestPort(t *testing.T) {
18 | for _, record := range PortCases {
19 | if golidators.Port(record.TargetValue) != record.Expected {
20 | t.Error(record.TargetValue)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.github/workflows/go.yml:
--------------------------------------------------------------------------------
1 | name: Go
2 |
3 | on:
4 | push:
5 | branches: [ '*' ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 |
11 | build:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v2
15 |
16 | - name: Set up Go
17 | uses: actions/setup-go@v2
18 | with:
19 | go-version: 1.17
20 |
21 | - name: Build
22 | run: go build -v ./...
23 |
24 | - name: Test
25 | run: go test -v ./...
26 |
--------------------------------------------------------------------------------
/internal/test/mac_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/eredotpkfr/golidators"
7 | )
8 |
9 | var MacCases = [7]StrTestRecord{
10 | {"01:23:45:67:ab:CD", true},
11 | {"01:23:45:67:AB:CD", true},
12 | {"00:00:00:00:00", false},
13 | {"01:23:45:67:89:", false},
14 | {"01:23:45:67:89:gh", false},
15 | {"123:23:45:67:89:00", false},
16 | {"01:23:45:67:89:GH", false},
17 | }
18 |
19 | func TestMac(t *testing.T) {
20 | for _, record := range MacCases {
21 | if golidators.Mac(record.TargetValue) != record.Expected {
22 | t.Error(record.TargetValue)
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/internal/test/creditcard_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/eredotpkfr/golidators"
7 | )
8 |
9 | var CreditCardCases = [10]IntTestRecord{
10 | {1234567890, false},
11 | {1234567897, true},
12 | {5146713835430, false},
13 | {5146713835433, true},
14 | {5371087585041475, true},
15 | {5300025108592596, true},
16 | {5302025202593516, false},
17 | {5184214431476070, true},
18 | {5371087585041475, true},
19 | {5101365588025704, true},
20 | }
21 |
22 | func TestCreditCard(t *testing.T) {
23 | for _, record := range CreditCardCases {
24 | if golidators.CreditCard(record.TargetValue) != record.Expected {
25 | t.Error(record.TargetValue)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/internal/test/uuid_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/eredotpkfr/golidators"
7 | )
8 |
9 | var UUIDCases = [7]StrTestRecord{
10 | {"2bc1c94f-0deb-43e9-92a1-4775189ec9f8", true},
11 | {"d22877be-b0cf-4d81-99bf-242afba289a6", true},
12 | {"D22877BE-B0CF-4D81-99BF-242AFBA289A6", true},
13 | {"2bc1c94f-deb-43e9-92a1-4775189ec9f8", false},
14 | {"2bc1c94f-0deb-43e9-92a1-4775189ec9f", false},
15 | {"gbc1c94f-0deb-43e9-92a1-4775189ec9f8", false},
16 | {"2bc1c94f 0deb-43e9-92a1-4775189ec9f8", false},
17 | }
18 |
19 | func TestUuid(t *testing.T) {
20 | for _, record := range UUIDCases {
21 | if golidators.Uuid(record.TargetValue) != record.Expected {
22 | t.Error(record.TargetValue)
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/luhn.go:
--------------------------------------------------------------------------------
1 | package golidators
2 |
3 | func luhnChecksum(number int) int {
4 | var sum int = 0
5 |
6 | for i := 0; number > 0; i++ {
7 | digit := number % 10
8 |
9 | if i%2 == 0 {
10 | digit = digit * 2
11 |
12 | if digit > 9 {
13 | digit = digit%10 + digit/10
14 | }
15 | }
16 |
17 | sum += digit
18 | number = number / 10
19 | }
20 |
21 | return sum % 10
22 | }
23 |
24 | // Luhn checks if the given integer is valid according to the Luhn algorithm
25 | func Luhn(number int) bool {
26 | return (number%10+luhnChecksum(number/10))%10 == 0
27 | }
28 |
29 | // LuhnCheckDigit calculates the check digit for a given number using the Luhn algorithm
30 | func LuhnCheckDigit(number int) int {
31 | return (10 - luhnChecksum(number)) % 10
32 | }
33 |
--------------------------------------------------------------------------------
/hashes.go:
--------------------------------------------------------------------------------
1 | package golidators
2 |
3 | import "github.com/eredotpkfr/golidators/internal/regexes"
4 |
5 | // Md5 function for validating MD5
6 | func Md5(md5 string) bool {
7 | return regexes.Md5Regex.MatchString(md5)
8 | }
9 |
10 | // Sha1 function for validating SHA1
11 | func Sha1(sha1 string) bool {
12 | return regexes.Sha1Regex.MatchString(sha1)
13 | }
14 |
15 | // Sha224 function for validating SHA224
16 | func Sha224(sha224 string) bool {
17 | return regexes.Sha224Regex.MatchString(sha224)
18 | }
19 |
20 | // Sha256 function for validating SHA256
21 | func Sha256(sha256 string) bool {
22 | return regexes.Sha256Regex.MatchString(sha256)
23 | }
24 |
25 | // Sha512 function for validating SHA512
26 | func Sha512(sha512 string) bool {
27 | return regexes.Sha512Regex.MatchString(sha512)
28 | }
29 |
--------------------------------------------------------------------------------
/internal/regexes/hashes.go:
--------------------------------------------------------------------------------
1 | package regexes
2 |
3 | import rgx "regexp"
4 |
5 | const (
6 | md5Pattern string = "^[0-9a-f]{32}$"
7 | sha1Pattern string = "^[0-9a-f]{40}$"
8 | sha224Pattern string = "^[0-9a-f]{56}$"
9 | sha256Pattern string = "^[0-9a-f]{64}$"
10 | sha512Pattern string = "^[0-9a-f]{128}$"
11 | )
12 |
13 | var (
14 | // Md5Regex for validating MD5
15 | Md5Regex = rgx.MustCompile(makeCaseInsensitive(md5Pattern))
16 | // Sha1Regex for validating SHA1
17 | Sha1Regex = rgx.MustCompile(makeCaseInsensitive(sha1Pattern))
18 | // Sha224Regex for validating SHA224
19 | Sha224Regex = rgx.MustCompile(makeCaseInsensitive(sha224Pattern))
20 | // Sha256Regex for validating SHA256
21 | Sha256Regex = rgx.MustCompile(makeCaseInsensitive(sha256Pattern))
22 | // Sha512Regex for validating SHA512
23 | Sha512Regex = rgx.MustCompile(makeCaseInsensitive(sha512Pattern))
24 | )
25 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6 |
7 | ## Unreleased
8 |
9 | ## 0.1.6 - 2024-12-22
10 |
11 | ### Added
12 |
13 | - Credit card validator
14 | - Luhn validator
15 | - Luhn check digit calculation function
16 |
17 | ## 0.1.5 - 2021-10-11
18 |
19 | ### Added
20 |
21 | - Extended IP test cases
22 |
23 | ## 0.1.4 - 2021-09-28
24 |
25 | ### Fixed
26 |
27 | - Fixed critical bug in `Ipv4Cidr` and `Ipv6Cidr` validators. For details [issue #1](https://github.com/eredotpkfr/golidators/issues/1)
28 |
29 | ### Added
30 |
31 | - Extended IP test cases
32 |
33 | ## 0.1.3 - 2021-09-27
34 |
35 | ### Added
36 |
37 | - Added following validators:
38 | - Domain
39 | - MD5, SHA1, SHA224, SHA256, SHA512
40 | - IPv4, IPv4CIDR, IPv6, IPv6CIDR
41 | - MAC
42 | - Port
43 | - URL
44 | - UUID
45 | - Tests were done
46 |
--------------------------------------------------------------------------------
/internal/test/luhn_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/eredotpkfr/golidators"
7 | )
8 |
9 | var LuhnCases = [7]IntTestRecord{
10 | {1234567890, false},
11 | {1234567897, true},
12 | {5146713835430, false},
13 | {5146713835433, true},
14 | {5371087585041475, true},
15 | {5300025108592596, true},
16 | {5302025202593516, false},
17 | }
18 |
19 | var LuhnCheckDigitCases = [7]IntTestRecordWithIntReturn{
20 | {1234567890, 3},
21 | {1234567897, 8},
22 | {5146713835430, 2},
23 | {5146713835433, 6},
24 | {5371087585041475, 1},
25 | {5300025108592596, 2},
26 | {5302025202593516, 6},
27 | }
28 |
29 | func TestLuhn(t *testing.T) {
30 | for _, record := range LuhnCases {
31 | if golidators.Luhn(record.TargetValue) != record.Expected {
32 | t.Error(record.TargetValue)
33 | }
34 | }
35 | }
36 |
37 | func TestLuhnCheckDigit(t *testing.T) {
38 | for _, record := range LuhnCheckDigitCases {
39 | if golidators.LuhnCheckDigit(record.TargetValue) != record.Expected {
40 | t.Error(record.TargetValue)
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Erdoğan Yoksul
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/internal/utilities/utilities.go:
--------------------------------------------------------------------------------
1 | package utilities
2 |
3 | // 0xFFFFFF -> 16777215
4 | const big = 0xFFFFFF
5 |
6 | // Xtoi is Hexadecimal to integer.
7 | // Returns number, characters consumed, success.
8 | // Official function definition is here: https://cs.opensource.google/go/go/+/refs/tags/go1.17.1:src/net/parse.go
9 | func Xtoi(s string) (n int, i int, ok bool) {
10 | n = 0
11 | for i = 0; i < len(s); i++ {
12 | if '0' <= s[i] && s[i] <= '9' {
13 | n *= 16
14 | n += int(s[i] - '0')
15 | } else if 'a' <= s[i] && s[i] <= 'f' {
16 | n *= 16
17 | n += int(s[i]-'a') + 10
18 | } else if 'A' <= s[i] && s[i] <= 'F' {
19 | n *= 16
20 | n += int(s[i]-'A') + 10
21 | } else {
22 | break
23 | }
24 | if n >= big {
25 | return 0, i, false
26 | }
27 | }
28 | if i == 0 {
29 | return 0, i, false
30 | }
31 | return n, i, true
32 | }
33 |
34 | // Dtoi is Decimal to integer.
35 | // Returns number, characters consumed, success.
36 | // Official function definition is here: https://cs.opensource.google/go/go/+/refs/tags/go1.17.1:src/net/parse.go
37 | func Dtoi(s string) (n int, i int, ok bool) {
38 | n = 0
39 | for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
40 | n = n*10 + int(s[i]-'0')
41 | if n >= big {
42 | return big, i, false
43 | }
44 | }
45 | if i == 0 {
46 | return 0, 0, false
47 | }
48 | return n, i, true
49 | }
50 |
--------------------------------------------------------------------------------
/internal/test/domain_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/eredotpkfr/golidators"
7 | )
8 |
9 | var DomainCases = [35]StrTestRecord{
10 | {"example.com", true},
11 | {"EXAMPLE.com", true},
12 | {"xn----gtbspbbmkef.xn--p1ai", true},
13 | {"underscore_subdomain.example.com", true},
14 | {"something.versicherung", true},
15 | {"someThing.versicherung", true},
16 | {"11.com", true},
17 | {"11.COM", true},
18 | {"3.cn", true},
19 | {"a.cn", true},
20 | {"sub1.sub2.sample.co.uk", true},
21 | {"somerandomexample.xn--fiqs8s", true},
22 | {"kräuter.com", true},
23 | {"über.com", true},
24 | {"xn--eckwd4c7c.xn--zckzah", true},
25 | {"XN--ECKWD4C7C.XN--ZCKZAH", true},
26 | {"www.google.com", true},
27 | {"google.com", true},
28 | {"example.com/", false},
29 | {"example.com:4444", false},
30 | {"example.-com", false},
31 | {"example.", false},
32 | {"-example.com", false},
33 | {"example-.com", false},
34 | {"_example.com", false},
35 | {"example_.com", false},
36 | {"EXAMPLE_.COM", false},
37 | {"example", false},
38 | {"a......b.com", false},
39 | {"A......B.COM", false},
40 | {"a.123", false},
41 | {"123.123", false},
42 | {"123.123.123", false},
43 | {"123.123.123.123", false},
44 | {"example.com:4444", false},
45 | }
46 |
47 | func TestDomain(t *testing.T) {
48 | for _, record := range DomainCases {
49 | if golidators.Domain(record.TargetValue) != record.Expected {
50 | t.Error(record.TargetValue)
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | [](https://goreportcard.com/report/github.com/eredotpkfr/golidators)
3 | [](https://pkg.go.dev/github.com/eredotpkfr/golidators)
4 | [](https://golang.org/)
5 | [](https://github.com/eredotpkfr/golidators/releases/latest)
6 | [](https://github.com/eredotpkfr/golidators/blob/main/LICENSE)
7 | [](https://github.com/eredotpkfr/golidators/stargazers)
8 |
9 | # golidators
10 |
11 | Golidators is a golang package, it includes basic data validation functions and regexes
12 |
13 | ## Install
14 |
15 | ```bash
16 | ~$ go get github.com/eredotpkfr/golidators
17 | ```
18 |
19 | ## Overview
20 |
21 | Following validators available on this package:
22 |
23 | - Domain
24 | - MD5, SHA1, SHA224, SHA256, SHA512
25 | - IPv4, IPv4CIDR, IPv6, IPv6CIDR
26 | - MAC
27 | - Port
28 | - URL
29 | - UUID
30 | - CreditCard/Luhn
31 |
32 | ## Usage
33 |
34 | Just import and use it. Also see documentation at [pkg.go.dev](https://pkg.go.dev/github.com/eredotpkfr/golidators#section-documentation)
35 |
36 | ```go
37 | package main
38 |
39 | import (
40 | "github.com/eredotpkfr/golidators"
41 | "fmt"
42 | )
43 |
44 | func main() {
45 | // Validate domain address
46 | fmt.Println(golidators.Domain("www.example.com"))
47 | // Validate IPv4 address
48 | fmt.Println(golidators.Ipv4("::1"))
49 | // Validate IPv6 address
50 | fmt.Println(golidators.Ipv6("::1"))
51 | // Validate URL
52 | fmt.Println(golidators.Url("https://www.example.com"))
53 | // Validate IPv4CIDR
54 | fmt.Println(golidators.Ipv4Cidr("127.0.0.1/12"))
55 | // Validate most common hashes
56 | fmt.Println(golidators.Md5("foo/bar"))
57 | // Validate with Luhn algorithm
58 | fmt.Println(golidators.Luhn(5300025108592596))
59 | // Calculate check digit with Luhn algorithm
60 | fmt.Println(golidators.LuhnCheckDigit(5146713835433))
61 | // Validate credit card number with Luhn
62 | fmt.Println(golidators.CreditCard(5184214431476070))
63 | }
64 | ```
65 |
66 | ## Contact
67 |
68 | Blog - [erdoganyoksul.com](https://www.erdoganyoksul.com)
69 | Mail - erdoganyoksul3@gmail.com
70 |
--------------------------------------------------------------------------------
/internal/test/hashes_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/eredotpkfr/golidators"
7 | )
8 |
9 | var (
10 | Md5Cases = [4]StrTestRecord{
11 | {"fffd51c41b9176ae3ed36a97699018eb", true},
12 | {"D41D8CD98F00B204E9800998ECF8427E", true},
13 | {"fffd51c41b9176ae3ed36a97699018eaa", false},
14 | {"D41D8CD98F00B204E9800998ECF8427EA", false},
15 | }
16 | Sha1Cases = [4]StrTestRecord{
17 | {"7cf42528c35d46dad692c67b985240f63d53f63e", true},
18 | {"930A0029225AA4C28B8EF095B679285EAAE27078", true},
19 | {"7cf42528c35d46dad692c67b985240f63d53f63eaasdasd", false},
20 | {"930A0029225AA4C28B8EF095B679285EAAE27078AKLMCDE", false},
21 | }
22 | Sha224Cases = [4]StrTestRecord{
23 | {"448b9c7aa6f6245ee1d77e7d140c73179f7f7a596dd386f62a0f6912", true},
24 | {"448B9C7AA6F6245EE1D77E7D140C73179F7F7A596DD386F62A0F6912", true},
25 | {"z14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", false},
26 | {"Z14A028C2A3A2BC9476102BB288234C415A2B01F828EA62AC5B3E42F", false},
27 | }
28 | Sha256Cases = [4]StrTestRecord{
29 | {"d8a928b2043db77e340b523547bf16cb4aa483f0645fe0a290ed1f20aab76257", true},
30 | {"D8A928B2043DB77E340B523547BF16CB4AA483F0645FE0A290ED1F20AAB76257", true},
31 | {"7815696ecbf1c96e6894b779456d330e", false},
32 | {"7815696ECBF1C96E6894B779456D330E", false},
33 | }
34 | Sha512Cases = [4]StrTestRecord{
35 | {"7621770eae0880e21dbf3939f045b9a44013f190df54243f0a4b3d28806d2c55c5de651d4fd4160e09ec3af805695275da1933044a70677a3efa361943644577", true},
36 | {"7621770EAE0880E21DBF3939F045B9A44013F190DF54243F0A4B3D28806D2C55C5DE651D4FD4160E09EC3AF805695275DA1933044A70677A3EFA361943644577", true},
37 | {"7815696ecbf1c96e6894b779456d330e", false},
38 | {"7815696ECBF1C96E6894B779456D330E", false},
39 | }
40 | )
41 |
42 | func TestMd5(t *testing.T) {
43 | for _, record := range Md5Cases {
44 | if golidators.Md5(record.TargetValue) != record.Expected {
45 | t.Error(record.TargetValue)
46 | }
47 | }
48 | }
49 |
50 | func TestSha1(t *testing.T) {
51 | for _, record := range Sha1Cases {
52 | if golidators.Sha1(record.TargetValue) != record.Expected {
53 | t.Error(record.TargetValue)
54 | }
55 | }
56 | }
57 |
58 | func TestSha224(t *testing.T) {
59 | for _, record := range Sha224Cases {
60 | if golidators.Sha224(record.TargetValue) != record.Expected {
61 | t.Error(record.TargetValue)
62 | }
63 | }
64 | }
65 |
66 | func TestSha256(t *testing.T) {
67 | for _, record := range Sha256Cases {
68 | if golidators.Sha256(record.TargetValue) != record.Expected {
69 | t.Error(record.TargetValue)
70 | }
71 | }
72 | }
73 |
74 | func TestSha512(t *testing.T) {
75 | for _, record := range Sha512Cases {
76 | if golidators.Sha512(record.TargetValue) != record.Expected {
77 | t.Error(record.TargetValue)
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/ip.go:
--------------------------------------------------------------------------------
1 | package golidators
2 |
3 | import (
4 | "strings"
5 |
6 | utils "github.com/eredotpkfr/golidators/internal/utilities"
7 | )
8 |
9 | const (
10 | // IP CIDR separator
11 | cidrSep = "/"
12 |
13 | // 0xFF -> 255
14 | ipv4MaxPart = 0xFF
15 | ipv4Length = 4
16 |
17 | // 0xFFFF -> 65535
18 | ipv6MaxPart = 0xFFFF
19 | ipv6Length = 16
20 | )
21 |
22 | // Ipv4 function for validating IPv4
23 | func Ipv4(ipv4Addr string) bool {
24 | for index := 0; index < ipv4Length; index++ {
25 |
26 | if len(ipv4Addr) == 0 {
27 | return false
28 | }
29 |
30 | if index > 0 {
31 | if ipv4Addr[0] != '.' {
32 | return false
33 | }
34 |
35 | ipv4Addr = ipv4Addr[1:]
36 | }
37 |
38 | number, consumed, ok := utils.Dtoi(ipv4Addr)
39 |
40 | if !ok || number > ipv4MaxPart {
41 | return false
42 | }
43 |
44 | if consumed > 1 && ipv4Addr[0] == '0' {
45 | return false
46 | }
47 |
48 | ipv4Addr = ipv4Addr[consumed:]
49 |
50 | }
51 |
52 | return len(ipv4Addr) == 0
53 | }
54 |
55 | // Ipv4Cidr function for validating IPv4CIDR
56 | func Ipv4Cidr(ipv4AddrCidr string) bool {
57 | splitted := strings.Split(ipv4AddrCidr, cidrSep)
58 |
59 | if len(splitted) != 2 {
60 | return false
61 | }
62 |
63 | prefix, suffix := splitted[0], splitted[1]
64 | number, consumed, ok := utils.Dtoi(suffix)
65 |
66 | if !ok || !Ipv4(prefix) || consumed > 2 {
67 | return false
68 | }
69 |
70 | return 0 <= number && number <= 32
71 | }
72 |
73 | // Ipv6 function for validating IPv6
74 | func Ipv6(ipv6Addr string) bool {
75 | ellipsis := -1
76 |
77 | if len(ipv6Addr) >= 2 && ipv6Addr[0] == ':' && ipv6Addr[1] == ':' {
78 | ellipsis = 0
79 | ipv6Addr = ipv6Addr[2:]
80 |
81 | if len(ipv6Addr) == 0 {
82 | return true
83 | }
84 | }
85 |
86 | index := 0
87 | for index < ipv6Length {
88 | number, consumed, ok := utils.Xtoi(ipv6Addr)
89 |
90 | if !ok || number > ipv6MaxPart {
91 | return false
92 | }
93 |
94 | if consumed < len(ipv6Addr) && ipv6Addr[consumed] == '.' {
95 | if ellipsis < 0 && index != ipv6Length-ipv4Length {
96 | return false
97 | }
98 | if index+ipv4Length > ipv6Length {
99 | return false
100 | }
101 | if !Ipv4(ipv6Addr) {
102 | return false
103 | }
104 |
105 | ipv6Addr = ""
106 | index += ipv4Length
107 | break
108 | }
109 |
110 | index += 2
111 |
112 | ipv6Addr = ipv6Addr[consumed:]
113 | if len(ipv6Addr) == 0 {
114 | break
115 | }
116 |
117 | if ipv6Addr[0] != ':' || len(ipv6Addr) == 1 {
118 | return false
119 | }
120 |
121 | ipv6Addr = ipv6Addr[1:]
122 |
123 | if ipv6Addr[0] == ':' {
124 | if ellipsis >= 0 {
125 | return false
126 | }
127 |
128 | ellipsis = index
129 | ipv6Addr = ipv6Addr[1:]
130 |
131 | if len(ipv6Addr) == 0 {
132 | break
133 | }
134 |
135 | }
136 | }
137 |
138 | if len(ipv6Addr) != 0 {
139 | return false
140 | }
141 |
142 | if index < ipv6Length {
143 | if ellipsis < 0 {
144 | return false
145 | }
146 | } else if ellipsis >= 0 {
147 | return false
148 | }
149 |
150 | return true
151 | }
152 |
153 | // Ipv6Cidr function for validating IPv6CIDR
154 | func Ipv6Cidr(ipv6AddrCidr string) bool {
155 | splitted := strings.Split(ipv6AddrCidr, cidrSep)
156 |
157 | if len(splitted) != 2 {
158 | return false
159 | }
160 |
161 | prefix, suffix := splitted[0], splitted[1]
162 | number, consumed, ok := utils.Dtoi(suffix)
163 |
164 | if !ok || !Ipv6(prefix) || consumed > 3 {
165 | return false
166 | }
167 |
168 | return 0 <= number && number <= 128
169 | }
170 |
--------------------------------------------------------------------------------
/internal/regexes/url.go:
--------------------------------------------------------------------------------
1 | package regexes
2 |
3 | import rgx "regexp"
4 |
5 | const (
6 | // IP octets
7 | ipMiddleOctet string = "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5]))"
8 | ipLastOctet string = "(?:\\.(?:0|[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-5]))"
9 |
10 | urlPattern string = "^" +
11 | // protocol identifier
12 | "(?:(?:https?|ftp)://)" +
13 | // user:pass authentication
14 | "(?:[-a-z\u00a1-\uffff0-9._~%!$&'()*+,;=:]+" +
15 | "(?::[-a-z0-9._~%!$&'()*+,;=:]*)?@)?" +
16 | "(?:" +
17 | "(?P" +
18 | // IP address exclusion
19 | // private & local networks
20 | "(?:(?:10|127)" + ipMiddleOctet + "{2}" + ipLastOctet + ")|" +
21 | "(?:(?:169\\.254|192\\.168)" + ipMiddleOctet + ipLastOctet + ")|" +
22 | "(?:172\\.(?:1[6-9]|2\\d|3[0-1])" + ipMiddleOctet + ipLastOctet + "))" +
23 | "|" +
24 | // private & local hosts
25 | "(?P" +
26 | "(?:localhost))" +
27 | "|" +
28 | // IP address dotted notation octets
29 | // excludes loopback network 0.0.0.0
30 | // excludes reserved space >= 224.0.0.0
31 | // excludes network & broadcast addresses
32 | // (first & last IP address of each class)
33 | "(?P" +
34 | "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
35 | "" + ipMiddleOctet + "{2}" +
36 | "" + ipLastOctet + ")" +
37 | "|" +
38 | // IPv6 RegEx from https://stackoverflow.com/a/17871737
39 | "\\[(" +
40 | // 1:2:3:4:5:6:7:8
41 | "([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" +
42 | // 1:: 1:2:3:4:5:6:7::
43 | "([0-9a-fA-F]{1,4}:){1,7}:|" +
44 | // 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8
45 | "([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" +
46 | // 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8
47 | "([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" +
48 | // 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8
49 | "([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" +
50 | // 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8
51 | "([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" +
52 | // 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8
53 | "([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" +
54 | // 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8
55 | "[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" +
56 | // ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 ::
57 | ":((:[0-9a-fA-F]{1,4}){1,7}|:)|" +
58 | // fe80::7:8%eth0 fe80::7:8%1
59 | // (link-local IPv6 addresses with zone index)
60 | "fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|" +
61 | "::(ffff(:0{1,4}){0,1}:){0,1}" +
62 | "((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}" +
63 | // ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255
64 | // (IPv4-mapped IPv6 addresses and IPv4-translated addresses)
65 | "(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|" +
66 | "([0-9a-fA-F]{1,4}:){1,4}:" +
67 | "((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}" +
68 | // 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33
69 | // (IPv4-Embedded IPv6 Address)
70 | "(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])" +
71 | ")\\]|" +
72 | // host name
73 | "(?:(?:(?:xn--)|[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]-?)*" +
74 | "[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]+)" +
75 | // domain name
76 | "(?:\\.(?:(?:xn--)|[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]-?)*" +
77 | "[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]+)*" +
78 | // TLD identifier
79 | "(?:\\.(?:(?:xn--[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]{2,})|" +
80 | "[a-z\u00a1-\uffff\U00010000-\U0010ffff]{2,}))" +
81 | ")" +
82 | // port number
83 | "(?::\\d{2,5})?" +
84 | // resource path
85 | "(?:/[-a-z\u00a1-\uffff\U00010000-\U0010ffff0-9._~%!$&'()*+,;=:@/]*)?" +
86 | // query string
87 | "(?:\\?\\S*)?" +
88 | // fragment
89 | "(?:#\\S*)?" +
90 | "$"
91 | )
92 |
93 | // URLRegex for validating URL data
94 | var URLRegex = rgx.MustCompile(makeCaseInsensitive(urlPattern))
95 |
--------------------------------------------------------------------------------
/internal/test/ip_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/eredotpkfr/golidators"
7 | )
8 |
9 | var (
10 | Ipv4Cases = [26]StrTestRecord{
11 | {"127.0.0.1", true},
12 | {"10.0.0.0", true},
13 | {"192.168.1.43", true},
14 | {"95.67.123.56", true},
15 | {"", false},
16 | {"123.5.77.88", true},
17 | {"12.12.12.12", true},
18 | {"255.255.255.255", true},
19 | {"abc.0.0.1", false},
20 | {"1278.0.0.1", false},
21 | {"127.0.0.abc", false},
22 | {"900.200.100.75", false},
23 | {"10.0.0.0:8080", false},
24 | {"foo/bar", false},
25 | {"127.0.0.1.", false},
26 | {".......", false},
27 | {"127.0.0.1....", false},
28 | {"...127.0.0.1...", false},
29 | {".127.0.0.1", false},
30 | {"foo", false},
31 | {"::1::2", false},
32 | {"::1", false},
33 | {"127.0.0.1.1.2.3", false},
34 | {".127.0.0.1.", false},
35 | {"clear.text", false},
36 | {" ", false},
37 | }
38 | Ipv4CidrCases = [27]StrTestRecord{
39 | {"127.0.0.1/0", true},
40 | {"123.5.77.88/8", true},
41 | {"239.0.0.0/8", true},
42 | {"12.12.12.12/32", true},
43 | {"127.0.0.1/12", true},
44 | {"192.168.1.45/24", true},
45 | {"abc.0.0.1", false},
46 | {"1.1.1.1", false},
47 | {"1.1.1.1/-1", false},
48 | {"1.1.1.1/33", false},
49 | {"1.1.1.1/foo", false},
50 | {"127.0.b.a/12", false},
51 | {"127.0.0.2/44", false},
52 | {"a.b.c/123/", false},
53 | {".127.0.0.1/12", false},
54 | {"..127.0.0.1/12", false},
55 | {"127.0.0.1./12", false},
56 | {"127.0.0.1../12", false},
57 | {"", false},
58 | {" ", false},
59 | {"foo", false},
60 | {"foo/bar", false},
61 | {"127.0.0.1/12/13/14", false},
62 | {"/", false},
63 | {"////", false},
64 | {"foo/bar/", false},
65 | {"/foo/bar", false},
66 | }
67 | Ipv6Cases = [20]StrTestRecord{
68 | {"::1", true},
69 | {"2002::", true},
70 | {"0:0:0:0:0:ffff:c0a8:12b", true},
71 | {"dead:beef:0:0:0:0:42:1", true},
72 | {"abcd:ef::42:1", true},
73 | {"0:0:0:0:0:ffff:1.2.3.4", true},
74 | {"2001:0db8:0000:0000:0000:ff00:0042:8329", true},
75 | {"::192.168.30.2", true},
76 | {"abc.0.0.1", false},
77 | {"2002::::::::::", false},
78 | {"abcd:1234::123::1", false},
79 | {"1:2:3:4:5:6:7:8:9", false},
80 | {"abcd::1ffff", false},
81 | {"", false},
82 | {" ", false},
83 | {"foo", false},
84 | {"////", false},
85 | {":", false},
86 | {"::::", false},
87 | {"deag:beef:0:0:0:0:42:1", false},
88 | }
89 | Ipv6CidrCases = [26]StrTestRecord{
90 | {"::1/0", true},
91 | {"2002::/12", true},
92 | {"dead:beef:0:0:0:0:42:1/8", true},
93 | {"abcd:ef::42:1/32", true},
94 | {"0:0:0:0:0:ffff:1.2.3.4/64", true},
95 | {"::192.168.30.2/128", true},
96 | {"abc.0.0.1", false},
97 | {"abcd:1234::123::1", false},
98 | {"1:2:3:4:5:6:7:8:9", false},
99 | {"abcd::1ffff", false},
100 | {"1.1.1.1", false},
101 | {"::1", false},
102 | {"::1/129", false},
103 | {"::1/-1", false},
104 | {"::1/foo", false},
105 | {"::1/144", false},
106 | {"2002::::::::::/12", false},
107 | {"127.0.0.1/12/13/14", false},
108 | {"/", false},
109 | {"", false},
110 | {" ", false},
111 | {"///", false},
112 | {"....", false},
113 | {"....", false},
114 | {"foo/bar/", false},
115 | {"/foo/bar", false},
116 | }
117 | )
118 |
119 | func TestIpv4(t *testing.T) {
120 | for _, record := range Ipv4Cases {
121 | if golidators.Ipv4(record.TargetValue) != record.Expected {
122 | t.Error(record.TargetValue)
123 | }
124 | }
125 | }
126 |
127 | func TestIpv4Cidr(t *testing.T) {
128 | for _, record := range Ipv4CidrCases {
129 | if golidators.Ipv4Cidr(record.TargetValue) != record.Expected {
130 | t.Error(record.TargetValue)
131 | }
132 | }
133 | }
134 |
135 | func TestIpv6(t *testing.T) {
136 | for _, record := range Ipv6Cases {
137 | if golidators.Ipv6(record.TargetValue) != record.Expected {
138 | t.Error(record.TargetValue)
139 | }
140 | }
141 | }
142 |
143 | func TestIpv6Cidr(t *testing.T) {
144 | for _, record := range Ipv6CidrCases {
145 | if golidators.Ipv6Cidr(record.TargetValue) != record.Expected {
146 | t.Error(record.TargetValue)
147 | }
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/internal/test/url_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/eredotpkfr/golidators"
7 | )
8 |
9 | var URLCases = [118]StrTestRecord{
10 | {"http://foobar.dk", true},
11 | {"http://foobar.museum/foobar", true},
12 | {"http://fo.com", true},
13 | {"http://www.google.com", true},
14 | {"ftp://www.test.co/", true},
15 | {"https://www.facebook.com/", true},
16 | {"http://FOO.com", true},
17 | {"http://foo.com/blah_blah", true},
18 | {"http://foo.com/blah_blah/", true},
19 | {"http://foo.com/blah_blah_(wikipedia)", true},
20 | {"http://foo.com/blah_blah_(wikipedia)_(again)", true},
21 | {"http://www.example.com/wpstyle/?p=364", true},
22 | {"https://www.example.com/foo/?bar=baz&inga=42&quux", true},
23 | {"https://www.example.com?bar=baz", true},
24 | {"http://✪df.ws/123", true},
25 | {"http://www.test.co?id=2&q=test#asdasda", true},
26 | {"http://userid:password@example.com:8080", true},
27 | {"http://userid:password@example.com:8080/", true},
28 | {"http://userid@example.com", true},
29 | {"http://userid@example.com/", true},
30 | {"http://userid@example.com:8080", true},
31 | {"http://userid@example.com:8080/", true},
32 | {"http://userid:password@example.com", true},
33 | {"http://userid:password@example.com/", true},
34 | {"http://142.42.1.1/", true},
35 | {"http://142.42.1.1:8080/", true},
36 | {"http://➡.ws/䨹", true},
37 | {"http://⌘.ws", true},
38 | {"http://⌘.ws/", true},
39 | {"http://foo.com/blah_(wikipedia)#cite-1", true},
40 | {"http://foo.com/blah_(wikipedia)_blah#cite-1", true},
41 | {"http://foo.com/unicode_(✪)_in_parens", true},
42 | {"http://foo.com/(something)?after=parens", true},
43 | {"http://☺.damowmow.com/", true},
44 | {"http://code.google.com/events/#&product=browser", true},
45 | {"http://j.mp", true},
46 | {"ftp://foo.bar/baz", true},
47 | {"http://foo.bar/?q=Test%20URL-encoded%20stuff", true},
48 | {"http://مثال.إختبار", true},
49 | {"http://例子.测试", true},
50 | {"http://उदाहरण.परीक्षा", true},
51 | {"http://www.😉.com", true},
52 | {"http://😉.com/😁", true},
53 | {"http://উদাহরণ.বাংলা", true},
54 | {"http://xn--d5b6ci4b4b3a.xn--54b7fta0cc", true},
55 | {"http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", true},
56 | {"http://1337.net", true},
57 | {"http://a.b-c.de", true},
58 | {"http://223.255.255.254", true},
59 | {"http://10.1.1.0", true},
60 | {"http://10.1.1.1", true},
61 | {"http://10.1.1.254", true},
62 | {"http://10.1.1.255", true},
63 | {"http://127.0.0.1:8080", true},
64 | {"http://127.0.10.150", true},
65 | {"http://localhost", true},
66 | {"http://localhost:8000", true},
67 | {"http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html", true},
68 | {"http://[1080:0:0:0:8:800:200C:417A]/index.html", true},
69 | {"http://[3ffe:2a00:100:7031::1]", true},
70 | {"http://[1080::8:800:200C:417A]/foo", true},
71 | {"http://[::192.9.5.5]/ipng", true},
72 | {"http://[::FFFF:129.144.52.38]:80/index.html", true},
73 | {"http://[2010:836B:4179::836B:4179]", true},
74 | {"", false},
75 | {"google.com", false},
76 | {"www.google.com", false},
77 | {"çç3#>#>£#>{¾[¾{]âßâ¢ß", false},
78 | {"http://http://asdad.com/?id=2", false},
79 | {"\" 'test')\"", false},
80 | {"http://foobar", false},
81 | {"http://127.0.0/asdf", false},
82 | {"http://foobar.d", false},
83 | {"http://foobar.12", false},
84 | {"http://foobar", false},
85 | {"htp://foobar.com", false},
86 | {"http://foobar..com", false},
87 | {"http://fo..com", false},
88 | {"http://", false},
89 | {"http://.", false},
90 | {"http://..", false},
91 | {"http://../", false},
92 | {"http://?", false},
93 | {"http://??", false},
94 | {"http://??/", false},
95 | {"http://#", false},
96 | {"http://##", false},
97 | {"http://##/", false},
98 | {"http://foo.bar?q=Spaces should be encoded", false},
99 | {"//", false},
100 | {"//a", false},
101 | {"///a", false},
102 | {"///", false},
103 | {"http:///a", false},
104 | {"foo.com", false},
105 | {"rdar://1234", false},
106 | {"h://test", false},
107 | {"http:// shouldfail.com", false},
108 | {":// should fail", false},
109 | {"http://foo.bar/foo(bar)baz quux", false},
110 | {"ftps://foo.bar/", false},
111 | {"http://-error-.invalid/", false},
112 | {"http://a.b--c.de/", false},
113 | {"http://-a.b.co", false},
114 | {"http://a.b-.co", false},
115 | {"http://0.0.0.0", false},
116 | {"http://224.1.1.1", false},
117 | {"http://1.1.1.1.1", false},
118 | {"http://123.123.123", false},
119 | {"http://3628126748", false},
120 | {"http://.www.foo.bar/", false},
121 | {"http://www.foo.bar./", false},
122 | {"http://.www.foo.bar./", false},
123 | {"http://127.12.0.260", false},
124 | {"http://example.com/\">user@example.com", false},
125 | {"http://[2010:836B:4179::836B:4179", false},
126 | {"http://2010:836B:4179::836B:4179", false},
127 | {"http://2010:836B:4179::836B:4179:80/index.html", false},
128 | }
129 |
130 | func TestUrl(t *testing.T) {
131 | for _, record := range URLCases {
132 | if golidators.Url(record.TargetValue) != record.Expected {
133 | t.Error(record.TargetValue)
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------