this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

internal/encoding/yaml: reject trailing input in Unmarshal

To be consistent with encoding/json.Unmarshal, and so that both
pkg/encoding/json and pkg/encoding/yaml's Unmarshal APIs reject it.

Signed-off-by: Daniel Martí <mvdan@mvdan.cc>
Change-Id: Iee7dabf35d578d461c7aecd5ff6282774a51d017
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1193242
Reviewed-by: Roger Peppe <rogpeppe@gmail.com>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>

+44 -14
+11 -3
internal/encoding/yaml/decode.go
··· 158 158 // Unmarshal parses a single YAML value to a CUE expression. 159 159 func Unmarshal(filename string, data []byte) (ast.Expr, error) { 160 160 d := NewDecoder(filename, data) 161 - x, err := d.Decode() 161 + n, err := d.Decode() 162 162 if err != nil { 163 163 if err == io.EOF { 164 164 return nil, nil // empty input 165 165 } 166 166 return nil, err 167 167 } 168 - // TODO(mvdan): fail if there are more documents or garbage in the input 169 - return x, nil 168 + // TODO(mvdan): decoding the entire next value is unnecessary; 169 + // consider either a "More" or "Done" method to tell if we are at EOF, 170 + // or splitting the Decode method into two variants. 171 + // This should use proper error values with positions as well. 172 + if n2, err := d.Decode(); err == nil { 173 + return nil, fmt.Errorf("%s: expected a single YAML document", n2.Pos()) 174 + } else if err != io.EOF { 175 + return nil, fmt.Errorf("expected a single YAML document: %v", err) 176 + } 177 + return n, nil 170 178 } 171 179 172 180 func (d *decoder) extract(yn *yaml.Node) (ast.Expr, error) {
+27 -9
internal/encoding/yaml/decode_test.go
··· 26 26 "strings" 27 27 "testing" 28 28 29 + "github.com/go-quicktest/qt" 30 + "github.com/google/go-cmp/cmp" 31 + 29 32 "cuelang.org/go/cue/ast" 30 33 "cuelang.org/go/cue/format" 31 34 "cuelang.org/go/internal" 32 35 "cuelang.org/go/internal/cueexperiment" 33 36 "cuelang.org/go/internal/cuetest" 34 37 "cuelang.org/go/internal/encoding/yaml" 35 - "github.com/google/go-cmp/cmp" 36 38 ) 37 39 38 40 // These tests are only for the new YAML decoder. ··· 764 766 "Override anchor": "Bar" 765 767 "Reuse anchor": "Bar"`, 766 768 }, 767 - // Single document with garbage following it. 768 - // TODO(mvdan): This should work for a single Decoder.Decode call, 769 - // but it should be an error with Unmarshal. 770 - { 771 - "---\nhello\n...\n}not yaml", 772 - `"hello"`, 773 - }, 774 769 } 775 770 776 771 type M map[interface{}]interface{} ··· 785 780 786 781 func newDecoder(t *testing.T, data string) yaml.Decoder { 787 782 t.Helper() 788 - t.Logf("input yaml:\n%s", data) 783 + t.Logf(" yaml:\n%s", data) 789 784 return yaml.NewDecoder("test.yaml", []byte(data)) 790 785 } 791 786 ··· 978 973 }) 979 974 } 980 975 } 976 + 977 + func TestTrailingInput(t *testing.T) { 978 + for _, input := range []string{ 979 + "---\nfirst\n...\n}invalid yaml", 980 + "---\nfirst\n---\nsecond\n", 981 + } { 982 + t.Run("", func(t *testing.T) { 983 + // Unmarshal should fail as it expects one value. 984 + wantErr := ".*expected a single YAML document.*" 985 + _, err := callUnmarshal(t, input) 986 + qt.Assert(t, qt.ErrorMatches(err, wantErr)) 987 + 988 + // A single Decode call should succeed, no matter whether there is any valid or invalid trailing input. 989 + wantFirst := `"first"` 990 + dec := newDecoder(t, input) 991 + expr, err := dec.Decode() 992 + qt.Assert(t, qt.IsNil(err)) 993 + gotFirst := cueStr(expr) 994 + qt.Assert(t, qt.Equals(gotFirst, wantFirst)) 995 + }) 996 + } 997 + 998 + }
+6 -2
pkg/encoding/yaml/testdata/gen.txtar
··· 45 45 ./in.cue:6:5 46 46 ./in.cue:6:49 47 47 yaml.ValidatePartial:3:4 48 + unmarshalTrailingInput.valid: error in call to encoding/yaml.Unmarshal: 3:1: expected a single YAML document: 49 + ./in.cue:27:11 50 + unmarshalTrailingInput.invalid: error in call to encoding/yaml.Unmarshal: expected a single YAML document: :2: did not find expected node content: 51 + ./in.cue:28:11 48 52 49 53 Result: 50 54 t1: _|_ // t1: error in call to encoding/yaml.Validate: a: invalid value 4 (out of bound <3) ··· 81 85 null2: [1, null, 2] 82 86 } 83 87 unmarshalTrailingInput: { 84 - valid: 1 85 - invalid: 1 88 + valid: _|_ // unmarshalTrailingInput.valid: error in call to encoding/yaml.Unmarshal: 3:1: expected a single YAML document 89 + invalid: _|_ // unmarshalTrailingInput.invalid: error in call to encoding/yaml.Unmarshal: expected a single YAML document: :2: did not find expected node content 86 90 }