diff --git a/README.md b/README.md index 5ec177d..44ffffc 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ This package currently provides the following checkers: - [regexp](doc/checkers/regexp.md) checks if the given string matches the regexp pattern. - [required](doc/checkers/required.md) checks if the required value is provided. - [same](doc/checkers/same.md) checks if the given value is equal to the value of the field with the given name. +- [url](doc/checkers/url.md) checks if the given value is a valid URL. # Normalizers Provided diff --git a/checker.go b/checker.go index 6a1adaa..4a5cd6b 100644 --- a/checker.go +++ b/checker.go @@ -50,6 +50,7 @@ var makers = map[string]MakeFunc{ CheckerRegexp: makeRegexp, CheckerRequired: makeRequired, CheckerSame: makeSame, + CheckerURL: makeURL, NormalizerLower: makeLower, NormalizerUpper: makeUpper, NormalizerTitle: makeTitle, diff --git a/doc/checkers/url.md b/doc/checkers/url.md new file mode 100644 index 0000000..5d7778f --- /dev/null +++ b/doc/checkers/url.md @@ -0,0 +1,29 @@ +# URL Checker + +The ```url``` checker checks if the given value is a valid URL. If the given value is not a valid URL, the checker will return the ```NOT_URL``` result. The checker uses [ParseRequestURI](https://pkg.go.dev/net/url#ParseRequestURI) function to parse the URL, and then checks if the schema or the host are both set. + +Here is an example: + +```golang +type Bookmark struct { + URL string `checkers:"url"` +} + +bookmark := &Bookmark{ + URL: "https://zdo.com", +} + +_, valid := checker.Check(bookmark) +if !valid { + // Send the mistakes back to the user +} +``` + +In your custom checkers, you can call the ```url``` checker function ```IsURL``` to validate the user input. Here is an example: + +```golang +result := checker.IsURL("https://zdo.com") +if result != checker.ResultValid { + // Send the mistakes back to the user +} +``` diff --git a/url.go b/url.go new file mode 100644 index 0000000..1553d2a --- /dev/null +++ b/url.go @@ -0,0 +1,44 @@ +package checker + +import ( + "net/url" + "reflect" +) + +// CheckerURL is the name of the checker. +const CheckerURL = "url" + +// ResultNotURL indicates that the given value is not a valid URL. +const ResultNotURL = "NOT_URL" + +// IsURL checks if the given value is a valid URL. +func IsURL(value string) Result { + url, err := url.ParseRequestURI(value) + if err != nil { + return ResultNotURL + } + + if url.Scheme == "" { + return ResultNotURL + } + + if url.Host == "" { + return ResultNotURL + } + + return ResultValid +} + +// makeURL makes a checker function for the URL checker. +func makeURL(_ string) CheckFunc { + return checkURL +} + +// checkURL checks if the given value is a valid URL. +func checkURL(value, _ reflect.Value) Result { + if value.Kind() != reflect.String { + panic("string expected") + } + + return IsURL(value.String()) +} diff --git a/url_test.go b/url_test.go new file mode 100644 index 0000000..d501c18 --- /dev/null +++ b/url_test.go @@ -0,0 +1,93 @@ +package checker_test + +import ( + "testing" + + "github.com/cinar/checker" +) + +func TestIsURLValid(t *testing.T) { + result := checker.IsURL("https://zdo.com") + if result != checker.ResultValid { + t.Fail() + } +} + +func TestIsURLInvalid(t *testing.T) { + result := checker.IsURL("https:://index.html") + if result == checker.ResultValid { + t.Fail() + } +} + +func TestCheckURLNonString(t *testing.T) { + defer checker.FailIfNoPanic(t) + + type Bookmark struct { + URL int `checkers:"url"` + } + + bookmark := &Bookmark{} + + checker.Check(bookmark) +} + +func TestCheckURLValid(t *testing.T) { + type Bookmark struct { + URL string `checkers:"url"` + } + + bookmark := &Bookmark{ + URL: "https://zdo.com", + } + + _, valid := checker.Check(bookmark) + if !valid { + t.Fail() + } +} + +func TestCheckURLInvalid(t *testing.T) { + type Bookmark struct { + URL string `checkers:"url"` + } + + bookmark := &Bookmark{ + URL: "zdo.com/index.html", + } + + _, valid := checker.Check(bookmark) + if valid { + t.Fail() + } +} + +func TestCheckURLWithoutSchema(t *testing.T) { + type Bookmark struct { + URL string `checkers:"url"` + } + + bookmark := &Bookmark{ + URL: "//zdo.com/index.html", + } + + _, valid := checker.Check(bookmark) + if valid { + t.Fail() + } +} + +func TestCheckURLWithoutHost(t *testing.T) { + type Bookmark struct { + URL string `checkers:"url"` + } + + bookmark := &Bookmark{ + URL: "https:://index.html", + } + + _, valid := checker.Check(bookmark) + if valid { + t.Fail() + } +}