Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for strict errors #796

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions apic.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
//
//
// Copyright (c) 2011-2019 Canonical Ltd
// Copyright (c) 2006-2010 Kirill Simonov
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Expand Down
13 changes: 8 additions & 5 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,10 @@ func (p *parser) mapping() *Node {
// Decoder, unmarshals a node into a provided value.

type decoder struct {
doc *Node
aliases map[*Node]bool
terrors []string
doc *Node
aliases map[*Node]bool
terrors []string
strictErrors []string

stringMapType reflect.Type
generalMapType reflect.Type
Expand Down Expand Up @@ -361,6 +362,7 @@ func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) {
err := u.UnmarshalYAML(n)
if e, ok := err.(*TypeError); ok {
d.terrors = append(d.terrors, e.Errors...)
d.strictErrors = append(d.strictErrors, e.StrictErrors...)
return false
}
if err != nil {
Expand All @@ -377,12 +379,13 @@ func (d *decoder) callObsoleteUnmarshaler(n *Node, u obsoleteUnmarshaler) (good
if len(d.terrors) > terrlen {
issues := d.terrors[terrlen:]
d.terrors = d.terrors[:terrlen]
return &TypeError{issues}
return &TypeError{issues, nil}
}
return nil
})
if e, ok := err.(*TypeError); ok {
d.terrors = append(d.terrors, e.Errors...)
d.strictErrors = append(d.strictErrors, e.StrictErrors...)
return false
}
if err != nil {
Expand Down Expand Up @@ -908,7 +911,7 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
d.unmarshal(n.Content[i+1], value)
inlineMap.SetMapIndex(name, value)
} else if d.knownFields {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
d.strictErrors = append(d.strictErrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
}
}
return true
Expand Down
38 changes: 22 additions & 16 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ var unmarshalTests = []struct {
M{"a": 123456e1},
}, {
"a: 123456E1\n",
M{"a": 123456E1},
M{"a": 123456e1},
},
// yaml-test-suite 3GZX: Spec Example 7.1. Alias Nodes
{
Expand Down Expand Up @@ -802,7 +802,6 @@ var unmarshalTests = []struct {
"c": []interface{}{"d", "e"},
},
},

}

type M map[string]interface{}
Expand Down Expand Up @@ -950,14 +949,14 @@ var unmarshalErrorTests = []struct {
{"a: 1\nb: 2\nc 2\nd: 3\n", "^yaml: line 3: could not find expected ':'$"},
{
"a: &a [00,00,00,00,00,00,00,00,00]\n" +
"b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]\n" +
"c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]\n" +
"d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]\n" +
"e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]\n" +
"f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]\n" +
"g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]\n" +
"h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]\n" +
"i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]\n",
"b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]\n" +
"c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]\n" +
"d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]\n" +
"e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]\n" +
"f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]\n" +
"g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]\n" +
"h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]\n" +
"i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]\n",
"yaml: document contains excessive aliasing",
},
}
Expand Down Expand Up @@ -1111,8 +1110,8 @@ func (s *S) TestUnmarshalerWholeDocument(c *C) {
}

func (s *S) TestUnmarshalerTypeError(c *C) {
unmarshalerResult[2] = &yaml.TypeError{[]string{"foo"}}
unmarshalerResult[4] = &yaml.TypeError{[]string{"bar"}}
unmarshalerResult[2] = &yaml.TypeError{[]string{"foo"}, nil}
unmarshalerResult[4] = &yaml.TypeError{[]string{"bar"}, nil}
defer func() {
delete(unmarshalerResult, 2)
delete(unmarshalerResult, 4)
Expand Down Expand Up @@ -1142,8 +1141,8 @@ func (s *S) TestUnmarshalerTypeError(c *C) {
}

func (s *S) TestObsoleteUnmarshalerTypeError(c *C) {
unmarshalerResult[2] = &yaml.TypeError{[]string{"foo"}}
unmarshalerResult[4] = &yaml.TypeError{[]string{"bar"}}
unmarshalerResult[2] = &yaml.TypeError{[]string{"foo"}, nil}
unmarshalerResult[4] = &yaml.TypeError{[]string{"bar"}, nil}
defer func() {
delete(unmarshalerResult, 2)
delete(unmarshalerResult, 4)
Expand Down Expand Up @@ -1436,7 +1435,10 @@ func (s *S) TestMergeStruct(c *C) {
}
}

var unmarshalNullTests = []struct{ input string; pristine, expected func() interface{} }{{
var unmarshalNullTests = []struct {
input string
pristine, expected func() interface{}
}{{
"null",
func() interface{} { var v interface{}; v = "v"; return &v },
func() interface{} { var v interface{}; v = nil; return &v },
Expand Down Expand Up @@ -1487,7 +1489,7 @@ func (s *S) TestUnmarshalNull(c *C) {
func (s *S) TestUnmarshalPreservesData(c *C) {
var v struct {
A, B int
C int `yaml:"-"`
C int `yaml:"-"`
}
v.A = 42
v.C = 88
Expand Down Expand Up @@ -1603,6 +1605,10 @@ func (s *S) TestUnmarshalKnownFields(c *C) {
dec.KnownFields(item.known)
err := dec.Decode(value.Interface())
c.Assert(err, ErrorMatches, item.error)
if !item.unique {
// If a strict error occurs, the decoding should still be successful
c.Assert(value.Elem().Interface(), DeepEquals, item.value)
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion emitterc.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool
emitter.indent += 2
} else {
// Everything else aligns to the chosen indentation.
emitter.indent = emitter.best_indent*((emitter.indent+emitter.best_indent)/emitter.best_indent)
emitter.indent = emitter.best_indent * ((emitter.indent + emitter.best_indent) / emitter.best_indent)
}
}
return true
Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module "gopkg.in/yaml.v3"
module gopkg.in/yaml.v3

require (
"gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405
)
go 1.17

require gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
36 changes: 18 additions & 18 deletions node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -688,17 +688,17 @@ var nodeTests = []struct {
Line: 3,
Column: 4,
}, {
Kind: yaml.ScalarNode,
Tag: "!!str",
Value: "c",
Kind: yaml.ScalarNode,
Tag: "!!str",
Value: "c",
LineComment: "# IC",
Line: 5,
Column: 1,
Line: 5,
Column: 1,
}, {
Kind: yaml.SequenceNode,
Tag: "!!seq",
Line: 6,
Column: 3,
Kind: yaml.SequenceNode,
Tag: "!!seq",
Line: 6,
Column: 3,
Content: []*yaml.Node{{
Kind: yaml.ScalarNode,
Tag: "!!str",
Expand All @@ -707,17 +707,17 @@ var nodeTests = []struct {
Column: 5,
}},
}, {
Kind: yaml.ScalarNode,
Tag: "!!str",
Value: "d",
Kind: yaml.ScalarNode,
Tag: "!!str",
Value: "d",
LineComment: "# ID",
Line: 7,
Column: 1,
Line: 7,
Column: 1,
}, {
Kind: yaml.MappingNode,
Tag: "!!map",
Line: 8,
Column: 3,
Kind: yaml.MappingNode,
Tag: "!!map",
Line: 8,
Column: 3,
Content: []*yaml.Node{{
Kind: yaml.ScalarNode,
Tag: "!!str",
Expand Down
8 changes: 4 additions & 4 deletions readerc.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
//
//
// Copyright (c) 2011-2019 Canonical Ltd
// Copyright (c) 2006-2010 Kirill Simonov
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Expand Down
8 changes: 4 additions & 4 deletions scannerc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2847,7 +2847,7 @@ func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t
continue
}
if parser.buffer[parser.buffer_pos+peek] == '#' {
seen := parser.mark.index+peek
seen := parser.mark.index + peek
for {
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
return false
Expand Down Expand Up @@ -2876,7 +2876,7 @@ func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t
parser.comments = append(parser.comments, yaml_comment_t{
token_mark: token_mark,
start_mark: start_mark,
line: text,
line: text,
})
}
return true
Expand Down Expand Up @@ -2910,7 +2910,7 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo
// the foot is the line below it.
var foot_line = -1
if scan_mark.line > 0 {
foot_line = parser.mark.line-parser.newlines+1
foot_line = parser.mark.line - parser.newlines + 1
if parser.newlines == 0 && parser.mark.column > 1 {
foot_line++
}
Expand Down Expand Up @@ -2996,7 +2996,7 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo
recent_empty = false

// Consume until after the consumed comment line.
seen := parser.mark.index+peek
seen := parser.mark.index + peek
for {
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
return false
Expand Down
8 changes: 4 additions & 4 deletions writerc.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
//
//
// Copyright (c) 2011-2019 Canonical Ltd
// Copyright (c) 2006-2010 Kirill Simonov
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Expand Down
22 changes: 11 additions & 11 deletions yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ func (dec *Decoder) Decode(v interface{}) (err error) {
out = out.Elem()
}
d.unmarshal(node, out)
if len(d.terrors) > 0 {
return &TypeError{d.terrors}
if len(d.terrors) > 0 || len(d.strictErrors) > 0 {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if this is now common enough to have its own helper func attached to the decoder, something like if err := d.checkErr(); err != nil { return err } ... it would add some overhead due to one extra fn call so not sure if it's worth it.

return &TypeError{d.terrors, d.strictErrors}
}
return nil
}
Expand All @@ -147,8 +147,8 @@ func (n *Node) Decode(v interface{}) (err error) {
out = out.Elem()
}
d.unmarshal(n, out)
if len(d.terrors) > 0 {
return &TypeError{d.terrors}
if len(d.terrors) > 0 || len(d.strictErrors) > 0 {
return &TypeError{d.terrors, d.strictErrors}
}
return nil
}
Expand All @@ -166,8 +166,8 @@ func unmarshal(in []byte, out interface{}, strict bool) (err error) {
}
d.unmarshal(node, v)
}
if len(d.terrors) > 0 {
return &TypeError{d.terrors}
if len(d.terrors) > 0 || len(d.strictErrors) > 0 {
return &TypeError{d.terrors, d.strictErrors}
}
return nil
}
Expand Down Expand Up @@ -313,11 +313,12 @@ func failf(format string, args ...interface{}) {
// types. When this error is returned, the value is still
// unmarshaled partially.
type TypeError struct {
Errors []string
Errors []string
StrictErrors []string
}

func (e *TypeError) Error() string {
return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n "))
return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(append(e.Errors, e.StrictErrors...), "\n "))
}

type Kind uint32
Expand Down Expand Up @@ -363,7 +364,7 @@ const (
// Address yaml.Node
// }
// err := yaml.Unmarshal(data, &person)
//
//
// Or by itself:
//
// var person Node
Expand All @@ -373,7 +374,7 @@ type Node struct {
// Kind defines whether the node is a document, a mapping, a sequence,
// a scalar value, or an alias to another node. The specific data type of
// scalar nodes may be obtained via the ShortTag and LongTag methods.
Kind Kind
Kind Kind

// Style allows customizing the apperance of the node in the tree.
Style Style
Expand Down Expand Up @@ -421,7 +422,6 @@ func (n *Node) IsZero() bool {
n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0
}


// LongTag returns the long form of the tag that indicates the data type for
// the node. If the Tag field isn't explicitly defined, one will be computed
// based on the node properties.
Expand Down
1 change: 0 additions & 1 deletion yamlh.go
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,6 @@ type yaml_parser_t struct {
}

type yaml_comment_t struct {

scan_mark yaml_mark_t // Position where scanning for comments started
token_mark yaml_mark_t // Position after which tokens will be associated with this comment
start_mark yaml_mark_t // Position of '#' comment mark
Expand Down
Loading