diff --git a/url.go b/url.go new file mode 100644 index 00000000..5eb759c3 --- /dev/null +++ b/url.go @@ -0,0 +1,88 @@ +package pflag + +import ( + "fmt" + "net/url" +) + +// -- url.Value +type urlValue struct { + value *url.URL + changed bool +} + +func newURLValue(val *url.URL, p *url.URL) *urlValue { + uv := new(urlValue) + uv.value = p + *uv.value = *val + return uv +} + +func (u *urlValue) Set(s string) error { + v, err := url.Parse(s) + if err != nil { + return fmt.Errorf("failed to parse URL: %w", err) + } + *u.value = *v + u.changed = true + return nil +} + +func (u *urlValue) Type() string { + return "url" +} + +func (u *urlValue) String() string { + if u.value == nil { + return "" + } + return u.value.String() +} + +// URLVar defines a url.URL flag with specified name, default value, and usage string. +func (f *FlagSet) URLVar(p *url.URL, name string, value url.URL, usage string) { + f.VarP(newURLValue(&value, p), name, "", usage) +} + +// URLVarP is like URLVar, but accepts a shorthand letter. +func (f *FlagSet) URLVarP(p *url.URL, name, shorthand string, value url.URL, usage string) { + f.VarP(newURLValue(&value, p), name, shorthand, usage) +} + +// URL defines a url.URL flag with specified name, default value, and usage string. +func (f *FlagSet) URL(name string, value url.URL, usage string) *url.URL { + p := new(url.URL) + f.URLVarP(p, name, "", value, usage) + return p +} + +// URLP is like URL, but accepts a shorthand letter. +func (f *FlagSet) URLP(name, shorthand string, value url.URL, usage string) *url.URL { + p := new(url.URL) + f.URLVarP(p, name, shorthand, value, usage) + return p +} + +// URLVar defines a url.URL flag with specified name, default value, and usage string. +func URLVar(p *url.URL, name string, value url.URL, usage string) { + CommandLine.VarP(newURLValue(&value, p), name, "", usage) +} + +// URLVarP is like URLVar, but accepts a shorthand letter. +func URLVarP(p *url.URL, name, shorthand string, value url.URL, usage string) { + CommandLine.VarP(newURLValue(&value, p), name, shorthand, usage) +} + +// URL defines a url.URL flag with specified name, default value, and usage string. +func URL(name string, value url.URL, usage string) *url.URL { + p := new(url.URL) + CommandLine.URLVarP(p, name, "", value, usage) + return p +} + +// URLP is like URL, but accepts a shorthand letter. +func URLP(name, shorthand string, value url.URL, usage string) *url.URL { + p := new(url.URL) + CommandLine.URLVarP(p, name, shorthand, value, usage) + return p +} diff --git a/url_test.go b/url_test.go new file mode 100644 index 00000000..ece74596 --- /dev/null +++ b/url_test.go @@ -0,0 +1,62 @@ +package pflag + +import ( + "net/url" + "testing" +) + +func TestURL(t *testing.T) { + fs := NewFlagSet("test", ContinueOnError) + u := fs.URL("url", url.URL{Scheme: "https", Host: "example.com"}, "test url flag") + args := []string{"--url", "https://go.dev/pkg/net/url/"} + if err := fs.Parse(args); err != nil { + t.Fatal(err) + } + if u.String() != "https://go.dev/pkg/net/url/" { + t.Errorf("expected https://go.dev/pkg/net/url/, got %s", u.String()) + } +} + +func TestURLDefault(t *testing.T) { + fs := NewFlagSet("test", ContinueOnError) + u := fs.URL("url", url.URL{Scheme: "https", Host: "example.com"}, "test url flag") + if err := fs.Parse([]string{}); err != nil { + t.Fatal(err) + } + if u.String() != "https://example.com" { + t.Errorf("expected https://example.com, got %s", u.String()) + } +} + +func TestURLInvalid(t *testing.T) { + fs := NewFlagSet("test", ContinueOnError) + fs.URL("url", url.URL{}, "test url flag") + args := []string{"--url", "://invalid"} + if err := fs.Parse(args); err == nil { + t.Error("expected error for invalid URL, got nil") + } +} + +func TestURLP(t *testing.T) { + fs := NewFlagSet("test", ContinueOnError) + u := fs.URLP("url", "u", url.URL{}, "test url flag") + args := []string{"-u", "https://example.com/path"} + if err := fs.Parse(args); err != nil { + t.Fatal(err) + } + if u.String() != "https://example.com/path" { + t.Errorf("expected https://example.com/path, got %s", u.String()) + } +} + +func TestURLChanged(t *testing.T) { + fs := NewFlagSet("test", ContinueOnError) + fs.URL("url", url.URL{}, "test url flag") + args := []string{"--url", "https://changed.com"} + if err := fs.Parse(args); err != nil { + t.Fatal(err) + } + if !fs.Lookup("url").Changed { + t.Error("expected Changed to be true") + } +}