From b9e863058fc9df166b8a4a8f6f45ab0926eb08bb Mon Sep 17 00:00:00 2001 From: Jacob Hochstetler Date: Mon, 31 Jul 2023 11:05:31 -0500 Subject: [PATCH] Added BeforeValidate hook and tests Updated README.md --- README.md | 6 ++---- hooks.go | 6 ++++++ kong.go | 3 +++ kong_test.go | 16 +++++++++++----- resolver_test.go | 4 ++-- 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 35b07c6..1089e46 100644 --- a/README.md +++ b/README.md @@ -303,10 +303,8 @@ func main() { ## Hooks: BeforeReset(), BeforeResolve(), BeforeApply(), AfterApply() and the Bind() option -If a node in the grammar has a `BeforeReset(...)`, `BeforeResolve -(...)`, `BeforeApply(...) error` and/or `AfterApply(...) error` method, those -methods will be called before values are reset, before validation/assignment, -and after validation/assignment, respectively. +If a node in the grammar has a `BeforeReset(...)`, `BeforeResolve(...)`, `BeforeApply(...) error`, `AfterApply(...) error`, and/or `BeforeValidate(...) error` method, +those methods will be called before values are reset, before validation/assignment, and after validation/assignment, respectively. The `--help` flag is implemented with a `BeforeReset` hook. diff --git a/hooks.go b/hooks.go index d166b08..990047f 100644 --- a/hooks.go +++ b/hooks.go @@ -12,6 +12,12 @@ type BeforeApply interface { BeforeApply(args ...interface{}) error } +// BeforeValidate is a documentation-only interface describing hooks that run before validation is applied. +type BeforeValidate interface { + // This is not the correct signature - see README for details. + BeforeValidate(args ...interface{}) error +} + // AfterApply is a documentation-only interface describing hooks that run after values are set. type AfterApply interface { // This is not the correct signature - see README for details. diff --git a/kong.go b/kong.go index 255633f..38da282 100644 --- a/kong.go +++ b/kong.go @@ -302,6 +302,9 @@ func (k *Kong) Parse(args []string) (ctx *Context, err error) { if _, err = ctx.Apply(); err != nil { return nil, &ParseError{error: err, Context: ctx} } + if err = k.applyHook(ctx, "BeforeValidate"); err != nil { + return nil, &ParseError{error: err, Context: ctx} + } if err = ctx.Validate(); err != nil { return nil, &ParseError{error: err, Context: ctx} } diff --git a/kong_test.go b/kong_test.go index 1ef424e..926ad3e 100644 --- a/kong_test.go +++ b/kong_test.go @@ -455,6 +455,12 @@ func (h *hookValue) BeforeApply(ctx *hookContext) error { return nil } +func (h *hookValue) BeforeValidate(ctx *hookContext) error { + *h = hookValue(strings.ToUpper(string(*h))) + ctx.values = append(ctx.values, "beforeValidate:"+string(*h)) + return nil +} + func (h *hookValue) AfterApply(ctx *hookContext) error { ctx.values = append(ctx.values, "after:"+string(*h)) return nil @@ -482,9 +488,9 @@ func TestHooks(t *testing.T) { values hookContext }{ {"Command", "one", hookContext{true, nil}}, - {"Arg", "one two", hookContext{true, []string{"before:", "after:two"}}}, - {"Flag", "one --three=THREE", hookContext{true, []string{"before:", "after:THREE"}}}, - {"ArgAndFlag", "one two --three=THREE", hookContext{true, []string{"before:", "before:", "after:two", "after:THREE"}}}, + {"Arg", "one two", hookContext{true, []string{"before:", "beforeValidate:TWO", "after:TWO"}}}, + {"Flag", "one --three=THREE", hookContext{true, []string{"before:", "beforeValidate:THREE", "after:THREE"}}}, + {"ArgAndFlag", "one two --three=THREE", hookContext{true, []string{"before:", "before:", "beforeValidate:TWO", "beforeValidate:THREE", "after:TWO", "after:THREE"}}}, } var cli struct { @@ -776,8 +782,8 @@ func TestHooksCalledForDefault(t *testing.T) { ctx := &hookContext{} _, err := mustNew(t, &cli, kong.Bind(ctx)).Parse(nil) assert.NoError(t, err) - assert.Equal(t, "default", string(cli.Flag)) - assert.Equal(t, []string{"before:default", "after:default"}, ctx.values) + assert.Equal(t, "DEFAULT", string(cli.Flag)) + assert.Equal(t, []string{"before:default", "beforeValidate:DEFAULT", "after:DEFAULT"}, ctx.values) } func TestEnum(t *testing.T) { diff --git a/resolver_test.go b/resolver_test.go index c1684b6..6a29863 100644 --- a/resolver_test.go +++ b/resolver_test.go @@ -368,8 +368,8 @@ func TestResolverTriggersHooks(t *testing.T) { _, err := mustNew(t, &cli, kong.Bind(ctx), kong.Resolvers(first)).Parse(nil) assert.NoError(t, err) - assert.Equal(t, "one", string(cli.Flag)) - assert.Equal(t, []string{"before:", "after:one"}, ctx.values) + assert.Equal(t, "ONE", string(cli.Flag)) + assert.Equal(t, []string{"before:", "beforeValidate:ONE", "after:ONE"}, ctx.values) } type validatingResolver struct {