aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2023-12-05 01:32:52 +0100
committerThomas Voss <mail@thomasvoss.com> 2023-12-05 01:32:52 +0100
commit264780bb60dda33e8d06c48be5f1991212d62a9a (patch)
tree684d61e3e7aaddf73ce4e7c6fc731f72a23a7fac
parent799bb3be1d099ce6979cd6baa8b84acc507130bd (diff)
Replace ‘optind’ with ‘rest’ in Get() and GetLong() returnsHEADv2.0.0master
-rw-r--r--README.md27
-rw-r--r--v2/err.go31
-rw-r--r--v2/go.mod3
-rw-r--r--v2/opts.go234
-rw-r--r--v2/opts_test.go366
5 files changed, 651 insertions, 10 deletions
diff --git a/README.md b/README.md
index b15aaf4..34e26d9 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,12 @@
+## Update 6th December, 2023
+
+The v2 of this library has been released, and you should probably use
+that instead:
+
+```sh
+$ go get -u git.sr.ht/~mango/opts/v2
+```
+
# Opts
Opts is a simple Go library implementing unicode-aware getopt(3)- and
@@ -21,7 +30,7 @@ import (
"fmt"
"os"
- "git.sr.ht/~mango/opts"
+ "git.sr.ht/~mango/opts/v2"
)
func usage() {
@@ -30,7 +39,7 @@ func usage() {
}
func main() {
- flags, optind, err := opts.Get(os.Args, "a:ßλ")
+ flags, rest, err := opts.Get(os.Args, "a:ßλ")
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], err)
usage()
@@ -47,8 +56,7 @@ func main() {
}
}
- // The remaining arguments
- rest := os.Args[optind:]
+ fmt.Println("The remaining arguments are:", rest)
}
```
@@ -65,19 +73,18 @@ import (
"git.sr.ht/~mango/opts"
)
-const noShortFlag = -1
-
func usage() {
fmt.Fprintf(os.Stderr, "Usage: %s [-ßλ] [-a arg] [--no-short]\n", os.Args[0])
os.Exit(1)
}
func main() {
- flags, optind, err := opts.GetLong(os.Args, []opts.LongOpt{
+ // The fourth long-option has no short-option equivalent
+ flags, rest, err := opts.GetLong(os.Args, []opts.LongOpt{
{Short: 'a', Long: "add", Arg: opts.Required},
{Short: 'ß', Long: "sheiße", Arg: opts.None},
{Short: 'λ', Long: "λεωνίδας", Arg: opts.None},
- {Short: noShortFlag, Long: "no-short", Arg: opts.None},
+ {Short: -1, Long: "no-short", Arg: opts.None},
})
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], err)
@@ -92,12 +99,12 @@ func main() {
fmt.Println("-ß or --sheiße given")
case 'λ':
fmt.Println("-λ or --λεωνίδας given")
- case noShortFlag:
+ case -1:
fmt.Println("--no-short given")
}
}
// The remaining arguments
- rest := os.Args[optind:]
+ fmt.Println("The remaining arguments are:", rest)
}
```
diff --git a/v2/err.go b/v2/err.go
new file mode 100644
index 0000000..23692fa
--- /dev/null
+++ b/v2/err.go
@@ -0,0 +1,31 @@
+package opts
+
+import "fmt"
+
+// A BadOptionError describes an option that the user attempted to pass
+// which the developer did not register.
+type BadOptionError struct {
+ r rune
+ s string
+}
+
+func (e BadOptionError) Error() string {
+ if e.r != 0 {
+ return fmt.Sprintf("unknown option ‘-%c’", e.r)
+ }
+ return fmt.Sprintf("unknown option ‘--%s’", e.s)
+}
+
+// A NoArgumentError describes an option that the user attempted to pass
+// without an argument, which required an argument.
+type NoArgumentError struct {
+ r rune
+ s string
+}
+
+func (e NoArgumentError) Error() string {
+ if e.r != 0 {
+ return fmt.Sprintf("expected argument for option ‘-%c’", e.r)
+ }
+ return fmt.Sprintf("expected argument for option ‘--%s’", e.s)
+}
diff --git a/v2/go.mod b/v2/go.mod
new file mode 100644
index 0000000..f12c3e9
--- /dev/null
+++ b/v2/go.mod
@@ -0,0 +1,3 @@
+module git.sr.ht/~mango/opts/v2
+
+go 1.21.4
diff --git a/v2/opts.go b/v2/opts.go
new file mode 100644
index 0000000..314acd8
--- /dev/null
+++ b/v2/opts.go
@@ -0,0 +1,234 @@
+// Package opts implements unicode-aware getopt(3)- and getopt_long(3)
+// flag parsing.
+//
+// The opts package aims to provide as simple an API as possible. If
+// your usecase requires more advanced argument-parsing or a more robust
+// API, this may not be the ideal package for you.
+//
+// While the opts package aims to closely follow the POSIX getopt(3) and
+// GNU getopt_long(3) C functions, there are some notable differences.
+// This package properly supports unicode flags, but also does not
+// support a leading ‘:’ in the [Get] function’s option string; all
+// user-facing I/O is delegrated to the caller.
+package opts
+
+import (
+ "slices"
+ "strings"
+)
+
+// ArgMode represents whether or not a long-option takes an argument.
+type ArgMode int
+
+// These tokens can be used to specify whether or not a long-option takes
+// an argument.
+const (
+ None ArgMode = iota // long opt takes no argument
+ Required // long opt takes an argument
+ Optional // long opt optionally takes an argument
+)
+
+// Flag represents a parsed command-line flag. Key corresponds to the
+// rune that was passed on the command-line, and Value corresponds to the
+// flags argument if one was provided. In the case of long-options Key
+// will map to the corresponding short-code, even if a long-option was
+// used.
+type Flag struct {
+ Key rune // the flag that was passed
+ Value string // the flags argument
+}
+
+// LongOpt represents a long-option to attempt to parse. All long
+// options have a short-hand form represented by Short and a long-form
+// represented by Long. Arg is used to represent whether or not the
+// long-option takes an argument.
+//
+// In the case that you want to parse a long-option which doesn’t have a
+// short-hand form, you can set Short to a negative integer.
+type LongOpt struct {
+ Short rune
+ Long string
+ Arg ArgMode
+}
+
+// Get parses the command-line arguments in args according to optstr.
+// Unlike POSIX-getopt(3), a leading ‘:’ in optstr is not supported and
+// will be ignored and no I/O is ever performed.
+//
+// Get will look for the flags listed in optstr (i.e., it will look for
+// ‘-a’, ‘-ß’, and ‘λ’ given optstr == "aßλ"). The optstr need not be
+// sorted in any particular order. If an option takes a required
+// argument, it can be suffixed by a colon. If an option takes an
+// optional argument, it can be suffixed by two colons. As an example,
+// optstr == "a::ßλ:" will search for ‘-a’ with an optional argument,
+// ‘-ß’ with no argument, and ‘-λ’ with a required argument.
+//
+// A successful parse returns the flags in the flags slice and a slice of
+// the remaining non-option arguments in rest. In the case of failure,
+// err will be one of [BadOptionError] or [NoArgumentError].
+func Get(args []string, optstr string) (flags []Flag, rest []string, err error) {
+ if len(args) == 0 {
+ return
+ }
+
+ optrs := []rune(optstr)
+ var i int
+ for i = 1; i < len(args); i++ {
+ arg := args[i]
+ if len(arg) == 0 || arg == "-" || arg[0] != '-' {
+ break
+ } else if arg == "--" {
+ i++
+ break
+ }
+
+ rs := []rune(arg[1:])
+ for j, r := range rs {
+ k := slices.Index(optrs, r)
+ if k == -1 {
+ return nil, nil, BadOptionError{r: r}
+ }
+
+ var s string
+ switch am := colonsToArgMode(optrs[k+1:]); {
+ case am != None && j < len(rs)-1:
+ s = string(rs[j+1:])
+ case am == Required:
+ i++
+ if i >= len(args) {
+ return nil, nil, NoArgumentError{r: r}
+ }
+ s = args[i]
+ default:
+ flags = append(flags, Flag{Key: r})
+ continue
+ }
+
+ flags = append(flags, Flag{r, s})
+ break
+ }
+ }
+
+ return flags, args[i:], nil
+}
+
+// GetLong parses the command-line arguments in args according to opts.
+//
+// This function is identical to [Get] except it parses according to a
+// [LongOpt] slice instead of an opt-string, and it parses long-options.
+// When parsing, GetLong will also accept incomplete long-options if they
+// are unambiguous. For example, given the following definition of opts:
+//
+// opts := []LongOpt{
+// {Short: 'a', Long: "add", Arg: None},
+// {Short: 'd', Long: "delete", Arg: None},
+// {Short: 'D', Long: "defer", Arg: None},
+// }
+//
+// The options ‘--a’ and ‘--ad’ will parse as ‘--add’. The option ‘--de’
+// will not parse however as it is ambiguous.
+func GetLong(args []string, opts []LongOpt) (flags []Flag, rest []string, err error) {
+ if len(args) == 0 {
+ return
+ }
+
+ var i int
+ for i = 1; i < len(args); i++ {
+ arg := args[i]
+ if len(arg) == 0 || arg == "-" || arg[0] != '-' {
+ break
+ } else if arg == "--" {
+ i++
+ break
+ }
+
+ if strings.HasPrefix(arg, "--") {
+ arg = arg[2:]
+
+ n := arg
+ j := strings.IndexByte(n, '=')
+ if j != -1 {
+ n = arg[:j]
+ }
+
+ var s string
+ o, ok := optStruct(opts, n)
+
+ switch {
+ case !ok:
+ return nil, nil, BadOptionError{s: n}
+ case o.Arg != None && j != -1:
+ s = arg[j+1:]
+ case o.Arg == Required:
+ i++
+ if i >= len(args) {
+ return nil, nil, NoArgumentError{s: n}
+ }
+ s = args[i]
+ }
+
+ flags = append(flags, Flag{Key: o.Short, Value: s})
+ } else {
+ rs := []rune(arg[1:])
+ for j, r := range rs {
+ var s string
+
+ switch am, ok := getModeRune(opts, r); {
+ case !ok:
+ return nil, nil, BadOptionError{r: r}
+ case am != None && j < len(rs)-1:
+ s = string(rs[j+1:])
+ case am == Required:
+ i++
+ if i >= len(args) {
+ return nil, nil, NoArgumentError{r: r}
+ }
+ s = args[i]
+ default:
+ flags = append(flags, Flag{Key: r})
+ continue
+ }
+
+ flags = append(flags, Flag{r, s})
+ break
+ }
+ }
+ }
+
+ return flags, args[i:], nil
+}
+
+func getModeRune(os []LongOpt, r rune) (ArgMode, bool) {
+ for _, o := range os {
+ if o.Short == r {
+ return o.Arg, true
+ }
+ }
+ return 0, false
+}
+
+func optStruct(os []LongOpt, s string) (LongOpt, bool) {
+ i := -1
+ for j, o := range os {
+ if strings.HasPrefix(o.Long, s) {
+ if i != -1 {
+ return LongOpt{}, false
+ }
+ i = j
+ }
+ }
+ if i == -1 {
+ return LongOpt{}, false
+ }
+ return os[i], true
+}
+
+func colonsToArgMode(rs []rune) ArgMode {
+ if len(rs) >= 2 && rs[0] == ':' && rs[1] == ':' {
+ return Optional
+ }
+ if len(rs) >= 1 && rs[0] == ':' {
+ return Required
+ }
+ return None
+}
diff --git a/v2/opts_test.go b/v2/opts_test.go
new file mode 100644
index 0000000..1e35910
--- /dev/null
+++ b/v2/opts_test.go
@@ -0,0 +1,366 @@
+package opts
+
+import (
+ "fmt"
+ "testing"
+)
+
+func die(t *testing.T, name string, want, got any) {
+ t.Fatalf("Expected %s to be ‘%s’ but got ‘%s’", name, want, got)
+}
+
+// SHORT OPTS
+
+func assertGet(t *testing.T, args []string, fw, rw int, ew error) []Flag {
+ flags, rest, err := Get(args, "abλc:dßĦ::")
+ if err != ew {
+ die(t, "err", ew, err)
+ }
+ if len(rest) != rw {
+ die(t, "rest", rw, rest)
+ }
+ if len(flags) != fw {
+ die(t, "flags", fw, flags)
+ }
+ return flags
+}
+
+func TestNoArg(t *testing.T) {
+ args := []string{}
+ assertGet(t, args, 0, 0, nil)
+}
+
+func TestNoFlag(t *testing.T) {
+ args := []string{"foo"}
+ assertGet(t, args, 0, 0, nil)
+}
+
+func TestCNoArg(t *testing.T) {
+ args := []string{"foo", "-c"}
+ assertGet(t, args, 0, 0, NoArgumentError{r: 'c'})
+}
+
+func TestCWithArg(t *testing.T) {
+ args := []string{"foo", "-c", "bar"}
+ flags := assertGet(t, args, 1, 0, nil)
+ if flags[0].Key != 'c' {
+ die(t, "flags[0].Key", 'c', flags[0].Key)
+ }
+ if flags[0].Value != "bar" {
+ die(t, "flags[0].Value", "bar", flags[0].Value)
+ }
+}
+
+func TestCWithArgNoSpace(t *testing.T) {
+ args := []string{"foo", "-cbar"}
+ flags := assertGet(t, args, 1, 0, nil)
+ if flags[0].Key != 'c' {
+ die(t, "flags[0].Key", 'c', flags[0].Key)
+ }
+ if flags[0].Value != "bar" {
+ die(t, "flags[0].Value", "bar", flags[0].Value)
+ }
+}
+
+func TestANoArg(t *testing.T) {
+ args := []string{"foo", "-a"}
+ flags := assertGet(t, args, 1, 0, nil)
+ if flags[0].Key != 'a' {
+ die(t, "flags[0].Key", 'a', flags[0].Key)
+ }
+ if flags[0].Value != "" {
+ die(t, "flags[0].Value", "", flags[0].Value)
+ }
+}
+
+func TestAWithArg(t *testing.T) {
+ args := []string{"foo", "-a", "bar"}
+ flags := assertGet(t, args, 1, 1, nil)
+ if flags[0].Key != 'a' {
+ die(t, "flags[0].Key", 'a', flags[0].Key)
+ }
+ if flags[0].Value != "" {
+ die(t, "flags[0].Value", "", flags[0].Value)
+ }
+}
+
+func TestAAndCWithArg(t *testing.T) {
+ args := []string{"foo", "-a", "-c", "bar"}
+ flags := assertGet(t, args, 2, 0, nil)
+ if flags[0].Key != 'a' {
+ die(t, "flags[0].Key", 'a', flags[0].Key)
+ }
+ if flags[0].Value != "" {
+ die(t, "flags[0].Value", "", flags[0].Value)
+ }
+ if flags[1].Key != 'c' {
+ die(t, "flags[0].Key", 'c', flags[1].Key)
+ }
+ if flags[1].Value != "bar" {
+ die(t, "flags[0].Value", "bar", flags[1].Value)
+ }
+}
+
+func TestACWithArg(t *testing.T) {
+ args := []string{"foo", "-ac", "bar"}
+ flags := assertGet(t, args, 2, 0, nil)
+ if flags[0].Key != 'a' {
+ die(t, "flags[0].Key", 'a', flags[0].Key)
+ }
+ if flags[0].Value != "" {
+ die(t, "flags[0].Value", "", flags[0].Value)
+ }
+ if flags[1].Key != 'c' {
+ die(t, "flags[0].Key", 'c', flags[1].Key)
+ }
+ if flags[1].Value != "bar" {
+ die(t, "flags[0].Value", "bar", flags[1].Value)
+ }
+}
+
+func TestCAWithArg(t *testing.T) {
+ args := []string{"foo", "-ca", "bar"}
+ flags := assertGet(t, args, 1, 1, nil)
+ if flags[0].Key != 'c' {
+ die(t, "flags[0].Key", 'c', flags[0].Key)
+ }
+ if flags[0].Value != "a" {
+ die(t, "flags[0].Value", "a", flags[0].Value)
+ }
+}
+
+func TestBAfterDashDash(t *testing.T) {
+ args := []string{"foo", "--", "-b"}
+ assertGet(t, args, 0, 1, nil)
+}
+
+func TestCWithArgAfterDashDash(t *testing.T) {
+ args := []string{"foo", "--", "-c", "bar", "baz"}
+ assertGet(t, args, 0, 3, nil)
+}
+
+func TestCWithArgThenDAfterDashDash(t *testing.T) {
+ args := []string{"foo", "-c", "bar", "baz", "--", "-d"}
+ flags := assertGet(t, args, 1, 3, nil)
+ if flags[0].Key != 'c' {
+ die(t, "flags[0].Key", 'c', flags[0].Key)
+ }
+ if flags[0].Value != "bar" {
+ die(t, "flags[0].Value", "bar", flags[0].Value)
+ }
+}
+
+func TestCWithArgThenDAfterEmpty(t *testing.T) {
+ args := []string{"foo", "-c", "bar", "baz", "", "-d"}
+ flags := assertGet(t, args, 1, 3, nil)
+ if flags[0].Key != 'c' {
+ die(t, "flags[0].Key", 'c', flags[0].Key)
+ }
+ if flags[0].Value != "bar" {
+ die(t, "flags[0].Value", "bar", flags[0].Value)
+ }
+}
+
+func TestBChainedThrice(t *testing.T) {
+ args := []string{"foo", "-bbb"}
+ flags := assertGet(t, args, 3, 0, nil)
+ for i := 0; i < 3; i++ {
+ s := fmt.Sprintf("flags[%d].", i)
+ if flags[i].Key != 'b' {
+ die(t, s+"Key", 'b', flags[i].Key)
+ }
+ if flags[i].Value != "" {
+ die(t, s+"Value", "", flags[i].Value)
+ }
+ }
+}
+
+func TestẞChainedTwice(t *testing.T) {
+ args := []string{"foo", "-ßß"}
+ flags := assertGet(t, args, 2, 0, nil)
+ for i := 0; i < 2; i++ {
+ s := fmt.Sprintf("flags[%d].", i)
+ if flags[i].Key != 'ß' {
+ die(t, s+"Key", 'ß', flags[i].Key)
+ }
+ if flags[i].Value != "" {
+ die(t, s+"Value", "", flags[i].Value)
+ }
+ }
+}
+
+func TestΛAsArgToC(t *testing.T) {
+ args := []string{"foo", "-c", "-λ"}
+ flags := assertGet(t, args, 1, 0, nil)
+ if flags[0].Key != 'c' {
+ die(t, "flags[0].Key", 'c', flags[0].Key)
+ }
+ if flags[0].Value != "-λ" {
+ die(t, "flags[0].Value", "-λ", flags[0].Value)
+ }
+}
+
+func TestInvalidFlag(t *testing.T) {
+ args := []string{"foo", "-X"}
+ assertGet(t, args, 0, 0, BadOptionError{r: 'X'})
+}
+
+func TestInvalidFlagWithArg(t *testing.T) {
+ args := []string{"foo", "-X", "bar"}
+ assertGet(t, args, 0, 0, BadOptionError{r: 'X'})
+}
+
+func TestAAfterArg(t *testing.T) {
+ args := []string{"foo", "bar", "-a"}
+ assertGet(t, args, 0, 2, nil)
+}
+
+func TestXAfterDash(t *testing.T) {
+ args := []string{"foo", "-", "-x"}
+ assertGet(t, args, 0, 2, nil)
+}
+
+func TestĦWithSpaceAndArg(t *testing.T) {
+ args := []string{"foo", "-Ħ", "bar"}
+ flags := assertGet(t, args, 1, 1, nil)
+ if flags[0].Key != 'Ħ' {
+ die(t, "flags[0].Key", 'Ħ', flags[0].Key)
+ }
+ if flags[0].Value != "" {
+ die(t, "flags[0].Value", "", flags[0].Value)
+ }
+}
+
+func TestĦWithArg(t *testing.T) {
+ args := []string{"foo", "-Ħbar"}
+ flags := assertGet(t, args, 1, 0, nil)
+ if flags[0].Key != 'Ħ' {
+ die(t, "flags[0].Key", 'Ħ', flags[0].Key)
+ }
+ if flags[0].Value != "bar" {
+ die(t, "flags[0].Value", "bar", flags[0].Value)
+ }
+}
+
+func TestΛĦWithArg(t *testing.T) {
+ args := []string{"foo", "-λĦbar"}
+ flags := assertGet(t, args, 2, 0, nil)
+ if flags[0].Key != 'λ' {
+ die(t, "flags[0].Key", 'λ', flags[0].Key)
+ }
+ if flags[0].Value != "" {
+ die(t, "flags[0].Value", "", flags[0].Value)
+ }
+ if flags[1].Key != 'Ħ' {
+ die(t, "flags[1].Key", 'Ħ', flags[1].Key)
+ }
+ if flags[1].Value != "bar" {
+ die(t, "flags[1].Value", "bar", flags[1].Value)
+ }
+}
+
+// LONG OPTS
+
+func assertGetLong(t *testing.T, args []string, fw, rw int, ew error) []Flag {
+ opts := []LongOpt{
+ {Short: 'a', Long: "add", Arg: None},
+ {Short: 'b', Long: "back", Arg: None},
+ {Short: 'λ', Long: "λεωνίδας", Arg: None},
+ {Short: 'c', Long: "change", Arg: Required},
+ {Short: 'C', Long: "count", Arg: None},
+ {Short: 'd', Long: "delete", Arg: None},
+ {Short: 'ß', Long: "scheiße", Arg: None},
+ {Short: 'Ħ', Long: "Ħaġrat", Arg: Optional},
+ }
+ flags, rest, err := GetLong(args, opts)
+ if err != ew {
+ die(t, "err", ew, err)
+ }
+ if len(rest) != rw {
+ die(t, "rest", rw, rest)
+ }
+ if len(flags) != fw {
+ die(t, "flags", fw, flags)
+ }
+ return flags
+}
+
+func TestNoArgL(t *testing.T) {
+ args := []string{}
+ assertGetLong(t, args, 0, 0, nil)
+}
+
+func TestNoFlagL(t *testing.T) {
+ args := []string{"foo"}
+ assertGetLong(t, args, 0, 0, nil)
+}
+
+func TestChangeNoArg(t *testing.T) {
+ args := []string{"foo", "--change"}
+ assertGetLong(t, args, 0, 0, NoArgumentError{s: "change"})
+}
+
+func TestChangeArgEqual(t *testing.T) {
+ args := []string{"foo", "--change=bar"}
+ flags := assertGetLong(t, args, 1, 0, nil)
+ if flags[0].Key != 'c' {
+ die(t, "flags[0].Key", 'c', flags[0].Key)
+ }
+ if flags[0].Value != "bar" {
+ die(t, "flags[0].Value", "bar", flags[0].Value)
+ }
+}
+
+func TestChangeArgSpace(t *testing.T) {
+ args := []string{"foo", "--change", "bar"}
+ flags := assertGetLong(t, args, 1, 0, nil)
+ if flags[0].Key != 'c' {
+ die(t, "flags[0].Key", 'c', flags[0].Key)
+ }
+ if flags[0].Value != "bar" {
+ die(t, "flags[0].Value", "bar", flags[0].Value)
+ }
+}
+
+func TestChangeArgSpaceShort(t *testing.T) {
+ args := []string{"foo", "--ch", "bar"}
+ flags := assertGetLong(t, args, 1, 0, nil)
+ if flags[0].Key != 'c' {
+ die(t, "flags[0].Key", 'c', flags[0].Key)
+ }
+ if flags[0].Value != "bar" {
+ die(t, "flags[0].Value", "bar", flags[0].Value)
+ }
+}
+
+func TestChangeArgSpaceShortFail(t *testing.T) {
+ args := []string{"foo", "--c", "bar"}
+ assertGetLong(t, args, 0, 0, BadOptionError{s: "c"})
+}
+
+func TestĦaġratNoArg(t *testing.T) {
+ args := []string{"foo", "--Ħ"}
+ assertGetLong(t, args, 1, 0, nil)
+}
+
+func TestĦaġratArgEqual(t *testing.T) {
+ args := []string{"foo", "--Ħ=bar"}
+ flags := assertGetLong(t, args, 1, 0, nil)
+ if flags[0].Key != 'Ħ' {
+ die(t, "flags[0].Key", 'Ħ', flags[0].Key)
+ }
+ if flags[0].Value != "bar" {
+ die(t, "flags[0].Value", "bar", flags[0].Value)
+ }
+}
+
+func TestĦaġratArgSpace(t *testing.T) {
+ args := []string{"foo", "--Ħ", "bar"}
+ flags := assertGetLong(t, args, 1, 1, nil)
+ if flags[0].Key != 'Ħ' {
+ die(t, "flags[0].Key", 'Ħ', flags[0].Key)
+ }
+ if flags[0].Value != "" {
+ die(t, "flags[0].Value", "", flags[0].Value)
+ }
+}