Skip to content

Commit

Permalink
feat: Introduce ErrYAMLMultidoc
Browse files Browse the repository at this point in the history
Return ErrYAMLMultidoc if the YAML source contains multiple documents.
  • Loading branch information
romshark committed Jun 23, 2024
1 parent 54842b4 commit c7fef5a
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ an error annotated with line and column in the YAML file if necessary.
- 🚫 Forbids assigning non-string values to Go types that implement
the [`encoding.TextUnmarshaler`](https://pkg.go.dev/encoding#TextUnmarshaler) interface.
- 🚫 Forbids empty array items ([see rationale](#why-are-empty-array-items-forbidden)).
- 🚫 Forbids multi-document files.
- Features:
- 🪄 If any type within your configuration struct implements the `Validate` interface,
then its validation method will be called using reflection
Expand Down
16 changes: 14 additions & 2 deletions yamagiconf.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ var (
ErrValidation = errors.New("validation")
ErrValidateTagViolation = errors.New("violates validation rule")

ErrYAMLMultidoc = errors.New("multi-document YAML files are not supported")
ErrYAMLEmptyFile = errors.New("empty file")
ErrYAMLMalformed = errors.New("malformed YAML")
ErrYAMLInlineNonAnon = errors.New("inline yaml on non-embedded field")
Expand Down Expand Up @@ -127,8 +128,19 @@ func Load[T any, S string | []byte](yamlSource S, config *T) error {
}

var rootNode yaml.Node
if err := newDecoderYAML(yamlSource).Decode(&rootNode); err != nil {
return fmt.Errorf("decoding yaml structure: %w", err)
{
dec := newDecoderYAML(yamlSource)
if err := dec.Decode(&rootNode); err != nil {
return fmt.Errorf("decoding yaml structure: %w", err)
}

// Check if multi-doc
var n yaml.Node
if err = dec.Decode(&n); err == nil {
return fmt.Errorf("at %d:%d: %w", n.Line, n.Column, ErrYAMLMultidoc)
} else if !errors.Is(err, io.EOF) {
return fmt.Errorf("%w: %w", ErrYAMLMultidoc, err)
}
}

configType := reflect.TypeOf(config).Elem()
Expand Down
34 changes: 34 additions & 0 deletions yamagiconf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1446,6 +1446,40 @@ func TestLoadErr(t *testing.T) {
require.NotZero(t, c)
})

t.Run("multidocument", func(t *testing.T) {
_, err := LoadSrc[TestConfig](`# Second doc contains different data.
---
foo: 1
---
foo: 2
`)
require.ErrorIs(t, err, yamagiconf.ErrYAMLMultidoc)
require.Equal(t, "at 4:1: "+yamagiconf.ErrYAMLMultidoc.Error(), err.Error())
})

t.Run("multidocument_second_doc_not_to_spec", func(t *testing.T) {
_, err := LoadSrc[TestConfig](`# Second doc can't be decoded to TestConfig.
---
foo: 1
---
bar: 2
`)
require.ErrorIs(t, err, yamagiconf.ErrYAMLMultidoc)
require.Equal(t, "at 4:1: "+yamagiconf.ErrYAMLMultidoc.Error(), err.Error())
})

t.Run("multidocument_error_in_second_file", func(t *testing.T) {
_, err := LoadSrc[TestConfig](`# Second doc contains a syntax error.
---
foo: 1
---
:
`)
require.ErrorIs(t, err, yamagiconf.ErrYAMLMultidoc)
require.Equal(t, yamagiconf.ErrYAMLMultidoc.Error()+
": yaml: line 4: did not find expected key", err.Error())
})

t.Run("unsupported_boolean_literal", func(t *testing.T) {
type TestConfig struct {
Boolean bool `yaml:"boolean"`
Expand Down

0 comments on commit c7fef5a

Please sign in to comment.