Skip to content

Commit

Permalink
allow skip in UnmarshalJSONV2 methods
Browse files Browse the repository at this point in the history
* fix skipping in arshal_test.go
  • Loading branch information
elv-gilles committed Apr 16, 2024
1 parent ed9469c commit 6510be0
Show file tree
Hide file tree
Showing 7 changed files with 959 additions and 10 deletions.
19 changes: 19 additions & 0 deletions arshal_methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
switch which := implementsWhich(t, jsonMarshalerV2Type, jsonMarshalerV1Type, textAppenderType, textMarshalerType); which {
case jsonMarshalerV2Type:
fncs.nonDefault = true
defMarshal := fncs.marshal
fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
xe := export.Encoder(enc)
prevDepth, prevLength := xe.Tokens.DepthLength()
Expand All @@ -120,6 +121,15 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil {
err = errors.New("must write exactly one JSON value")
}
if err == SkipFunc && defMarshal != nil {
if prevDepth == currDepth && prevLength == currLength {
fncs.nonDefault = false
err = defMarshal(enc, va, mo)
} else {
err = errors.New("must not write any JSON tokens when skipping")
}
}

if err != nil {
err = wrapSkipFunc(err, "marshal method")
// TODO: Avoid wrapping semantic or I/O errors.
Expand Down Expand Up @@ -188,6 +198,7 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
switch which := implementsWhich(t, jsonUnmarshalerV2Type, jsonUnmarshalerV1Type, textUnmarshalerType); which {
case jsonUnmarshalerV2Type:
fncs.nonDefault = true
defUnmarshal := fncs.unmarshal
fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
xd := export.Decoder(dec)
prevDepth, prevLength := xd.Tokens.DepthLength()
Expand All @@ -198,6 +209,14 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil {
err = errors.New("must read exactly one JSON value")
}
if err == SkipFunc && defUnmarshal != nil {
if prevDepth == currDepth && prevLength == currLength {
fncs.nonDefault = false
err = defUnmarshal(dec, va, uo)
} else {
err = errors.New("must not read any JSON tokens when skipping")
}
}
if err != nil {
err = wrapSkipFunc(err, "unmarshal method")
// TODO: Avoid wrapping semantic, syntactic, or I/O errors.
Expand Down
270 changes: 260 additions & 10 deletions arshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ type (
Pointer *structAll
Interface any
}
structAllSkip structAll
structStringifiedAll struct {
Bool bool `json:",string"`
String string `json:",string"`
Expand Down Expand Up @@ -481,6 +482,13 @@ type (
}
)

func (s *structAllSkip) UnmarshalJSONV2(dec *jsontext.Decoder, opts Options) error {
return SkipFunc
}
func (s *structAllSkip) MarshalJSONV2(*jsontext.Encoder, Options) error {
return SkipFunc
}

func (p *allMethods) MarshalJSONV2(enc *jsontext.Encoder, opts Options) error {
if got, want := "MarshalJSONV2", p.method; got != want {
return fmt.Errorf("called wrong method: got %v, want %v", got, want)
Expand Down Expand Up @@ -3041,10 +3049,150 @@ func TestMarshal(t *testing.T) {
wantErr: &SemanticError{action: "marshal", GoType: marshalJSONv2FuncType, Err: errors.New("must write exactly one JSON value")},
}, {
name: jsontest.Name("Methods/Invalid/JSONv2/SkipFunc"),
in: marshalJSONv2Func(func(enc *jsontext.Encoder, opts Options) error {
return SkipFunc
}),
wantErr: &SemanticError{action: "marshal", GoType: marshalJSONv2FuncType, Err: errors.New("marshal method cannot be skipped")},
opts: []Options{jsontext.Expand(true)},
in: structAllSkip{
Bool: true,
String: "hello",
Bytes: []byte{1, 2, 3},
Int: -64,
Uint: +64,
Float: 3.14159,
Map: map[string]string{"key": "value"},
StructScalars: structScalars{
Bool: true,
String: "hello",
Bytes: []byte{1, 2, 3},
Int: -64,
Uint: +64,
Float: 3.14159,
},
StructMaps: structMaps{
MapBool: map[string]bool{"": true},
MapString: map[string]string{"": "hello"},
MapBytes: map[string][]byte{"": {1, 2, 3}},
MapInt: map[string]int64{"": -64},
MapUint: map[string]uint64{"": +64},
MapFloat: map[string]float64{"": 3.14159},
},
StructSlices: structSlices{
SliceBool: []bool{true},
SliceString: []string{"hello"},
SliceBytes: [][]byte{{1, 2, 3}},
SliceInt: []int64{-64},
SliceUint: []uint64{+64},
SliceFloat: []float64{3.14159},
},
Slice: []string{"fizz", "buzz"},
Array: [1]string{"goodbye"},
Pointer: new(structAll),
Interface: (*structAll)(nil),
},
want: `{
"Bool": true,
"String": "hello",
"Bytes": "AQID",
"Int": -64,
"Uint": 64,
"Float": 3.14159,
"Map": {
"key": "value"
},
"StructScalars": {
"Bool": true,
"String": "hello",
"Bytes": "AQID",
"Int": -64,
"Uint": 64,
"Float": 3.14159
},
"StructMaps": {
"MapBool": {
"": true
},
"MapString": {
"": "hello"
},
"MapBytes": {
"": "AQID"
},
"MapInt": {
"": -64
},
"MapUint": {
"": 64
},
"MapFloat": {
"": 3.14159
}
},
"StructSlices": {
"SliceBool": [
true
],
"SliceString": [
"hello"
],
"SliceBytes": [
"AQID"
],
"SliceInt": [
-64
],
"SliceUint": [
64
],
"SliceFloat": [
3.14159
]
},
"Slice": [
"fizz",
"buzz"
],
"Array": [
"goodbye"
],
"Pointer": {
"Bool": false,
"String": "",
"Bytes": "",
"Int": 0,
"Uint": 0,
"Float": 0,
"Map": {},
"StructScalars": {
"Bool": false,
"String": "",
"Bytes": "",
"Int": 0,
"Uint": 0,
"Float": 0
},
"StructMaps": {
"MapBool": {},
"MapString": {},
"MapBytes": {},
"MapInt": {},
"MapUint": {},
"MapFloat": {}
},
"StructSlices": {
"SliceBool": [],
"SliceString": [],
"SliceBytes": [],
"SliceInt": [],
"SliceUint": [],
"SliceFloat": []
},
"Slice": [],
"Array": [
""
],
"Pointer": null,
"Interface": null
},
"Interface": null
}`,
}, {
name: jsontest.Name("Methods/Invalid/JSONv1/Error"),
in: marshalJSONv1Func(func() ([]byte, error) {
Expand Down Expand Up @@ -7126,12 +7274,114 @@ func TestUnmarshal(t *testing.T) {
})),
wantErr: &SemanticError{action: "unmarshal", GoType: unmarshalJSONv2FuncType, Err: errors.New("must read exactly one JSON value")},
}, {
name: jsontest.Name("Methods/Invalid/JSONv2/SkipFunc"),
inBuf: `{}`,
inVal: addr(unmarshalJSONv2Func(func(*jsontext.Decoder, Options) error {
return SkipFunc
})),
wantErr: &SemanticError{action: "unmarshal", GoType: unmarshalJSONv2FuncType, Err: errors.New("unmarshal method cannot be skipped")},
name: jsontest.Name("Methods/Invalid/JSONv2/SkipFunc"),
inBuf: `{
"Bool": true,
"String": "hello",
"Bytes": "AQID",
"Int": -64,
"Uint": 64,
"Float": 3.14159,
"Map": {
"key": "value"
},
"StructScalars": {
"Bool": true,
"String": "hello",
"Bytes": "AQID",
"Int": -64,
"Uint": 64,
"Float": 3.14159
},
"StructMaps": {
"MapBool": {
"": true
},
"MapString": {
"": "hello"
},
"MapBytes": {
"": "AQID"
},
"MapInt": {
"": -64
},
"MapUint": {
"": 64
},
"MapFloat": {
"": 3.14159
}
},
"StructSlices": {
"SliceBool": [
true
],
"SliceString": [
"hello"
],
"SliceBytes": [
"AQID"
],
"SliceInt": [
-64
],
"SliceUint": [
64
],
"SliceFloat": [
3.14159
]
},
"Slice": [
"fizz",
"buzz"
],
"Array": [
"goodbye"
],
"Pointer": null,
"Interface": null
}`,
inVal: new(structAllSkip),
opts: []Options{},
want: &structAllSkip{
Bool: true,
String: "hello",
Bytes: []byte{1, 2, 3},
Int: -64,
Uint: +64,
Float: 3.14159,
Map: map[string]string{"key": "value"},
StructScalars: structScalars{
Bool: true,
String: "hello",
Bytes: []byte{1, 2, 3},
Int: -64,
Uint: +64,
Float: 3.14159,
},
StructMaps: structMaps{
MapBool: map[string]bool{"": true},
MapString: map[string]string{"": "hello"},
MapBytes: map[string][]byte{"": {1, 2, 3}},
MapInt: map[string]int64{"": -64},
MapUint: map[string]uint64{"": +64},
MapFloat: map[string]float64{"": 3.14159},
},
StructSlices: structSlices{
SliceBool: []bool{true},
SliceString: []string{"hello"},
SliceBytes: [][]byte{{1, 2, 3}},
SliceInt: []int64{-64},
SliceUint: []uint64{+64},
SliceFloat: []float64{3.14159},
},
Slice: []string{"fizz", "buzz"},
Array: [1]string{"goodbye"},
Pointer: nil,
},
wantErr: nil,
}, {
name: jsontest.Name("Methods/Invalid/JSONv1/Error"),
inBuf: `{}`,
Expand Down
Loading

0 comments on commit 6510be0

Please sign in to comment.