Repository: goccy/go-yaml
Pull request #78 (2020-01-12 13:29:56)

Pass raw string to yaml.BytesUnmarshaler
fix: #75 


Patch:
diff --git a/decode.go b/decode.go
index b9b21f9..c5d6f48 100644
--- a/decode.go
+++ b/decode.go
@@ -336,7 +336,12 @@ func (d *Decoder) decodeValue(dst reflect.Value, src ast.Node) error {
 	}
 	valueType := dst.Type()
 	if unmarshaler, ok := dst.Addr().Interface().(BytesUnmarshaler); ok {
-		b := fmt.Sprintf("%v", src)
+		var b string
+		if scalar, isScalar := src.(ast.ScalarNode); isScalar {
+			b = fmt.Sprint(scalar.GetValue())
+		} else {
+			b = src.String()
+		}
 		if err := unmarshaler.UnmarshalYAML([]byte(b)); err != nil {
 			return errors.Wrapf(err, "failed to UnmarshalYAML")
 		}
diff --git a/go.mod b/go.mod
index 71a617d..b6e88de 100644
--- a/go.mod
+++ b/go.mod
@@ -12,4 +12,6 @@ require (
 	golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898
 	gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
 	gopkg.in/go-playground/validator.v9 v9.30.0
+	gopkg.in/yaml.v2 v2.2.2
+	gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2
 )
diff --git a/go.sum b/go.sum
index d4ff87e..f142df7 100644
--- a/go.sum
+++ b/go.sum
@@ -36,3 +36,5 @@ gopkg.in/go-playground/validator.v9 v9.30.0 h1:Wk0Z37oBmKj9/n+tPyBHZmeL19LaCoK3Q
 gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
 gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM=
+gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=


Test patch:
diff --git a/decode_test.go b/decode_test.go
index 5c830c3..c016be6 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -6,6 +6,7 @@ import (
 	"log"
 	"math"
 	"reflect"
+	"strconv"
 	"strings"
 	"testing"
 	"time"
@@ -1355,3 +1356,95 @@ complecated: string
 	//     >  3 | complecated: string
 	//           ^
 }
+
+type unmarshalableStringValue string
+
+func (v *unmarshalableStringValue) UnmarshalYAML(raw []byte) error {
+	*v = unmarshalableStringValue(string(raw))
+	return nil
+}
+
+type unmarshalableStringContainer struct {
+	V unmarshalableStringValue `yaml:"value" json:"value"`
+}
+
+func TestUnmarshalableString(t *testing.T) {
+	t.Run("empty string", func(t *testing.T) {
+		t.Parallel()
+		var container unmarshalableStringContainer
+		if err := yaml.Unmarshal([]byte(`value: ""`), &container); err != nil {
+			t.Fatalf("failed to unmarshal %v", err)
+		}
+		if container.V != "" {
+			t.Fatalf("expected empty string, but %q is set", container.V)
+		}
+	})
+	t.Run("filled string", func(t *testing.T) {
+		t.Parallel()
+		var container unmarshalableStringContainer
+		if err := yaml.Unmarshal([]byte(`value: "aaa"`), &container); err != nil {
+			t.Fatalf("failed to unmarshal %v", err)
+		}
+		if container.V != "aaa" {
+			t.Fatalf("expected \"aaa\", but %q is set", container.V)
+		}
+	})
+	t.Run("single-quoted string", func(t *testing.T) {
+		t.Parallel()
+		var container unmarshalableStringContainer
+		if err := yaml.Unmarshal([]byte(`value: 'aaa'`), &container); err != nil {
+			t.Fatalf("failed to unmarshal %v", err)
+		}
+		if container.V != "aaa" {
+			t.Fatalf("expected \"aaa\", but %q is set", container.V)
+		}
+	})
+}
+
+type unmarshalableIntValue int
+
+func (v *unmarshalableIntValue) UnmarshalYAML(raw []byte) error {
+	i, err := strconv.Atoi(string(raw))
+	if err != nil {
+		return err
+	}
+	*v = unmarshalableIntValue(i)
+	return nil
+}
+
+type unmarshalableIntContainer struct {
+	V unmarshalableIntValue `yaml:"value" json:"value"`
+}
+
+func TestUnmarshalableInt(t *testing.T) {
+	t.Run("empty int", func(t *testing.T) {
+		t.Parallel()
+		var container unmarshalableIntContainer
+		if err := yaml.Unmarshal([]byte(``), &container); err != nil {
+			t.Fatalf("failed to unmarshal %v", err)
+		}
+		if container.V != 0 {
+			t.Fatalf("expected empty int, but %d is set", container.V)
+		}
+	})
+	t.Run("filled int", func(t *testing.T) {
+		t.Parallel()
+		var container unmarshalableIntContainer
+		if err := yaml.Unmarshal([]byte(`value: 9`), &container); err != nil {
+			t.Fatalf("failed to unmarshal %v", err)
+		}
+		if container.V != 9 {
+			t.Fatalf("expected 9, but %d is set", container.V)
+		}
+	})
+	t.Run("filled number", func(t *testing.T) {
+		t.Parallel()
+		var container unmarshalableIntContainer
+		if err := yaml.Unmarshal([]byte(`value: 9`), &container); err != nil {
+			t.Fatalf("failed to unmarshal %v", err)
+		}
+		if container.V != 9 {
+			t.Fatalf("expected 9, but %d is set", container.V)
+		}
+	})
+}