Skip to content

Commit

Permalink
fix(encode): extra test cases and fixes
Browse files Browse the repository at this point in the history
Add round-trip tests as requested in code review and fix a few other scenarios
uncovered by the addition of new tests.
  • Loading branch information
stormqueen1990 committed Aug 16, 2024
1 parent f404b76 commit 742f5e6
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 20 deletions.
10 changes: 10 additions & 0 deletions goyaml.v2/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding"
"fmt"
"io"
"math/big"
"reflect"
"regexp"
"sort"
Expand Down Expand Up @@ -122,6 +123,9 @@ func (e *encoder) marshal(tag string, in reflect.Value) {
// we don't want to treat it as a string for YAML
// purposes because YAML has special support for
// timestamps.
case *big.Int:
e.bigintv(tag, reflect.ValueOf(m.String()))
return
case Marshaler:
v, err := m.MarshalYAML()
if err != nil {
Expand Down Expand Up @@ -354,6 +358,12 @@ func (e *encoder) uintv(tag string, in reflect.Value) {
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
}

func (e *encoder) bigintv(tag string, in reflect.Value) {
value := &big.Int{}
s, _ := value.SetString(in.String(), 0)
e.emitScalar(s.String(), "", tag, yaml_PLAIN_SCALAR_STYLE)
}

func (e *encoder) timev(tag string, in reflect.Value) {
t := in.Interface().(time.Time)
s := t.Format(time.RFC3339Nano)
Expand Down
36 changes: 35 additions & 1 deletion goyaml.v2/encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"os"

. "gopkg.in/check.v1"
"sigs.k8s.io/yaml/goyaml.v2"
yaml "sigs.k8s.io/yaml/goyaml.v2"
)

type jsonNumberT string
Expand Down Expand Up @@ -641,6 +641,40 @@ func (s *S) TestSortedOutput(c *C) {
}
}

func (s *S) TestQuotingMaintained(c *C) {
var buf bytes.Buffer
var yamlValue map[string]interface{}
const originalYaml = `data:
A1: "0x0000000000000000000000010000000000000000"
A2: "0x000000000000000000000000FFFFFFFFFFFFFFFF"
A3: "1234"
A4: 0x0000000000000000000000010000000000000000
A5: 0x000000000000000000000000FFFFFFFFFFFFFFFF
A6: 1234
`
const outputYaml = `data:
A1: "0x0000000000000000000000010000000000000000"
A2: "0x000000000000000000000000FFFFFFFFFFFFFFFF"
A3: "1234"
A4: 18446744073709551616
A5: 18446744073709551615
A6: 1234
`

dec := yaml.NewDecoder(strings.NewReader(originalYaml))
errDec := dec.Decode(&yamlValue)
c.Assert(errDec, IsNil)

enc := yaml.NewEncoder(&buf)
errEnc := enc.Encode(yamlValue)
c.Assert(errEnc, IsNil)

errClose := enc.Close()
c.Assert(errClose, IsNil)

c.Assert(buf.String(), Equals, outputYaml)
}

func newTime(t time.Time) *time.Time {
return &t
}
23 changes: 19 additions & 4 deletions goyaml.v2/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package yaml

import (
"encoding/base64"
"errors"
"math"
"math/big"
"regexp"
"strconv"
"strings"
Expand Down Expand Up @@ -148,16 +150,18 @@ func resolve(tag string, in string) (rtag string, out interface{}) {
}

plain := strings.Replace(in, "_", "", -1)
intv, err := strconv.ParseInt(plain, 0, 64)
if err == nil {

var intConvErr error
intv, intConvErr := strconv.ParseInt(plain, 0, 64)
if intConvErr == nil {
if intv == int64(int(intv)) {
return yaml_INT_TAG, int(intv)
} else {
return yaml_INT_TAG, intv
}
}
uintv, err := strconv.ParseUint(plain, 0, 64)
if err == nil {
uintv, intConvErr := strconv.ParseUint(plain, 0, 64)
if intConvErr == nil {
return yaml_INT_TAG, uintv
}
if yamlStyleFloat.MatchString(plain) {
Expand Down Expand Up @@ -189,6 +193,17 @@ func resolve(tag string, in string) (rtag string, out interface{}) {
}
}
}

// If number out of range and doesn't fit any of the other cases,
// check if it's valid for bigger than 64 bytes
if errors.Is(intConvErr, strconv.ErrRange) {
value := &big.Int{}

bigintv, ok := value.SetString(plain, 0)
if ok {
return yaml_INT_TAG, bigintv
}
}
default:
panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")")
}
Expand Down
32 changes: 17 additions & 15 deletions goyaml.v3/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,29 +191,20 @@ func resolve(tag string, in string) (rtag string, out interface{}) {
}

plain := strings.Replace(in, "_", "", -1)
intv, err := strconv.ParseInt(plain, 0, 64)
if err == nil {

var intConvErr error
intv, intConvErr := strconv.ParseInt(plain, 0, 64)
if intConvErr == nil {
if intv == int64(int(intv)) {
return intTag, int(intv)
} else {
return intTag, intv
}
}
uintv, err := strconv.ParseUint(plain, 0, 64)
if err == nil {
uintv, intConvErr := strconv.ParseUint(plain, 0, 64)
if intConvErr == nil {
return intTag, uintv
}

// If integer out of range, check if it's valid for bigger than 64 bytes
if errors.Is(err, strconv.ErrRange) {
value := &big.Int{}

result, ok := value.SetString(plain, 0)
if ok {
return intTag, result
}
}

if yamlStyleFloat.MatchString(plain) {
floatv, err := strconv.ParseFloat(plain, 64)
if err == nil {
Expand Down Expand Up @@ -270,6 +261,17 @@ func resolve(tag string, in string) (rtag string, out interface{}) {
}
}
}

// If number out of range and doesn't fit any of the other cases,
// check if it's valid for bigger than 64 bytes
if errors.Is(intConvErr, strconv.ErrRange) {
value := &big.Int{}

bigintv, ok := value.SetString(plain, 0)
if ok {
return intTag, bigintv
}
}
default:
panic("internal error: missing handler for resolver table: " + string(rune(hint)) + " (with " + in + ")")
}
Expand Down
27 changes: 27 additions & 0 deletions yaml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,31 @@ func TestYAMLToJSON(t *testing.T) {
json: `{"a":"\ufffd\ufffd\ufffd"}`,
yamlReverseOverwrite: strPtr("a: \ufffd\ufffd\ufffd\n"),
},
"small hex value": {
yaml: "key: 0x0001",
json: `{"key":1}`,
yamlReverseOverwrite: strPtr("key: 1\n"),
},
"hex value at the 64 byte mark": {
yaml: "key: 0x000000000000000000000000FFFFFFFFFFFFFFFF",
json: `{"key":18446744073709551615}`,
yamlReverseOverwrite: strPtr("key: 18446744073709551615\n"),
},
"hex value at the 64 byte mark in string format": {
yaml: "key: \"0x000000000000000000000000FFFFFFFFFFFFFFFF\"",
json: `{"key":"0x000000000000000000000000FFFFFFFFFFFFFFFF"}`,
yamlReverseOverwrite: strPtr("key: \"0x000000000000000000000000FFFFFFFFFFFFFFFF\"\n"),
},
"huge hex value bigger than 64 bytes": {
yaml: "key: 0x0000000000000000000000010000000000000000",
json: `{"key":18446744073709551616}`,
yamlReverseOverwrite: strPtr("key: 1.8446744073709552e+19\n"),
},
"huge hex value bigger than 64 bytes in string format": {
yaml: "key: \"0x0000000000000000000000010000000000000000\"",
json: `{"key":"0x0000000000000000000000010000000000000000"}`,
yamlReverseOverwrite: strPtr("key: \"0x0000000000000000000000010000000000000000\"\n"),
},

// Cases that should produce errors.
"~ key": {
Expand Down Expand Up @@ -809,6 +834,7 @@ func TestJSONObjectToYAMLObject(t *testing.T) {
"slice": []interface{}{"foo", "bar"},
"string": string("foo"),
"uint64 big": bigUint64,
"big hex int": "0x0000000000000000000000010000000000000000",
},
expected: yamlv2.MapSlice{
{Key: "nil slice"},
Expand All @@ -826,6 +852,7 @@ func TestJSONObjectToYAMLObject(t *testing.T) {
{Key: "slice", Value: []interface{}{"foo", "bar"}},
{Key: "string", Value: string("foo")},
{Key: "uint64 big", Value: bigUint64},
{Key: "big hex int", Value: "0x0000000000000000000000010000000000000000"},
},
},
}
Expand Down

0 comments on commit 742f5e6

Please sign in to comment.