Repository: goccy/go-yaml
Pull request #725 (2025-05-07 15:07:47)

Set null value for empty document
fix https://github.com/goccy/go-yaml/issues/724

codecov-commenter: :warning: Please install the !['codecov app svg image'](https://github.com/codecov/engineering-team/assets/152432831/e90313f4-9d3a-4b63-8b54-cfe14e7ec20d) to ensure uploads and comments are reliably processed by Codecov.

## [Codecov](https://app.codecov.io/gh/goccy/go-yaml/pull/725?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 77.94%. Comparing base [(`4b07c0d`)](https://app.codecov.io/gh/goccy/go-yaml/commit/4b07c0d4851994ed29d585de04d20cb7c7533359?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima) to head [(`08fd6a5`)](https://app.codecov.io/gh/goccy/go-yaml/commit/08fd6a5b2044e679d3bf9f840af948eb05de5ec3?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima).

:exclamation: Your organization needs to install the [Codecov GitHub app](https://github.com/apps/codecov/installations/select_target) to enable full functionality.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master     #725      +/-   ##
==========================================
+ Coverage   77.92%   77.94%   +0.01%     
==========================================
  Files          22       22              
  Lines        7986     7992       +6     
==========================================
+ Hits         6223     6229       +6     
  Misses       1348     1348              
  Partials      415      415              
```

</details>
<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>

Patch:
diff --git a/decode.go b/decode.go
index 00f628c..9c168fe 100644
--- a/decode.go
+++ b/decode.go
@@ -882,6 +882,9 @@ func (d *Decoder) decodeValue(ctx context.Context, dst reflect.Value, src ast.No
 	if d.isExceededMaxDepth() {
 		return ErrExceededMaxDepth
 	}
+	if !dst.IsValid() {
+		return nil
+	}
 
 	if src.Type() == ast.AnchorType {
 		anchor, _ := src.(*ast.AnchorNode)
@@ -930,6 +933,8 @@ func (d *Decoder) decodeValue(ctx context.Context, dst reflect.Value, src ast.No
 		v := reflect.ValueOf(srcVal)
 		if v.IsValid() {
 			dst.Set(v)
+		} else {
+			dst.Set(reflect.Zero(valueType))
 		}
 	case reflect.Map:
 		return d.decodeMap(ctx, dst, src)
@@ -1930,6 +1935,13 @@ func (d *Decoder) decodeInit(ctx context.Context) error {
 func (d *Decoder) decode(ctx context.Context, v reflect.Value) error {
 	d.decodeDepth = 0
 	d.anchorValueMap = make(map[string]reflect.Value)
+	if len(d.parsedFile.Docs) == 0 {
+		// empty document.
+		dst := v.Elem()
+		if dst.IsValid() {
+			dst.Set(reflect.Zero(dst.Type()))
+		}
+	}
 	if len(d.parsedFile.Docs) <= d.streamIndex {
 		return io.EOF
 	}
@@ -1960,14 +1972,11 @@ func (d *Decoder) Decode(v interface{}) error {
 // and stores it in the value pointed to by v with context.Context.
 func (d *Decoder) DecodeContext(ctx context.Context, v interface{}) error {
 	rv := reflect.ValueOf(v)
-	if rv.Type().Kind() != reflect.Ptr {
+	if !rv.IsValid() || rv.Type().Kind() != reflect.Ptr {
 		return ErrDecodeRequiredPointerType
 	}
 	if d.isInitialized() {
 		if err := d.decode(ctx, rv); err != nil {
-			if err == io.EOF {
-				return err
-			}
 			return err
 		}
 		return nil
@@ -1976,9 +1985,6 @@ func (d *Decoder) DecodeContext(ctx context.Context, v interface{}) error {
 		return err
 	}
 	if err := d.decode(ctx, rv); err != nil {
-		if err == io.EOF {
-			return err
-		}
 		return err
 	}
 	return nil


Test patch:
diff --git a/decode_test.go b/decode_test.go
index 81db22f..2623e39 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -3685,3 +3685,42 @@ releases:
 		t.Fatal(err)
 	}
 }
+
+func TestSetNullValue(t *testing.T) {
+	tests := []struct {
+		name string
+		src  string
+	}{
+		{
+			name: "empty document",
+			src:  "",
+		},
+		{
+			name: "null value",
+			src:  "null",
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			t.Run("set null", func(t *testing.T) {
+				var v any
+				v = 0x1
+				if err := yaml.Unmarshal([]byte(test.src), &v); err != nil {
+					t.Fatal(err)
+				}
+				if v != nil {
+					t.Fatal("failed to set nil value")
+				}
+			})
+			t.Run("invalid value", func(t *testing.T) {
+				var v *struct{}
+				if err := yaml.Unmarshal([]byte(test.src), v); err != nil {
+					t.Fatal(err)
+				}
+				if v != nil {
+					t.Fatal("failed to set nil value")
+				}
+			})
+		})
+	}
+}