diff --git a/util/templates/template.go b/util/templates/template.go index 247b07a4a..a667b26ff 100644 --- a/util/templates/template.go +++ b/util/templates/template.go @@ -387,7 +387,7 @@ func (t *Template) RenderResult(renderMode int, other map[string]any) ([]byte, m } // validate required fields from yaml - if s == "" && p.IsRequired() && (renderMode == RenderModeUnitTest || renderMode == RenderModeInstance && !testing.Testing()) { + if p.IsRequired() && p.IsZero(s) && (renderMode == RenderModeUnitTest || renderMode == RenderModeInstance && !testing.Testing()) { // validate required per usage if len(p.Usages) == 0 || slices.Contains(p.Usages, usage) { return nil, nil, fmt.Errorf("missing required `%s`", p.Name) diff --git a/util/templates/template_test.go b/util/templates/template_test.go index 6eb7967d6..8c3172280 100644 --- a/util/templates/template_test.go +++ b/util/templates/template_test.go @@ -32,7 +32,7 @@ func TestPresets(t *testing.T) { }, tmpl.Params) } -func TestRequired(t *testing.T) { +func TestRequiredString(t *testing.T) { tmpl := &Template{ Params: []Param{ { @@ -63,6 +63,43 @@ func TestRequired(t *testing.T) { assert.NoError(t, err, "docs: required present but nil") } +func TestRequiredNumber(t *testing.T) { + tmpl := &Template{ + Params: []Param{ + { + Name: "param", + Type: TypeInt, + Required: true, + }, + }, + } + + _, _, err := tmpl.RenderResult(RenderModeUnitTest, map[string]any{ + "Param": "1", + }) + assert.NoError(t, err, "test: required present") + + _, _, err = tmpl.RenderResult(RenderModeUnitTest, map[string]any{ + "Param": "", + }) + assert.Error(t, err, "test: required present but empty") + + _, _, err = tmpl.RenderResult(RenderModeUnitTest, map[string]any{ + "Param": "0", + }) + assert.Error(t, err, "test: required present but zero value") + + _, _, err = tmpl.RenderResult(RenderModeUnitTest, map[string]any{ + "Param": nil, + }) + assert.Error(t, err, "test: required present but nil") + + _, _, err = tmpl.RenderResult(RenderModeDocs, map[string]any{ + "Param": nil, + }) + assert.NoError(t, err, "docs: required present but nil") +} + func TestRequiredDeprecated(t *testing.T) { tmpl := &Template{ Params: []Param{ diff --git a/util/templates/types.go b/util/templates/types.go index ebc259262..eff41e91e 100644 --- a/util/templates/types.go +++ b/util/templates/types.go @@ -11,6 +11,7 @@ import ( "dario.cat/mergo" "github.com/gosimple/slug" + "github.com/spf13/cast" ) const ( @@ -269,6 +270,19 @@ func (p *Param) IsDeprecated() bool { return p.Deprecated } +func (p *Param) IsZero(s string) bool { + switch p.Type { + case TypeInt: + return cast.ToInt64(s) == 0 + case TypeFloat: + return cast.ToFloat64(s) == 0 + case TypeDuration: + return cast.ToDuration(s) == 0 + default: + return len(s) == 0 + } +} + // yamlQuote quotes strings for yaml if they would otherwise by modified by the unmarshaler func (p *Param) yamlQuote(value string) string { if p.Type != TypeString {