nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: goccy/go-yaml
Pull request #213 (2021-03-04 20:03:12)

Add error for unterminated flow mapping node
Hello @goccy, I found your yaml parser as an alternative to go-yaml, and it seems to handle several cases that go-yaml/yaml doesn't: not just anchors and aliases, but also repeated flow documents (`{ ... }{ ... }`) and tabs in flow documents, which I think would allow us to replace our use of `encoding/json` with it.

I created this pull request to add one piece of error handling, for unterminated flow documents—please let me know what you think, or if there's more I can or should do to improve it. Also please let me know if other pull requests would be welcome. There are two other changes I'd be interested in making, if you're open to them:

- Error on unterminated strings (`"abc...<EOF>`)
- Acceptance tests for repeated flow documents and tabs in flow documents (an important use case for us)

I'd be happy to get in touch if you want to discuss these further.

Thanks for creating such a great library!

codecov-io: # [Codecov](https://codecov.io/gh/goccy/go-yaml/pull/213?src=pr&el=h1) Report
> Merging [#213](https://codecov.io/gh/goccy/go-yaml/pull/213?src=pr&el=desc) (ca156f6) into [master](https://codecov.io/gh/goccy/go-yaml/commit/2ca66a4c19ac4fca8118c85f0df9df2f5d968d4b?el=desc) (2ca66a4) will **not change** coverage.
> The diff coverage is `100.00%`.


```diff
@@           Coverage Diff           @@
##           master     #213   +/-   ##
=======================================
  Coverage   76.71%   76.71%           
=======================================
  Files          12       12           
  Lines        2946     2946           
=======================================
  Hits         2260     2260           
  Misses        461      461           
  Partials      225      225           
```


Patch:
diff --git a/parser/parser.go b/parser/parser.go
index e5b103a..27a6a6d 100644
--- a/parser/parser.go
+++ b/parser/parser.go
@@ -21,7 +21,7 @@ func (p *parser) parseMapping(ctx *context) (ast.Node, error) {
 		tk := ctx.currentToken()
 		if tk.Type == token.MappingEndType {
 			node.End = tk
-			break
+			return node, nil
 		} else if tk.Type == token.CollectEntryType {
 			ctx.progress(1)
 			continue
@@ -38,7 +38,7 @@ func (p *parser) parseMapping(ctx *context) (ast.Node, error) {
 		node.Values = append(node.Values, mvnode)
 		ctx.progress(1)
 	}
-	return node, nil
+	return nil, errors.ErrSyntax("unterminated flow mapping", node.GetToken())
 }
 
 func (p *parser) parseSequence(ctx *context) (ast.Node, error) {


Test patch:
diff --git a/parser/parser_test.go b/parser/parser_test.go
index a89c5ef..fb7526d 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -633,6 +633,14 @@ a
 [1:2] unexpected map
 >  1 | {invalid
         ^
+`,
+		},
+		{
+			`{ "key": "value" `,
+			`
+[1:1] unterminated flow mapping
+>  1 | { "key": "value"
+       ^
 `,
 		},
 	}
Repository: goccy/go-yaml
Pull request #221 (2021-04-24 21:13:43)

Handle missing required field validation
The current implementation ignores field errors when a required struct field is missing in the yaml.  This change will enable that error to be associated with the token of the parent of the node being validated.  Please consider accepting this small change which might be useful for others.


Patch:
diff --git a/decode.go b/decode.go
index 45d3044..40e3116 100644
--- a/decode.go
+++ b/decode.go
@@ -1061,6 +1061,10 @@ func (d *Decoder) decodeStruct(ctx context.Context, dst reflect.Value, src ast.N
 					if exists {
 						// TODO: to make FieldError message cutomizable
 						return errors.ErrSyntax(fmt.Sprintf("%s", err), node.GetToken())
+					} else if t := src.GetToken(); t != nil && t.Prev != nil && t.Prev.Prev != nil {
+						// A missing required field will not be in the keyToNodeMap
+						// the error needs to be associated with the parent of the source node
+						return errors.ErrSyntax(fmt.Sprintf("%s", err), t.Prev.Prev)
 					}
 				}
 			}


Test patch:
diff --git a/validate_test.go b/validate_test.go
index 185a6b4..3727dfc 100644
--- a/validate_test.go
+++ b/validate_test.go
@@ -38,6 +38,24 @@ func TestStructValidator(t *testing.T) {
 				Age  int    `yaml:"age" validate:"gte=0,lt=120"`
 			}{},
 		},
+		{
+			TestName: "Test Missing Required Field",
+			YAMLContent: `---
+- name: john
+  age: 20
+- age: 10`,
+			ExpectedErr: `[4:1] Key: 'Name' Error:Field validation for 'Name' failed on the 'required' tag
+   1 | ---
+   2 | - name: john
+   3 |   age: 20
+>  4 | - age: 10
+       ^
+`,
+			Instance: &[]struct {
+				Name string `yaml:"name" validate:"required"`
+				Age  int    `yaml:"age" validate:"gte=0,lt=120"`
+			}{},
+		},
 		{
 			TestName: "Test Nested Validation Missing Internal Required",
 			YAMLContent: `---
@@ -45,7 +63,13 @@ name: john
 age: 10
 addr:
   number: seven`,
-			ExpectedErr: "",
+			ExpectedErr: `[4:5] Key: 'State' Error:Field validation for 'State' failed on the 'required' tag
+   1 | ---
+   2 | name: john
+   3 | age: 10
+>  4 | addr:
+           ^
+   5 |   number: seven`,
 			Instance: &struct {
 				Name string `yaml:"name" validate:"required"`
 				Age  int    `yaml:"age" validate:"gte=0,lt=120"`
Repository: goccy/go-yaml
Pull request #237 (2021-07-19 17:23:41)

Fix decode nodes included anchors
`DecodeFromNode` fails to decode nodes included anchors.


Patch:
diff --git a/decode.go b/decode.go
index bf17737..ab85e74 100644
--- a/decode.go
+++ b/decode.go
@@ -1506,6 +1506,8 @@ func (d *Decoder) DecodeFromNodeContext(ctx context.Context, node ast.Node, v in
 			return errors.Wrapf(err, "failed to decodInit")
 		}
 	}
+	// resolve references to the anchor on the same file
+	d.nodeToValue(node)
 	if err := d.decodeValue(ctx, rv.Elem(), node); err != nil {
 		return errors.Wrapf(err, "failed to decode value")
 	}


Test patch:
diff --git a/decode_test.go b/decode_test.go
index f970265..46317fd 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -1718,7 +1718,31 @@ func Test_UnmarshalerContext(t *testing.T) {
 }
 
 func TestDecoder_DecodeFromNode(t *testing.T) {
-	t.Run("with reference", func(t *testing.T) {
+	t.Run("has reference", func(t *testing.T) {
+		str := `
+anchor: &map
+  text: hello
+map: *map`
+		var buf bytes.Buffer
+		dec := yaml.NewDecoder(&buf)
+		f, err := parser.ParseBytes([]byte(str), 0)
+		if err != nil {
+			t.Fatalf("failed to parse: %s", err)
+		}
+		type T struct {
+			Map map[string]string
+		}
+		var v T
+		if err := dec.DecodeFromNode(f.Docs[0].Body, &v); err != nil {
+			t.Fatalf("failed to decode: %s", err)
+		}
+		actual := fmt.Sprintf("%+v", v)
+		expect := fmt.Sprintf("%+v", T{map[string]string{"text": "hello"}})
+		if actual != expect {
+			t.Fatalf("actual=[%s], expect=[%s]", actual, expect)
+		}
+	})
+	t.Run("with reference option", func(t *testing.T) {
 		anchor := strings.NewReader(`
 map: &map
   text: hello`)
Repository: goccy/go-yaml
Pull request #241 (2021-08-09 14:25:16)

fix bug in encoding nested sequences with IndentSequence
There was a bug in the test as well as in the code. The test looked right because it looks like there is indentation before the list items, but the indentation actually comes from the map (B). With this option on, there should be double indentation here. I added another element after the list to make sure I'm not breaking indentation on following items.

old test:
```
v:
  - A
  - 1
  - B:
    - 2
    - 3
```

new test:

```
v:
  - A
  - 1
  - B:
      - 2
      - 3
  - 2
```


Patch:
diff --git a/encode.go b/encode.go
index 8ed0694..026ebec 100644
--- a/encode.go
+++ b/encode.go
@@ -417,10 +417,10 @@ func (e *Encoder) encodeBool(v bool) ast.Node {
 }
 
 func (e *Encoder) encodeSlice(ctx context.Context, value reflect.Value) (ast.Node, error) {
-	column := e.column
 	if e.indentSequence {
-		column += e.indent
+		e.column += e.indent
 	}
+	column := e.column
 	sequence := ast.Sequence(token.New("-", "-", e.pos(column)), e.isFlowStyle)
 	for i := 0; i < value.Len(); i++ {
 		node, err := e.encodeValue(ctx, value.Index(i), column)
@@ -429,14 +429,17 @@ func (e *Encoder) encodeSlice(ctx context.Context, value reflect.Value) (ast.Nod
 		}
 		sequence.Values = append(sequence.Values, node)
 	}
+	if e.indentSequence {
+		e.column -= e.indent
+	}
 	return sequence, nil
 }
 
 func (e *Encoder) encodeArray(ctx context.Context, value reflect.Value) (ast.Node, error) {
-	column := e.column
 	if e.indentSequence {
-		column += e.indent
+		e.column += e.indent
 	}
+	column := e.column
 	sequence := ast.Sequence(token.New("-", "-", e.pos(column)), e.isFlowStyle)
 	for i := 0; i < value.Len(); i++ {
 		node, err := e.encodeValue(ctx, value.Index(i), column)
@@ -445,6 +448,9 @@ func (e *Encoder) encodeArray(ctx context.Context, value reflect.Value) (ast.Nod
 		}
 		sequence.Values = append(sequence.Values, node)
 	}
+	if e.indentSequence {
+		e.column -= e.indent
+	}
 	return sequence, nil
 }
 


Test patch:
diff --git a/encode_test.go b/encode_test.go
index 31e1a29..4c5a876 100644
--- a/encode_test.go
+++ b/encode_test.go
@@ -222,7 +222,7 @@ func TestEncoder(t *testing.T) {
 			nil,
 		},
 		{
-			"v:\n  - A\n  - 1\n  - B:\n    - 2\n    - 3\n",
+			"v:\n  - A\n  - 1\n  - B:\n      - 2\n      - 3\n  - 2\n",
 			map[string]interface{}{
 				"v": []interface{}{
 					"A",
@@ -230,6 +230,7 @@ func TestEncoder(t *testing.T) {
 					map[string][]int{
 						"B": {2, 3},
 					},
+					2,
 				},
 			},
 			[]yaml.EncodeOption{
Repository: goccy/go-yaml
Pull request #244 (2021-08-10 04:34:34)

Fix error reporting on inline structs in strict mode (#243)
Errors from inline structs were getting lost in strict mode.


Patch:
diff --git a/decode.go b/decode.go
index ab85e74..cb07a84 100644
--- a/decode.go
+++ b/decode.go
@@ -981,7 +981,7 @@ func (d *Decoder) decodeStruct(ctx context.Context, dst reflect.Value, src ast.N
 					err = nil
 				}
 
-				if err = d.deleteStructKeys(fieldValue.Type(), unknownFields); err != nil {
+				if err := d.deleteStructKeys(fieldValue.Type(), unknownFields); err != nil {
 					return errors.Wrapf(err, "cannot delete struct keys")
 				}
 			}


Test patch:
diff --git a/decode_test.go b/decode_test.go
index 46317fd..d6da735 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -1454,6 +1454,32 @@ c: true
 	}
 }
 
+func TestDecoder_InlineAndWrongTypeStrict(t *testing.T) {
+	type Base struct {
+		A int
+		B string
+	}
+	yml := `---
+a: notanint
+b: hello
+c: true
+`
+	var v struct {
+		*Base `yaml:",inline"`
+		C     bool
+	}
+	err := yaml.NewDecoder(strings.NewReader(yml), yaml.Strict()).Decode(&v)
+	if err == nil {
+		t.Fatalf("expected error")
+	}
+
+	//TODO: properly check if errors are colored/have source
+	t.Logf("%s", err)
+	t.Logf("%s", yaml.FormatError(err, true, false))
+	t.Logf("%s", yaml.FormatError(err, false, true))
+	t.Logf("%s", yaml.FormatError(err, true, true))
+}
+
 func TestDecoder_InvalidCases(t *testing.T) {
 	const src = `---
 a:
Repository: goccy/go-yaml
Pull request #245 (2021-08-10 07:44:46)

Properly report validation errors from inline fields in strict mode
Second half of #244...


Patch:
diff --git a/decode.go b/decode.go
index cb07a84..4b40e29 100644
--- a/decode.go
+++ b/decode.go
@@ -976,11 +976,6 @@ func (d *Decoder) decodeStruct(ctx context.Context, dst reflect.Value, src ast.N
 			}
 			newFieldValue, err := d.createDecodedNewValue(ctx, fieldValue.Type(), mapNode)
 			if d.disallowUnknownField {
-				var ufe *unknownFieldError
-				if xerrors.As(err, &ufe) {
-					err = nil
-				}
-
 				if err := d.deleteStructKeys(fieldValue.Type(), unknownFields); err != nil {
 					return errors.Wrapf(err, "cannot delete struct keys")
 				}
@@ -1042,7 +1037,9 @@ func (d *Decoder) decodeStruct(ctx context.Context, dst reflect.Value, src ast.N
 		return errors.Wrapf(foundErr, "failed to decode value")
 	}
 
-	if len(unknownFields) != 0 && d.disallowUnknownField {
+	// Ignore unknown fields when parsing an inline struct (recognized by a nil token).
+	// Unknown fields are expected (they could be fields from the parent struct).
+	if len(unknownFields) != 0 && d.disallowUnknownField && src.GetToken() != nil {
 		for key, node := range unknownFields {
 			return errUnknownField(fmt.Sprintf(`unknown field "%s"`, key), node.GetToken())
 		}
@@ -1073,6 +1070,7 @@ func (d *Decoder) decodeStruct(ctx context.Context, dst reflect.Value, src ast.N
 					}
 				}
 			}
+			return err
 		}
 	}
 	return nil


Test patch:
diff --git a/validate_test.go b/validate_test.go
index b20679e..265deb8 100644
--- a/validate_test.go
+++ b/validate_test.go
@@ -9,6 +9,10 @@ import (
 )
 
 func TestStructValidator(t *testing.T) {
+	type Inner struct {
+		Required string `validate:"required"`
+		Lt10     int    `validate:"lt=10"`
+	}
 
 	cases := []struct {
 		TestName    string
@@ -135,6 +139,40 @@ roles:
 				} `yaml:"roles"`
 			}{},
 		},
+		{
+			TestName: "Test inline validation missing required",
+			YAMLContent: `---
+name: john
+age: 20
+`,
+			ExpectedErr: `Key: 'Inner.Required' Error:Field validation for 'Required' failed on the 'required' tag`,
+			Instance: &struct {
+				Name  string `yaml:"name" validate:"required"`
+				Age   int    `yaml:"age" validate:"gte=0,lt=120"`
+				Inner `yaml:",inline"`
+			}{},
+		},
+		{
+			TestName: "Test inline validation field error",
+			YAMLContent: `---
+name: john
+age: 20
+required: present
+lt10: 20
+`,
+			ExpectedErr: `[5:7] Key: 'Inner.Lt10' Error:Field validation for 'Lt10' failed on the 'lt' tag
+   2 | name: john
+   3 | age: 20
+   4 | required: present
+>  5 | lt10: 20
+             ^
+`,
+			Instance: &struct {
+				Name  string `yaml:"name" validate:"required"`
+				Age   int    `yaml:"age" validate:"gte=0,lt=120"`
+				Inner `yaml:",inline"`
+			}{},
+		},
 	}
 
 	for _, tc := range cases {
Repository: goccy/go-yaml
Pull request #247 (2021-08-16 20:31:58)

Fix encoding of large floats
An extra `.0` was getting appended when the value of the float was a power of 10.


Patch:
diff --git a/encode.go b/encode.go
index 026ebec..1441f23 100644
--- a/encode.go
+++ b/encode.go
@@ -384,7 +384,7 @@ func (e *Encoder) encodeFloat(v float64, bitSize int) ast.Node {
 		return ast.Nan(token.New(value, value, e.pos(e.column)))
 	}
 	value := strconv.FormatFloat(v, 'g', -1, bitSize)
-	if !strings.Contains(value, ".") {
+	if !strings.Contains(value, ".") && !strings.Contains(value, "e") {
 		// append x.0 suffix to keep float value context
 		value = fmt.Sprintf("%s.0", value)
 	}


Test patch:
diff --git a/encode_test.go b/encode_test.go
index 4c5a876..40f0538 100644
--- a/encode_test.go
+++ b/encode_test.go
@@ -93,6 +93,11 @@ func TestEncoder(t *testing.T) {
 			map[string]float64{"v": 1.0},
 			nil,
 		},
+		{
+			"v: 1e+06\n",
+			map[string]float64{"v": 1000000},
+			nil,
+		},
 		{
 			"v: .inf\n",
 			map[string]interface{}{"v": math.Inf(0)},
Repository: goccy/go-yaml
Pull request #275 (2021-12-08 01:10:51)

Handle empty sequence entries
- adds a nil check for tk, and returns a syntax error if nil is found
- adds a test verifying fix

Signed-off-by: Taylor Thornton <thornton.tn@gmail.com>

fixes: #274 


Patch:
diff --git a/parser/parser.go b/parser/parser.go
index fcbd3bd..80c9f51 100644
--- a/parser/parser.go
+++ b/parser/parser.go
@@ -281,6 +281,9 @@ func (p *parser) parseSequenceEntry(ctx *context) (ast.Node, error) {
 	for tk.Type == token.SequenceEntryType {
 		ctx.progress(1) // skip sequence token
 		tk = ctx.currentToken()
+		if tk == nil {
+			return nil, errors.ErrSyntax("empty sequence entry", ctx.previousToken())
+		}
 		var comment *ast.CommentGroupNode
 		if tk.Type == token.CommentType {
 			comment = p.parseCommentOnly(ctx)


Test patch:
diff --git a/parser/parser_test.go b/parser/parser_test.go
index 9d86b05..9439d6f 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -643,6 +643,19 @@ a
 [1:1] unterminated flow mapping
 >  1 | { "key": "value"
        ^
+`,
+		},
+		{
+			`
+a:
+- b: c
+- `,
+			`
+[4:1] empty sequence entry
+   2 | a:
+   3 | - b: c
+>  4 | -
+       ^
 `,
 		},
 	}
Repository: goccy/go-yaml
Pull request #276 (2022-01-11 08:54:51)

Fix encoding of sequence with multiline string
Currently, there is a problem that indentation becomes deeper than necessary when using sequences with multiple strings.
This PR fixes this problem .


Patch:
diff --git a/ast/ast.go b/ast/ast.go
index 9a1c955..fa3e5e0 100644
--- a/ast/ast.go
+++ b/ast/ast.go
@@ -1586,6 +1586,12 @@ func (n *SequenceNode) blockStyleString() string {
 		splittedValues := strings.Split(valueStr, "\n")
 		trimmedFirstValue := strings.TrimLeft(splittedValues[0], " ")
 		diffLength := len(splittedValues[0]) - len(trimmedFirstValue)
+		if len(splittedValues) > 1 && value.Type() == StringType || value.Type() == LiteralType {
+			// If multi-line string, the space characters for indent have already been added, so delete them.
+			for i := 1; i < len(splittedValues); i++ {
+				splittedValues[i] = strings.TrimLeft(splittedValues[i], " ")
+			}
+		}
 		newValues := []string{trimmedFirstValue}
 		for i := 1; i < len(splittedValues); i++ {
 			if len(splittedValues[i]) <= diffLength {


Test patch:
diff --git a/encode_test.go b/encode_test.go
index 0df0bca..b7dc0cf 100644
--- a/encode_test.go
+++ b/encode_test.go
@@ -1302,3 +1302,49 @@ func Example_MarshalYAML() {
 	//
 	// field: 13
 }
+
+func TestMarshalIndentWithMultipleText(t *testing.T) {
+	t.Run("depth1", func(t *testing.T) {
+		b, err := yaml.MarshalWithOptions(map[string]interface{}{
+			"key": []string{`line1
+line2
+line3`},
+		}, yaml.Indent(2))
+		if err != nil {
+			t.Fatal(err)
+		}
+		got := string(b)
+		expected := `key:
+- |-
+  line1
+  line2
+  line3
+`
+		if expected != got {
+			t.Fatalf("failed to encode.\nexpected:\n%s\nbut got:\n%s\n", expected, got)
+		}
+	})
+	t.Run("depth2", func(t *testing.T) {
+		b, err := yaml.MarshalWithOptions(map[string]interface{}{
+			"key": map[string]interface{}{
+				"key2": []string{`line1
+line2
+line3`},
+			},
+		}, yaml.Indent(2))
+		if err != nil {
+			t.Fatal(err)
+		}
+		got := string(b)
+		expected := `key:
+  key2:
+  - |-
+    line1
+    line2
+    line3
+`
+		if expected != got {
+			t.Fatalf("failed to encode.\nexpected:\n%s\nbut got:\n%s\n", expected, got)
+		}
+	})
+}
Repository: goccy/go-yaml
Pull request #277 (2022-01-11 09:15:43)

Fix encoding of BytesMarshaler type
fix https://github.com/goccy/go-yaml/issues/268


Patch:
diff --git a/encode.go b/encode.go
index 7b4ba56..31eaf94 100644
--- a/encode.go
+++ b/encode.go
@@ -510,8 +510,8 @@ func (e *Encoder) encodeMap(ctx context.Context, value reflect.Value, column int
 		if err != nil {
 			return nil
 		}
-		if m, ok := value.(*ast.MappingNode); ok {
-			m.AddColumn(e.indent)
+		if value.Type() == ast.MappingType || value.Type() == ast.MappingValueType {
+			value.AddColumn(e.indent)
 		}
 		node.Values = append(node.Values, ast.MappingValue(
 			nil,


Test patch:
diff --git a/encode_test.go b/encode_test.go
index b7dc0cf..0a6f1fe 100644
--- a/encode_test.go
+++ b/encode_test.go
@@ -1348,3 +1348,32 @@ line3`},
 		}
 	})
 }
+
+type bytesMarshaler struct{}
+
+func (b *bytesMarshaler) MarshalYAML() ([]byte, error) {
+	return yaml.Marshal(map[string]interface{}{"d": "foo"})
+}
+
+func TestBytesMarshaler(t *testing.T) {
+	b, err := yaml.Marshal(map[string]interface{}{
+		"a": map[string]interface{}{
+			"b": map[string]interface{}{
+				"c": &bytesMarshaler{},
+			},
+		},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+	expected := `
+a:
+  b:
+    c:
+      d: foo
+`
+	got := "\n" + string(b)
+	if expected != got {
+		t.Fatalf("failed to encode. expected %s but got %s", expected, got)
+	}
+}
Repository: goccy/go-yaml
Pull request #318 (2022-10-24 16:14:43)

fix: insert a separator between each encoded document
Fix the behavior as [the comment](https://github.com/goccy/go-yaml/blob/ecececdd257a265811b1646bc8e96b85cc2d2b0d/encode.go#L71-L73).

> If multiple items are encoded to the stream,
> the second and subsequent document will be preceded with a "---" document separator,
> but the first will not.


Patch:
diff --git a/encode.go b/encode.go
index f582b48..221706b 100644
--- a/encode.go
+++ b/encode.go
@@ -39,6 +39,7 @@ type Encoder struct {
 	anchorPtrToNameMap         map[uintptr]string
 	useLiteralStyleIfMultiline bool
 	commentMap                 map[*Path]*Comment
+	written                    bool
 
 	line        int
 	column      int
@@ -86,6 +87,12 @@ func (e *Encoder) EncodeContext(ctx context.Context, v interface{}) error {
 	if err := e.setCommentByCommentMap(node); err != nil {
 		return errors.Wrapf(err, "failed to set comment by comment map")
 	}
+	if !e.written {
+		e.written = true
+	} else {
+		// write document separator
+		e.writer.Write([]byte("---\n"))
+	}
 	var p printer.Printer
 	e.writer.Write(p.PrintNode(node))
 	return nil


Test patch:
diff --git a/encode_test.go b/encode_test.go
index 2edb9a2..3720d41 100644
--- a/encode_test.go
+++ b/encode_test.go
@@ -1094,6 +1094,20 @@ a:
 	}
 }
 
+func TestEncoder_MultipleDocuments(t *testing.T) {
+	var buf bytes.Buffer
+	enc := yaml.NewEncoder(&buf)
+	if err := enc.Encode(1); err != nil {
+		t.Fatalf("failed to encode: %s", err)
+	}
+	if err := enc.Encode(2); err != nil {
+		t.Fatalf("failed to encode: %s", err)
+	}
+	if actual, expect := buf.String(), "1\n---\n2\n"; actual != expect {
+		t.Errorf("expect:\n%s\nactual\n%s\n", expect, actual)
+	}
+}
+
 func Example_Marshal_Node() {
 	type T struct {
 		Text ast.Node `yaml:"text"`
Repository: goccy/go-yaml
Pull request #322 (2022-11-14 10:20:16)

Fix resusing process of scanning context
fix https://github.com/goccy/go-yaml/issues/316


Patch:
diff --git a/scanner/context.go b/scanner/context.go
index e629a5c..8cd18cf 100644
--- a/scanner/context.go
+++ b/scanner/context.go
@@ -55,7 +55,11 @@ func (c *Context) reset(src []rune) {
 	c.src = src
 	c.tokens = c.tokens[:0]
 	c.resetBuffer()
+	c.isRawFolded = false
 	c.isSingleLine = true
+	c.isLiteral = false
+	c.isFolded = false
+	c.literalOpt = ""
 }
 
 func (c *Context) resetBuffer() {


Test patch:
diff --git a/decode_test.go b/decode_test.go
index af6e454..27b31ee 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -2732,3 +2732,52 @@ bar:
 		}
 	})
 }
+
+func TestUnmarshalMapSliceParallel(t *testing.T) {
+	content := `
+steps:
+  req0:
+    desc: Get /users/1
+    req:
+      /users/1:
+        get: nil
+    test: |
+      current.res.status == 200
+  req1:
+    desc: Get /private
+    req:
+      /private:
+        get: nil
+    test: |
+      current.res.status == 403
+  req2:
+    desc: Get /users
+    req:
+      /users:
+        get: nil
+    test: |
+      current.res.status == 200
+`
+	type mappedSteps struct {
+		Steps yaml.MapSlice `yaml:"steps,omitempty"`
+	}
+	for i := 0; i < 100; i++ {
+		t.Run(fmt.Sprintf("i=%d", i), func(t *testing.T) {
+			t.Parallel()
+			for i := 0; i < 10; i++ {
+				m := mappedSteps{
+					Steps: yaml.MapSlice{},
+				}
+				if err := yaml.Unmarshal([]byte(content), &m); err != nil {
+					t.Fatal(err)
+				}
+				for _, s := range m.Steps {
+					_, ok := s.Value.(map[string]interface{})
+					if !ok {
+						t.Fatal("unexpected error")
+					}
+				}
+			}
+		})
+	}
+}