From 8d4029d9007377c31ecde0b97d2e16ed2d70bb9a Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Sat, 9 Jan 2021 20:14:34 +0900 Subject: [PATCH] Add int32/int64 test cases --- coverage_test.go | 1244 ++++++++++++++++++++++++++++++++++++++++++++++ encode_vm.go | 432 ++++++++++++++-- 2 files changed, 1630 insertions(+), 46 deletions(-) diff --git a/coverage_test.go b/coverage_test.go index 47a6c66..97bc9e1 100644 --- a/coverage_test.go +++ b/coverage_test.go @@ -9,6 +9,8 @@ import ( func intptr(v int) *int { return &v } func int8ptr(v int8) *int8 { return &v } func int16ptr(v int16) *int16 { return &v } +func int32ptr(v int32) *int32 { return &v } +func int64ptr(v int64) *int64 { return &v } func TestCoverStructHeadInt(t *testing.T) { type structInt struct { @@ -1873,3 +1875,1245 @@ func TestCoverStructHeadInt16(t *testing.T) { } } } + +func TestCoverStructHeadInt32(t *testing.T) { + type structInt32 struct { + A int32 `json:"a"` + } + type structInt32Ptr struct { + A *int32 `json:"a"` + } + + tests := []struct { + name string + expected string + data interface{} + }{ + { + name: "HeadInt32Zero", + expected: `{"a":0}`, + data: struct { + A int32 `json:"a"` + }{}, + }, + { + name: "HeadInt32", + expected: `{"a":1}`, + data: struct { + A int32 `json:"a"` + }{A: 1}, + }, + { + name: "HeadInt32Ptr", + expected: `{"a":1}`, + data: struct { + A *int32 `json:"a"` + }{A: int32ptr(1)}, + }, + { + name: "HeadInt32PtrNil", + expected: `{"a":null}`, + data: struct { + A *int32 `json:"a"` + }{A: nil}, + }, + { + name: "PtrHeadInt32Zero", + expected: `{"a":0}`, + data: &struct { + A int32 `json:"a"` + }{}, + }, + { + name: "PtrHeadInt32", + expected: `{"a":1}`, + data: &struct { + A int32 `json:"a"` + }{A: 1}, + }, + { + name: "PtrHeadInt32Ptr", + expected: `{"a":1}`, + data: &struct { + A *int32 `json:"a"` + }{A: int32ptr(1)}, + }, + { + name: "PtrHeadInt32PtrNil", + expected: `{"a":null}`, + data: &struct { + A *int32 `json:"a"` + }{A: nil}, + }, + { + name: "PtrHeadInt32Nil", + expected: `null`, + data: (*struct { + A *int32 `json:"a"` + })(nil), + }, + { + name: "HeadInt32ZeroMultiFields", + expected: `{"a":0,"b":0}`, + data: struct { + A int32 `json:"a"` + B int32 `json:"b"` + }{}, + }, + { + name: "HeadInt32MultiFields", + expected: `{"a":1,"b":2}`, + data: struct { + A int32 `json:"a"` + B int32 `json:"b"` + }{A: 1, B: 2}, + }, + { + name: "HeadInt32PtrMultiFields", + expected: `{"a":1,"b":2}`, + data: struct { + A *int32 `json:"a"` + B *int32 `json:"b"` + }{A: int32ptr(1), B: int32ptr(2)}, + }, + { + name: "HeadInt32PtrNilMultiFields", + expected: `{"a":null,"b":null}`, + data: struct { + A *int32 `json:"a"` + B *int32 `json:"b"` + }{A: nil, B: nil}, + }, + { + name: "PtrHeadInt32ZeroMultiFields", + expected: `{"a":0,"b":0}`, + data: &struct { + A int32 `json:"a"` + B int32 `json:"b"` + }{}, + }, + { + name: "PtrHeadInt32MultiFields", + expected: `{"a":1,"b":2}`, + data: &struct { + A int32 `json:"a"` + B int32 `json:"b"` + }{A: 1, B: 2}, + }, + { + name: "PtrHeadInt32PtrMultiFields", + expected: `{"a":1,"b":2}`, + data: &struct { + A *int32 `json:"a"` + B *int32 `json:"b"` + }{A: int32ptr(1), B: int32ptr(2)}, + }, + { + name: "PtrHeadInt32PtrNilMultiFields", + expected: `{"a":null,"b":null}`, + data: &struct { + A *int32 `json:"a"` + B *int32 `json:"b"` + }{A: nil, B: nil}, + }, + { + name: "PtrHeadInt32NilMultiFields", + expected: `null`, + data: (*struct { + A *int32 `json:"a"` + B *int32 `json:"b"` + })(nil), + }, + { + name: "HeadInt32ZeroNotRoot", + expected: `{"A":{"a":0}}`, + data: struct { + A struct { + A int32 `json:"a"` + } + }{}, + }, + { + name: "HeadInt32NotRoot", + expected: `{"A":{"a":1}}`, + data: struct { + A struct { + A int32 `json:"a"` + } + }{A: struct { + A int32 `json:"a"` + }{A: 1}}, + }, + { + name: "HeadInt32PtrNotRoot", + expected: `{"A":{"a":1}}`, + data: struct { + A struct { + A *int32 `json:"a"` + } + }{A: struct { + A *int32 `json:"a"` + }{int32ptr(1)}}, + }, + { + name: "HeadInt32PtrNilNotRoot", + expected: `{"A":{"a":null}}`, + data: struct { + A struct { + A *int32 `json:"a"` + } + }{}, + }, + { + name: "PtrHeadInt32ZeroNotRoot", + expected: `{"A":{"a":0}}`, + data: struct { + A *struct { + A int32 `json:"a"` + } + }{A: new(struct { + A int32 `json:"a"` + })}, + }, + { + name: "PtrHeadInt32NotRoot", + expected: `{"A":{"a":1}}`, + data: struct { + A *struct { + A int32 `json:"a"` + } + }{A: &(struct { + A int32 `json:"a"` + }{A: 1})}, + }, + { + name: "PtrHeadInt32PtrNotRoot", + expected: `{"A":{"a":1}}`, + data: struct { + A *struct { + A *int32 `json:"a"` + } + }{A: &(struct { + A *int32 `json:"a"` + }{A: int32ptr(1)})}, + }, + { + name: "PtrHeadInt32PtrNilNotRoot", + expected: `{"A":{"a":null}}`, + data: struct { + A *struct { + A *int32 `json:"a"` + } + }{A: &(struct { + A *int32 `json:"a"` + }{A: nil})}, + }, + { + name: "PtrHeadInt32NilNotRoot", + expected: `{"A":null}`, + data: struct { + A *struct { + A *int32 `json:"a"` + } + }{A: nil}, + }, + { + name: "HeadInt32ZeroMultiFieldsNotRoot", + expected: `{"A":{"a":0},"B":{"b":0}}`, + data: struct { + A struct { + A int32 `json:"a"` + } + B struct { + B int32 `json:"b"` + } + }{}, + }, + { + name: "HeadInt32MultiFieldsNotRoot", + expected: `{"A":{"a":1},"B":{"b":2}}`, + data: struct { + A struct { + A int32 `json:"a"` + } + B struct { + B int32 `json:"b"` + } + }{A: struct { + A int32 `json:"a"` + }{A: 1}, B: struct { + B int32 `json:"b"` + }{B: 2}}, + }, + { + name: "HeadInt32PtrMultiFieldsNotRoot", + expected: `{"A":{"a":1},"B":{"b":2}}`, + data: struct { + A struct { + A *int32 `json:"a"` + } + B struct { + B *int32 `json:"b"` + } + }{A: struct { + A *int32 `json:"a"` + }{A: int32ptr(1)}, B: struct { + B *int32 `json:"b"` + }{B: int32ptr(2)}}, + }, + { + name: "HeadInt32PtrNilMultiFieldsNotRoot", + expected: `{"A":{"a":null},"B":{"b":null}}`, + data: struct { + A struct { + A *int32 `json:"a"` + } + B struct { + B *int32 `json:"b"` + } + }{A: struct { + A *int32 `json:"a"` + }{A: nil}, B: struct { + B *int32 `json:"b"` + }{B: nil}}, + }, + { + name: "PtrHeadInt32ZeroMultiFieldsNotRoot", + expected: `{"A":{"a":0},"B":{"b":0}}`, + data: &struct { + A struct { + A int32 `json:"a"` + } + B struct { + B int32 `json:"b"` + } + }{}, + }, + { + name: "PtrHeadInt32MultiFieldsNotRoot", + expected: `{"A":{"a":1},"B":{"b":2}}`, + data: &struct { + A struct { + A int32 `json:"a"` + } + B struct { + B int32 `json:"b"` + } + }{A: struct { + A int32 `json:"a"` + }{A: 1}, B: struct { + B int32 `json:"b"` + }{B: 2}}, + }, + { + name: "PtrHeadInt32PtrMultiFieldsNotRoot", + expected: `{"A":{"a":1},"B":{"b":2}}`, + data: &struct { + A *struct { + A *int32 `json:"a"` + } + B *struct { + B *int32 `json:"b"` + } + }{A: &(struct { + A *int32 `json:"a"` + }{A: int32ptr(1)}), B: &(struct { + B *int32 `json:"b"` + }{B: int32ptr(2)})}, + }, + { + name: "PtrHeadInt32PtrNilMultiFieldsNotRoot", + expected: `{"A":null,"B":null}`, + data: &struct { + A *struct { + A *int32 `json:"a"` + } + B *struct { + B *int32 `json:"b"` + } + }{A: nil, B: nil}, + }, + { + name: "PtrHeadInt32NilMultiFieldsNotRoot", + expected: `null`, + data: (*struct { + A *struct { + A *int32 `json:"a"` + } + B *struct { + B *int32 `json:"b"` + } + })(nil), + }, + { + name: "PtrHeadInt32DoubleMultiFieldsNotRoot", + expected: `{"A":{"a":1,"b":2},"B":{"a":3,"b":4}}`, + data: &struct { + A *struct { + A int32 `json:"a"` + B int32 `json:"b"` + } + B *struct { + A int32 `json:"a"` + B int32 `json:"b"` + } + }{A: &(struct { + A int32 `json:"a"` + B int32 `json:"b"` + }{A: 1, B: 2}), B: &(struct { + A int32 `json:"a"` + B int32 `json:"b"` + }{A: 3, B: 4})}, + }, + { + name: "PtrHeadInt32NilDoubleMultiFieldsNotRoot", + expected: `{"A":null,"B":null}`, + data: &struct { + A *struct { + A int32 `json:"a"` + B int32 `json:"b"` + } + B *struct { + A int32 `json:"a"` + B int32 `json:"b"` + } + }{A: nil, B: nil}, + }, + { + name: "PtrHeadInt32NilDoubleMultiFieldsNotRoot", + expected: `null`, + data: (*struct { + A *struct { + A int32 `json:"a"` + B int32 `json:"b"` + } + B *struct { + A int32 `json:"a"` + B int32 `json:"b"` + } + })(nil), + }, + { + name: "PtrHeadInt32PtrDoubleMultiFieldsNotRoot", + expected: `{"A":{"a":1,"b":2},"B":{"a":3,"b":4}}`, + data: &struct { + A *struct { + A *int32 `json:"a"` + B *int32 `json:"b"` + } + B *struct { + A *int32 `json:"a"` + B *int32 `json:"b"` + } + }{A: &(struct { + A *int32 `json:"a"` + B *int32 `json:"b"` + }{A: int32ptr(1), B: int32ptr(2)}), B: &(struct { + A *int32 `json:"a"` + B *int32 `json:"b"` + }{A: int32ptr(3), B: int32ptr(4)})}, + }, + { + name: "PtrHeadInt32PtrNilDoubleMultiFieldsNotRoot", + expected: `{"A":null,"B":null}`, + data: &struct { + A *struct { + A *int32 `json:"a"` + B *int32 `json:"b"` + } + B *struct { + A *int32 `json:"a"` + B *int32 `json:"b"` + } + }{A: nil, B: nil}, + }, + { + name: "PtrHeadInt32PtrNilDoubleMultiFieldsNotRoot", + expected: `null`, + data: (*struct { + A *struct { + A *int32 `json:"a"` + B *int32 `json:"b"` + } + B *struct { + A *int32 `json:"a"` + B *int32 `json:"b"` + } + })(nil), + }, + { + name: "AnonymousHeadInt32", + expected: `{"a":1,"b":2}`, + data: struct { + structInt32 + B int32 `json:"b"` + }{ + structInt32: structInt32{A: 1}, + B: 2, + }, + }, + { + name: "PtrAnonymousHeadInt32", + expected: `{"a":1,"b":2}`, + data: struct { + *structInt32 + B int32 `json:"b"` + }{ + structInt32: &structInt32{A: 1}, + B: 2, + }, + }, + { + name: "NilPtrAnonymousHeadInt32", + expected: `{"b":2}`, + data: struct { + *structInt32 + B int32 `json:"b"` + }{ + structInt32: nil, + B: 2, + }, + }, + { + name: "AnonymousHeadInt32Ptr", + expected: `{"a":1,"b":2}`, + data: struct { + structInt32Ptr + B *int32 `json:"b"` + }{ + structInt32Ptr: structInt32Ptr{A: int32ptr(1)}, + B: int32ptr(2), + }, + }, + { + name: "AnonymousHeadInt32PtrNil", + expected: `{"a":null,"b":2}`, + data: struct { + structInt32Ptr + B *int32 `json:"b"` + }{ + structInt32Ptr: structInt32Ptr{A: nil}, + B: int32ptr(2), + }, + }, + { + name: "PtrAnonymousHeadInt32Ptr", + expected: `{"a":1,"b":2}`, + data: struct { + *structInt32Ptr + B *int32 `json:"b"` + }{ + structInt32Ptr: &structInt32Ptr{A: int32ptr(1)}, + B: int32ptr(2), + }, + }, + { + name: "NilPtrAnonymousHeadInt32Ptr", + expected: `{"b":2}`, + data: struct { + *structInt32Ptr + B *int32 `json:"b"` + }{ + structInt32Ptr: nil, + B: int32ptr(2), + }, + }, + { + name: "AnonymousHeadInt32Only", + expected: `{"a":1}`, + data: struct { + structInt32 + }{ + structInt32: structInt32{A: 1}, + }, + }, + { + name: "PtrAnonymousHeadInt32Only", + expected: `{"a":1}`, + data: struct { + *structInt32 + }{ + structInt32: &structInt32{A: 1}, + }, + }, + { + name: "NilPtrAnonymousHeadInt32Only", + expected: `{}`, + data: struct { + *structInt32 + }{ + structInt32: nil, + }, + }, + { + name: "AnonymousHeadInt32PtrOnly", + expected: `{"a":1}`, + data: struct { + structInt32Ptr + }{ + structInt32Ptr: structInt32Ptr{A: int32ptr(1)}, + }, + }, + { + name: "AnonymousHeadInt32PtrNilOnly", + expected: `{"a":null}`, + data: struct { + structInt32Ptr + }{ + structInt32Ptr: structInt32Ptr{A: nil}, + }, + }, + { + name: "PtrAnonymousHeadInt32PtrOnly", + expected: `{"a":1}`, + data: struct { + *structInt32Ptr + }{ + structInt32Ptr: &structInt32Ptr{A: int32ptr(1)}, + }, + }, + { + name: "NilPtrAnonymousHeadInt32PtrOnly", + expected: `{}`, + data: struct { + *structInt32Ptr + }{ + structInt32Ptr: nil, + }, + }, + } + for _, test := range tests { + for _, htmlEscape := range []bool{true, false} { + var buf bytes.Buffer + enc := NewEncoder(&buf) + enc.SetEscapeHTML(htmlEscape) + if err := enc.Encode(test.data); err != nil { + t.Fatalf("%s(htmlEscape:%T): %s: %s", test.name, htmlEscape, test.expected, err) + } + if strings.TrimRight(buf.String(), "\n") != test.expected { + t.Fatalf("%s(htmlEscape:%T): expected %q but got %q", test.name, htmlEscape, test.expected, buf.String()) + } + } + } +} + +func TestCoverStructHeadInt64(t *testing.T) { + type structInt64 struct { + A int64 `json:"a"` + } + type structInt64Ptr struct { + A *int64 `json:"a"` + } + + tests := []struct { + name string + expected string + data interface{} + }{ + { + name: "HeadInt64Zero", + expected: `{"a":0}`, + data: struct { + A int64 `json:"a"` + }{}, + }, + { + name: "HeadInt64", + expected: `{"a":1}`, + data: struct { + A int64 `json:"a"` + }{A: 1}, + }, + { + name: "HeadInt64Ptr", + expected: `{"a":1}`, + data: struct { + A *int64 `json:"a"` + }{A: int64ptr(1)}, + }, + { + name: "HeadInt64PtrNil", + expected: `{"a":null}`, + data: struct { + A *int64 `json:"a"` + }{A: nil}, + }, + { + name: "PtrHeadInt64Zero", + expected: `{"a":0}`, + data: &struct { + A int64 `json:"a"` + }{}, + }, + { + name: "PtrHeadInt64", + expected: `{"a":1}`, + data: &struct { + A int64 `json:"a"` + }{A: 1}, + }, + { + name: "PtrHeadInt64Ptr", + expected: `{"a":1}`, + data: &struct { + A *int64 `json:"a"` + }{A: int64ptr(1)}, + }, + { + name: "PtrHeadInt64PtrNil", + expected: `{"a":null}`, + data: &struct { + A *int64 `json:"a"` + }{A: nil}, + }, + { + name: "PtrHeadInt64Nil", + expected: `null`, + data: (*struct { + A *int64 `json:"a"` + })(nil), + }, + { + name: "HeadInt64ZeroMultiFields", + expected: `{"a":0,"b":0}`, + data: struct { + A int64 `json:"a"` + B int64 `json:"b"` + }{}, + }, + { + name: "HeadInt64MultiFields", + expected: `{"a":1,"b":2}`, + data: struct { + A int64 `json:"a"` + B int64 `json:"b"` + }{A: 1, B: 2}, + }, + { + name: "HeadInt64PtrMultiFields", + expected: `{"a":1,"b":2}`, + data: struct { + A *int64 `json:"a"` + B *int64 `json:"b"` + }{A: int64ptr(1), B: int64ptr(2)}, + }, + { + name: "HeadInt64PtrNilMultiFields", + expected: `{"a":null,"b":null}`, + data: struct { + A *int64 `json:"a"` + B *int64 `json:"b"` + }{A: nil, B: nil}, + }, + { + name: "PtrHeadInt64ZeroMultiFields", + expected: `{"a":0,"b":0}`, + data: &struct { + A int64 `json:"a"` + B int64 `json:"b"` + }{}, + }, + { + name: "PtrHeadInt64MultiFields", + expected: `{"a":1,"b":2}`, + data: &struct { + A int64 `json:"a"` + B int64 `json:"b"` + }{A: 1, B: 2}, + }, + { + name: "PtrHeadInt64PtrMultiFields", + expected: `{"a":1,"b":2}`, + data: &struct { + A *int64 `json:"a"` + B *int64 `json:"b"` + }{A: int64ptr(1), B: int64ptr(2)}, + }, + { + name: "PtrHeadInt64PtrNilMultiFields", + expected: `{"a":null,"b":null}`, + data: &struct { + A *int64 `json:"a"` + B *int64 `json:"b"` + }{A: nil, B: nil}, + }, + { + name: "PtrHeadInt64NilMultiFields", + expected: `null`, + data: (*struct { + A *int64 `json:"a"` + B *int64 `json:"b"` + })(nil), + }, + { + name: "HeadInt64ZeroNotRoot", + expected: `{"A":{"a":0}}`, + data: struct { + A struct { + A int64 `json:"a"` + } + }{}, + }, + { + name: "HeadInt64NotRoot", + expected: `{"A":{"a":1}}`, + data: struct { + A struct { + A int64 `json:"a"` + } + }{A: struct { + A int64 `json:"a"` + }{A: 1}}, + }, + { + name: "HeadInt64PtrNotRoot", + expected: `{"A":{"a":1}}`, + data: struct { + A struct { + A *int64 `json:"a"` + } + }{A: struct { + A *int64 `json:"a"` + }{int64ptr(1)}}, + }, + { + name: "HeadInt64PtrNilNotRoot", + expected: `{"A":{"a":null}}`, + data: struct { + A struct { + A *int64 `json:"a"` + } + }{}, + }, + { + name: "PtrHeadInt64ZeroNotRoot", + expected: `{"A":{"a":0}}`, + data: struct { + A *struct { + A int64 `json:"a"` + } + }{A: new(struct { + A int64 `json:"a"` + })}, + }, + { + name: "PtrHeadInt64NotRoot", + expected: `{"A":{"a":1}}`, + data: struct { + A *struct { + A int64 `json:"a"` + } + }{A: &(struct { + A int64 `json:"a"` + }{A: 1})}, + }, + { + name: "PtrHeadInt64PtrNotRoot", + expected: `{"A":{"a":1}}`, + data: struct { + A *struct { + A *int64 `json:"a"` + } + }{A: &(struct { + A *int64 `json:"a"` + }{A: int64ptr(1)})}, + }, + { + name: "PtrHeadInt64PtrNilNotRoot", + expected: `{"A":{"a":null}}`, + data: struct { + A *struct { + A *int64 `json:"a"` + } + }{A: &(struct { + A *int64 `json:"a"` + }{A: nil})}, + }, + { + name: "PtrHeadInt64NilNotRoot", + expected: `{"A":null}`, + data: struct { + A *struct { + A *int64 `json:"a"` + } + }{A: nil}, + }, + { + name: "HeadInt64ZeroMultiFieldsNotRoot", + expected: `{"A":{"a":0},"B":{"b":0}}`, + data: struct { + A struct { + A int64 `json:"a"` + } + B struct { + B int64 `json:"b"` + } + }{}, + }, + { + name: "HeadInt64MultiFieldsNotRoot", + expected: `{"A":{"a":1},"B":{"b":2}}`, + data: struct { + A struct { + A int64 `json:"a"` + } + B struct { + B int64 `json:"b"` + } + }{A: struct { + A int64 `json:"a"` + }{A: 1}, B: struct { + B int64 `json:"b"` + }{B: 2}}, + }, + { + name: "HeadInt64PtrMultiFieldsNotRoot", + expected: `{"A":{"a":1},"B":{"b":2}}`, + data: struct { + A struct { + A *int64 `json:"a"` + } + B struct { + B *int64 `json:"b"` + } + }{A: struct { + A *int64 `json:"a"` + }{A: int64ptr(1)}, B: struct { + B *int64 `json:"b"` + }{B: int64ptr(2)}}, + }, + { + name: "HeadInt64PtrNilMultiFieldsNotRoot", + expected: `{"A":{"a":null},"B":{"b":null}}`, + data: struct { + A struct { + A *int64 `json:"a"` + } + B struct { + B *int64 `json:"b"` + } + }{A: struct { + A *int64 `json:"a"` + }{A: nil}, B: struct { + B *int64 `json:"b"` + }{B: nil}}, + }, + { + name: "PtrHeadInt64ZeroMultiFieldsNotRoot", + expected: `{"A":{"a":0},"B":{"b":0}}`, + data: &struct { + A struct { + A int64 `json:"a"` + } + B struct { + B int64 `json:"b"` + } + }{}, + }, + { + name: "PtrHeadInt64MultiFieldsNotRoot", + expected: `{"A":{"a":1},"B":{"b":2}}`, + data: &struct { + A struct { + A int64 `json:"a"` + } + B struct { + B int64 `json:"b"` + } + }{A: struct { + A int64 `json:"a"` + }{A: 1}, B: struct { + B int64 `json:"b"` + }{B: 2}}, + }, + { + name: "PtrHeadInt64PtrMultiFieldsNotRoot", + expected: `{"A":{"a":1},"B":{"b":2}}`, + data: &struct { + A *struct { + A *int64 `json:"a"` + } + B *struct { + B *int64 `json:"b"` + } + }{A: &(struct { + A *int64 `json:"a"` + }{A: int64ptr(1)}), B: &(struct { + B *int64 `json:"b"` + }{B: int64ptr(2)})}, + }, + { + name: "PtrHeadInt64PtrNilMultiFieldsNotRoot", + expected: `{"A":null,"B":null}`, + data: &struct { + A *struct { + A *int64 `json:"a"` + } + B *struct { + B *int64 `json:"b"` + } + }{A: nil, B: nil}, + }, + { + name: "PtrHeadInt64NilMultiFieldsNotRoot", + expected: `null`, + data: (*struct { + A *struct { + A *int64 `json:"a"` + } + B *struct { + B *int64 `json:"b"` + } + })(nil), + }, + { + name: "PtrHeadInt64DoubleMultiFieldsNotRoot", + expected: `{"A":{"a":1,"b":2},"B":{"a":3,"b":4}}`, + data: &struct { + A *struct { + A int64 `json:"a"` + B int64 `json:"b"` + } + B *struct { + A int64 `json:"a"` + B int64 `json:"b"` + } + }{A: &(struct { + A int64 `json:"a"` + B int64 `json:"b"` + }{A: 1, B: 2}), B: &(struct { + A int64 `json:"a"` + B int64 `json:"b"` + }{A: 3, B: 4})}, + }, + { + name: "PtrHeadInt64NilDoubleMultiFieldsNotRoot", + expected: `{"A":null,"B":null}`, + data: &struct { + A *struct { + A int64 `json:"a"` + B int64 `json:"b"` + } + B *struct { + A int64 `json:"a"` + B int64 `json:"b"` + } + }{A: nil, B: nil}, + }, + { + name: "PtrHeadInt64NilDoubleMultiFieldsNotRoot", + expected: `null`, + data: (*struct { + A *struct { + A int64 `json:"a"` + B int64 `json:"b"` + } + B *struct { + A int64 `json:"a"` + B int64 `json:"b"` + } + })(nil), + }, + { + name: "PtrHeadInt64PtrDoubleMultiFieldsNotRoot", + expected: `{"A":{"a":1,"b":2},"B":{"a":3,"b":4}}`, + data: &struct { + A *struct { + A *int64 `json:"a"` + B *int64 `json:"b"` + } + B *struct { + A *int64 `json:"a"` + B *int64 `json:"b"` + } + }{A: &(struct { + A *int64 `json:"a"` + B *int64 `json:"b"` + }{A: int64ptr(1), B: int64ptr(2)}), B: &(struct { + A *int64 `json:"a"` + B *int64 `json:"b"` + }{A: int64ptr(3), B: int64ptr(4)})}, + }, + { + name: "PtrHeadInt64PtrNilDoubleMultiFieldsNotRoot", + expected: `{"A":null,"B":null}`, + data: &struct { + A *struct { + A *int64 `json:"a"` + B *int64 `json:"b"` + } + B *struct { + A *int64 `json:"a"` + B *int64 `json:"b"` + } + }{A: nil, B: nil}, + }, + { + name: "PtrHeadInt64PtrNilDoubleMultiFieldsNotRoot", + expected: `null`, + data: (*struct { + A *struct { + A *int64 `json:"a"` + B *int64 `json:"b"` + } + B *struct { + A *int64 `json:"a"` + B *int64 `json:"b"` + } + })(nil), + }, + { + name: "AnonymousHeadInt64", + expected: `{"a":1,"b":2}`, + data: struct { + structInt64 + B int64 `json:"b"` + }{ + structInt64: structInt64{A: 1}, + B: 2, + }, + }, + { + name: "PtrAnonymousHeadInt64", + expected: `{"a":1,"b":2}`, + data: struct { + *structInt64 + B int64 `json:"b"` + }{ + structInt64: &structInt64{A: 1}, + B: 2, + }, + }, + { + name: "NilPtrAnonymousHeadInt64", + expected: `{"b":2}`, + data: struct { + *structInt64 + B int64 `json:"b"` + }{ + structInt64: nil, + B: 2, + }, + }, + { + name: "AnonymousHeadInt64Ptr", + expected: `{"a":1,"b":2}`, + data: struct { + structInt64Ptr + B *int64 `json:"b"` + }{ + structInt64Ptr: structInt64Ptr{A: int64ptr(1)}, + B: int64ptr(2), + }, + }, + { + name: "AnonymousHeadInt64PtrNil", + expected: `{"a":null,"b":2}`, + data: struct { + structInt64Ptr + B *int64 `json:"b"` + }{ + structInt64Ptr: structInt64Ptr{A: nil}, + B: int64ptr(2), + }, + }, + { + name: "PtrAnonymousHeadInt64Ptr", + expected: `{"a":1,"b":2}`, + data: struct { + *structInt64Ptr + B *int64 `json:"b"` + }{ + structInt64Ptr: &structInt64Ptr{A: int64ptr(1)}, + B: int64ptr(2), + }, + }, + { + name: "NilPtrAnonymousHeadInt64Ptr", + expected: `{"b":2}`, + data: struct { + *structInt64Ptr + B *int64 `json:"b"` + }{ + structInt64Ptr: nil, + B: int64ptr(2), + }, + }, + { + name: "AnonymousHeadInt64Only", + expected: `{"a":1}`, + data: struct { + structInt64 + }{ + structInt64: structInt64{A: 1}, + }, + }, + { + name: "PtrAnonymousHeadInt64Only", + expected: `{"a":1}`, + data: struct { + *structInt64 + }{ + structInt64: &structInt64{A: 1}, + }, + }, + { + name: "NilPtrAnonymousHeadInt64Only", + expected: `{}`, + data: struct { + *structInt64 + }{ + structInt64: nil, + }, + }, + { + name: "AnonymousHeadInt64PtrOnly", + expected: `{"a":1}`, + data: struct { + structInt64Ptr + }{ + structInt64Ptr: structInt64Ptr{A: int64ptr(1)}, + }, + }, + { + name: "AnonymousHeadInt64PtrNilOnly", + expected: `{"a":null}`, + data: struct { + structInt64Ptr + }{ + structInt64Ptr: structInt64Ptr{A: nil}, + }, + }, + { + name: "PtrAnonymousHeadInt64PtrOnly", + expected: `{"a":1}`, + data: struct { + *structInt64Ptr + }{ + structInt64Ptr: &structInt64Ptr{A: int64ptr(1)}, + }, + }, + { + name: "NilPtrAnonymousHeadInt64PtrOnly", + expected: `{}`, + data: struct { + *structInt64Ptr + }{ + structInt64Ptr: nil, + }, + }, + } + for _, test := range tests { + for _, htmlEscape := range []bool{true, false} { + var buf bytes.Buffer + enc := NewEncoder(&buf) + enc.SetEscapeHTML(htmlEscape) + if err := enc.Encode(test.data); err != nil { + t.Fatalf("%s(htmlEscape:%T): %s: %s", test.name, htmlEscape, test.expected, err) + } + if strings.TrimRight(buf.String(), "\n") != test.expected { + t.Fatalf("%s(htmlEscape:%T): expected %q but got %q", test.name, htmlEscape, test.expected, buf.String()) + } + } + } +} diff --git a/encode_vm.go b/encode_vm.go index 52b17d9..1696f7e 100644 --- a/encode_vm.go +++ b/encode_vm.go @@ -2039,24 +2039,13 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte b = encodeComma(b) code = code.next case opStructFieldPtrHeadInt32: - p := load(ctxptr, code.idx) - if p == 0 { - b = encodeNull(b) - b = encodeComma(b) - code = code.end.next - break - } - store(ctxptr, code.idx, e.ptrToPtr(p)) + store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) fallthrough case opStructFieldHeadInt32: ptr := load(ctxptr, code.idx) if ptr == 0 { - if code.op == opStructFieldPtrHeadInt32 { - b = encodeNull(b) - b = encodeComma(b) - } else { - b = append(b, '{', '}', ',') - } + b = encodeNull(b) + b = encodeComma(b) code = code.end.next } else { b = append(b, '{') @@ -2065,7 +2054,59 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte b = encodeComma(b) code = code.next } + case opStructFieldPtrHeadInt32Only, opStructFieldHeadInt32Only: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.key...) + b = appendInt(b, int64(e.ptrToInt32(p))) + b = encodeComma(b) + code = code.next case opStructEscapedFieldPtrHeadInt32: + store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) + fallthrough + case opStructEscapedFieldHeadInt32: + ptr := load(ctxptr, code.idx) + if ptr == 0 { + b = encodeNull(b) + b = encodeComma(b) + code = code.end.next + } else { + b = append(b, '{') + b = append(b, code.escapedKey...) + b = appendInt(b, int64(e.ptrToInt32(ptr+code.offset))) + b = encodeComma(b) + code = code.next + } + case opStructEscapedFieldPtrHeadInt32Only, opStructEscapedFieldHeadInt32Only: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.escapedKey...) + b = appendInt(b, int64(e.ptrToInt32(p))) + b = encodeComma(b) + code = code.next + case opStructFieldPtrHeadInt32Ptr: + store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) + fallthrough + case opStructFieldHeadInt32Ptr: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) + b = encodeComma(b) + code = code.end.next + break + } else { + b = append(b, '{') + b = append(b, code.key...) + p = e.ptrToPtr(p) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, int64(e.ptrToInt32(p+code.offset))) + } + } + b = encodeComma(b) + code = code.next + case opStructFieldPtrHeadInt32PtrOnly: p := load(ctxptr, code.idx) if p == 0 { b = encodeNull(b) @@ -2075,23 +2116,60 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte } store(ctxptr, code.idx, e.ptrToPtr(p)) fallthrough - case opStructEscapedFieldHeadInt32: - ptr := load(ctxptr, code.idx) - if ptr == 0 { - if code.op == opStructEscapedFieldPtrHeadInt32 { - b = encodeNull(b) - b = encodeComma(b) - } else { - b = append(b, '{', '}', ',') - } + case opStructFieldHeadInt32PtrOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.key...) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, int64(e.ptrToInt32(p+code.offset))) + } + b = encodeComma(b) + code = code.next + case opStructEscapedFieldPtrHeadInt32Ptr: + store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) + fallthrough + case opStructEscapedFieldHeadInt32Ptr: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) + b = encodeComma(b) code = code.end.next + break } else { b = append(b, '{') b = append(b, code.escapedKey...) - b = appendInt(b, int64(e.ptrToInt32(ptr+code.offset))) - b = encodeComma(b) - code = code.next + p = e.ptrToPtr(p) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, int64(e.ptrToInt32(p+code.offset))) + } } + b = encodeComma(b) + code = code.next + case opStructEscapedFieldPtrHeadInt32PtrOnly: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) + b = encodeComma(b) + code = code.end.next + break + } + store(ctxptr, code.idx, e.ptrToPtr(p)) + fallthrough + case opStructEscapedFieldHeadInt32PtrOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.escapedKey...) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, int64(e.ptrToInt32(p+code.offset))) + } + b = encodeComma(b) + code = code.next case opStructFieldPtrAnonymousHeadInt32: store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) fallthrough @@ -2118,25 +2196,106 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte b = encodeComma(b) code = code.next } - case opStructFieldPtrHeadInt64: + case opStructFieldPtrAnonymousHeadInt32Only, opStructFieldAnonymousHeadInt32Only: + ptr := load(ctxptr, code.idx) + if ptr == 0 { + code = code.end.next + } else { + b = append(b, code.key...) + b = appendInt(b, int64(e.ptrToInt32(ptr+code.offset))) + b = encodeComma(b) + code = code.next + } + case opStructEscapedFieldPtrAnonymousHeadInt32Only, opStructEscapedFieldAnonymousHeadInt32Only: + ptr := load(ctxptr, code.idx) + if ptr == 0 { + code = code.end.next + } else { + b = append(b, code.escapedKey...) + b = appendInt(b, int64(e.ptrToInt32(ptr+code.offset))) + b = encodeComma(b) + code = code.next + } + case opStructFieldPtrAnonymousHeadInt32Ptr: + store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) + fallthrough + case opStructFieldAnonymousHeadInt32Ptr: p := load(ctxptr, code.idx) + if p == 0 { + code = code.end.next + break + } + b = append(b, code.key...) + p = e.ptrToPtr(p) if p == 0 { b = encodeNull(b) - b = encodeComma(b) + } else { + b = appendInt(b, int64(e.ptrToInt32(p+code.offset))) + } + b = encodeComma(b) + code = code.next + case opStructEscapedFieldPtrAnonymousHeadInt32Ptr: + store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) + fallthrough + case opStructEscapedFieldAnonymousHeadInt32Ptr: + p := load(ctxptr, code.idx) + if p == 0 { + code = code.end.next + break + } + b = append(b, code.escapedKey...) + p = e.ptrToPtr(p) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, int64(e.ptrToInt32(p+code.offset))) + } + b = encodeComma(b) + code = code.next + case opStructFieldPtrAnonymousHeadInt32PtrOnly: + p := load(ctxptr, code.idx) + if p == 0 { code = code.end.next break } store(ctxptr, code.idx, e.ptrToPtr(p)) fallthrough + case opStructFieldAnonymousHeadInt32PtrOnly: + p := load(ctxptr, code.idx) + b = append(b, code.key...) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, int64(e.ptrToInt32(p+code.offset))) + } + b = encodeComma(b) + code = code.next + case opStructEscapedFieldPtrAnonymousHeadInt32PtrOnly: + p := load(ctxptr, code.idx) + if p == 0 { + code = code.end.next + break + } + store(ctxptr, code.idx, e.ptrToPtr(p)) + fallthrough + case opStructEscapedFieldAnonymousHeadInt32PtrOnly: + p := load(ctxptr, code.idx) + b = append(b, code.escapedKey...) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, int64(e.ptrToInt32(p+code.offset))) + } + b = encodeComma(b) + code = code.next + case opStructFieldPtrHeadInt64: + store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) + fallthrough case opStructFieldHeadInt64: ptr := load(ctxptr, code.idx) if ptr == 0 { - if code.op == opStructFieldPtrHeadInt64 { - b = encodeNull(b) - b = encodeComma(b) - } else { - b = append(b, '{', '}', ',') - } + b = encodeNull(b) + b = encodeComma(b) code = code.end.next } else { b = append(b, '{') @@ -2145,7 +2304,59 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte b = encodeComma(b) code = code.next } + case opStructFieldPtrHeadInt64Only, opStructFieldHeadInt64Only: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.key...) + b = appendInt(b, e.ptrToInt64(p)) + b = encodeComma(b) + code = code.next case opStructEscapedFieldPtrHeadInt64: + store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) + fallthrough + case opStructEscapedFieldHeadInt64: + ptr := load(ctxptr, code.idx) + if ptr == 0 { + b = encodeNull(b) + b = encodeComma(b) + code = code.end.next + } else { + b = append(b, '{') + b = append(b, code.escapedKey...) + b = appendInt(b, e.ptrToInt64(ptr+code.offset)) + b = encodeComma(b) + code = code.next + } + case opStructEscapedFieldPtrHeadInt64Only, opStructEscapedFieldHeadInt64Only: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.escapedKey...) + b = appendInt(b, e.ptrToInt64(p)) + b = encodeComma(b) + code = code.next + case opStructFieldPtrHeadInt64Ptr: + store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) + fallthrough + case opStructFieldHeadInt64Ptr: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) + b = encodeComma(b) + code = code.end.next + break + } else { + b = append(b, '{') + b = append(b, code.key...) + p = e.ptrToPtr(p) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, e.ptrToInt64(p+code.offset)) + } + } + b = encodeComma(b) + code = code.next + case opStructFieldPtrHeadInt64PtrOnly: p := load(ctxptr, code.idx) if p == 0 { b = encodeNull(b) @@ -2155,23 +2366,60 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte } store(ctxptr, code.idx, e.ptrToPtr(p)) fallthrough - case opStructEscapedFieldHeadInt64: - ptr := load(ctxptr, code.idx) - if ptr == 0 { - if code.op == opStructEscapedFieldPtrHeadInt64 { - b = encodeNull(b) - b = encodeComma(b) - } else { - b = append(b, '{', '}', ',') - } + case opStructFieldHeadInt64PtrOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.key...) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, e.ptrToInt64(p+code.offset)) + } + b = encodeComma(b) + code = code.next + case opStructEscapedFieldPtrHeadInt64Ptr: + store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) + fallthrough + case opStructEscapedFieldHeadInt64Ptr: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) + b = encodeComma(b) code = code.end.next + break } else { b = append(b, '{') b = append(b, code.escapedKey...) - b = appendInt(b, e.ptrToInt64(ptr+code.offset)) - b = encodeComma(b) - code = code.next + p = e.ptrToPtr(p) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, e.ptrToInt64(p+code.offset)) + } } + b = encodeComma(b) + code = code.next + case opStructEscapedFieldPtrHeadInt64PtrOnly: + p := load(ctxptr, code.idx) + if p == 0 { + b = encodeNull(b) + b = encodeComma(b) + code = code.end.next + break + } + store(ctxptr, code.idx, e.ptrToPtr(p)) + fallthrough + case opStructEscapedFieldHeadInt64PtrOnly: + p := load(ctxptr, code.idx) + b = append(b, '{') + b = append(b, code.escapedKey...) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, e.ptrToInt64(p+code.offset)) + } + b = encodeComma(b) + code = code.next case opStructFieldPtrAnonymousHeadInt64: store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) fallthrough @@ -2198,6 +2446,98 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte b = encodeComma(b) code = code.next } + case opStructFieldPtrAnonymousHeadInt64Only, opStructFieldAnonymousHeadInt64Only: + ptr := load(ctxptr, code.idx) + if ptr == 0 { + code = code.end.next + } else { + b = append(b, code.key...) + b = appendInt(b, e.ptrToInt64(ptr+code.offset)) + b = encodeComma(b) + code = code.next + } + case opStructEscapedFieldPtrAnonymousHeadInt64Only, opStructEscapedFieldAnonymousHeadInt64Only: + ptr := load(ctxptr, code.idx) + if ptr == 0 { + code = code.end.next + } else { + b = append(b, code.escapedKey...) + b = appendInt(b, e.ptrToInt64(ptr+code.offset)) + b = encodeComma(b) + code = code.next + } + case opStructFieldPtrAnonymousHeadInt64Ptr: + store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) + fallthrough + case opStructFieldAnonymousHeadInt64Ptr: + p := load(ctxptr, code.idx) + if p == 0 { + code = code.end.next + break + } + b = append(b, code.key...) + p = e.ptrToPtr(p) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, e.ptrToInt64(p+code.offset)) + } + b = encodeComma(b) + code = code.next + case opStructEscapedFieldPtrAnonymousHeadInt64Ptr: + store(ctxptr, code.idx, e.ptrToPtr(load(ctxptr, code.idx))) + fallthrough + case opStructEscapedFieldAnonymousHeadInt64Ptr: + p := load(ctxptr, code.idx) + if p == 0 { + code = code.end.next + break + } + b = append(b, code.escapedKey...) + p = e.ptrToPtr(p) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, e.ptrToInt64(p+code.offset)) + } + b = encodeComma(b) + code = code.next + case opStructFieldPtrAnonymousHeadInt64PtrOnly: + p := load(ctxptr, code.idx) + if p == 0 { + code = code.end.next + break + } + store(ctxptr, code.idx, e.ptrToPtr(p)) + fallthrough + case opStructFieldAnonymousHeadInt64PtrOnly: + p := load(ctxptr, code.idx) + b = append(b, code.key...) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, e.ptrToInt64(p+code.offset)) + } + b = encodeComma(b) + code = code.next + case opStructEscapedFieldPtrAnonymousHeadInt64PtrOnly: + p := load(ctxptr, code.idx) + if p == 0 { + code = code.end.next + break + } + store(ctxptr, code.idx, e.ptrToPtr(p)) + fallthrough + case opStructEscapedFieldAnonymousHeadInt64PtrOnly: + p := load(ctxptr, code.idx) + b = append(b, code.escapedKey...) + if p == 0 { + b = encodeNull(b) + } else { + b = appendInt(b, e.ptrToInt64(p+code.offset)) + } + b = encodeComma(b) + code = code.next case opStructFieldPtrHeadUint: p := load(ctxptr, code.idx) if p == 0 {