2016-02-28 03:16:29 +03:00
|
|
|
package tests
|
|
|
|
|
|
|
|
|
|
import (
|
2019-07-17 18:16:32 +01:00
|
|
|
"bytes"
|
2020-05-10 13:34:43 +03:00
|
|
|
"encoding/json"
|
2019-07-17 18:16:32 +01:00
|
|
|
"net/http/httptest"
|
2016-02-28 03:16:29 +03:00
|
|
|
"reflect"
|
|
|
|
|
"testing"
|
2016-02-28 14:11:49 +03:00
|
|
|
|
2016-03-29 16:04:34 +03:00
|
|
|
"github.com/mailru/easyjson"
|
2016-06-14 20:56:03 +03:00
|
|
|
"github.com/mailru/easyjson/jwriter"
|
2016-02-28 03:16:29 +03:00
|
|
|
)
|
|
|
|
|
|
2016-02-28 14:11:49 +03:00
|
|
|
type testType interface {
|
|
|
|
|
json.Marshaler
|
|
|
|
|
json.Unmarshaler
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var testCases = []struct {
|
|
|
|
|
Decoded testType
|
|
|
|
|
Encoded string
|
|
|
|
|
}{
|
|
|
|
|
{&primitiveTypesValue, primitiveTypesString},
|
2016-03-29 13:14:08 +03:00
|
|
|
{&namedPrimitiveTypesValue, namedPrimitiveTypesString},
|
2016-02-28 14:11:49 +03:00
|
|
|
{&structsValue, structsString},
|
|
|
|
|
{&omitEmptyValue, omitEmptyString},
|
2026-03-14 07:51:56 -07:00
|
|
|
{&omitZeroValue, omitZeroString},
|
|
|
|
|
{&omitEmptyAndZeroValue, omitEmptyAndZeroString},
|
2016-02-28 14:11:49 +03:00
|
|
|
{&snakeStructValue, snakeStructString},
|
|
|
|
|
{&omitEmptyDefaultValue, omitEmptyDefaultString},
|
2026-03-14 07:51:56 -07:00
|
|
|
{&omitZeroDefaultValue, omitZeroDefaultString},
|
2016-02-28 14:11:49 +03:00
|
|
|
{&optsValue, optsString},
|
|
|
|
|
{&rawValue, rawString},
|
2016-03-04 23:27:56 +10:00
|
|
|
{&stdMarshalerValue, stdMarshalerString},
|
2017-03-06 21:23:53 +03:00
|
|
|
{&userMarshalerValue, userMarshalerString},
|
2016-03-30 15:55:25 +03:00
|
|
|
{&unexportedStructValue, unexportedStructString},
|
2016-04-09 15:10:53 +07:00
|
|
|
{&excludedFieldValue, excludedFieldString},
|
2016-08-18 13:23:52 -07:00
|
|
|
{&sliceValue, sliceString},
|
2016-09-22 01:13:38 -07:00
|
|
|
{&arrayValue, arrayString},
|
2016-04-12 14:10:37 +03:00
|
|
|
{&mapsValue, mapsString},
|
2016-07-01 18:26:23 +07:00
|
|
|
{&deepNestValue, deepNestString},
|
2016-07-18 16:21:03 +03:00
|
|
|
{&IntsValue, IntsString},
|
2016-10-07 15:52:17 +03:00
|
|
|
{&mapStringStringValue, mapStringStringString},
|
2017-01-07 16:50:05 -08:00
|
|
|
{&namedTypeValue, namedTypeValueString},
|
2018-03-06 13:43:16 -08:00
|
|
|
{&customMapKeyTypeValue, customMapKeyTypeValueString},
|
2018-03-06 13:23:15 -08:00
|
|
|
{&embeddedTypeValue, embeddedTypeValueString},
|
2017-10-19 19:07:55 -07:00
|
|
|
{&mapMyIntStringValue, mapMyIntStringValueString},
|
|
|
|
|
{&mapIntStringValue, mapIntStringValueString},
|
|
|
|
|
{&mapInt32StringValue, mapInt32StringValueString},
|
|
|
|
|
{&mapInt64StringValue, mapInt64StringValueString},
|
|
|
|
|
{&mapUintStringValue, mapUintStringValueString},
|
|
|
|
|
{&mapUint32StringValue, mapUint32StringValueString},
|
|
|
|
|
{&mapUint64StringValue, mapUint64StringValueString},
|
|
|
|
|
{&mapUintptrStringValue, mapUintptrStringValueString},
|
|
|
|
|
{&intKeyedMapStructValue, intKeyedMapStructValueString},
|
2017-12-19 13:06:15 +03:00
|
|
|
{&intArrayStructValue, intArrayStructValueString},
|
2018-04-27 01:46:49 +03:00
|
|
|
{&myUInt8SliceValue, myUInt8SliceString},
|
|
|
|
|
{&myUInt8ArrayValue, myUInt8ArrayString},
|
2019-04-03 16:56:06 +00:00
|
|
|
{&mapWithEncodingMarshaler, mapWithEncodingMarshalerString},
|
2019-03-28 15:25:01 +01:00
|
|
|
{&myGenDeclaredValue, myGenDeclaredString},
|
|
|
|
|
{&myGenDeclaredWithCommentValue, myGenDeclaredWithCommentString},
|
|
|
|
|
{&myTypeDeclaredValue, myTypeDeclaredString},
|
2020-05-10 14:08:06 +03:00
|
|
|
{&myTypeNotSkippedValue, myTypeNotSkippedString},
|
2020-04-07 11:02:46 +09:00
|
|
|
{&intern, internString},
|
2016-02-28 14:11:49 +03:00
|
|
|
}
|
|
|
|
|
|
2016-02-28 03:16:29 +03:00
|
|
|
func TestMarshal(t *testing.T) {
|
|
|
|
|
for i, test := range testCases {
|
|
|
|
|
data, err := test.Decoded.MarshalJSON()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("[%d, %T] MarshalJSON() error: %v", i, test.Decoded, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
got := string(data)
|
|
|
|
|
if got != test.Encoded {
|
|
|
|
|
t.Errorf("[%d, %T] MarshalJSON(): got \n%v\n\t\t want \n%v", i, test.Decoded, got, test.Encoded)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestUnmarshal(t *testing.T) {
|
|
|
|
|
for i, test := range testCases {
|
|
|
|
|
v1 := reflect.New(reflect.TypeOf(test.Decoded).Elem()).Interface()
|
|
|
|
|
v := v1.(testType)
|
|
|
|
|
|
|
|
|
|
err := v.UnmarshalJSON([]byte(test.Encoded))
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("[%d, %T] UnmarshalJSON() error: %v", i, test.Decoded, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(v, test.Decoded) {
|
2016-04-12 14:10:37 +03:00
|
|
|
t.Errorf("[%d, %T] UnmarshalJSON(): got \n%+v\n\t\t want \n%+v", i, test.Decoded, v, test.Decoded)
|
2016-02-28 03:16:29 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-29 16:04:34 +03:00
|
|
|
|
|
|
|
|
func TestRawMessageSTD(t *testing.T) {
|
|
|
|
|
type T struct {
|
|
|
|
|
F easyjson.RawMessage
|
|
|
|
|
Fnil easyjson.RawMessage
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val := T{F: easyjson.RawMessage([]byte(`"test"`))}
|
|
|
|
|
str := `{"F":"test","Fnil":null}`
|
|
|
|
|
|
|
|
|
|
data, err := json.Marshal(val)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("json.Marshal() error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
got := string(data)
|
|
|
|
|
if got != str {
|
|
|
|
|
t.Errorf("json.Marshal() = %v; want %v", got, str)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wantV := T{F: easyjson.RawMessage([]byte(`"test"`)), Fnil: easyjson.RawMessage([]byte("null"))}
|
|
|
|
|
var gotV T
|
|
|
|
|
|
|
|
|
|
err = json.Unmarshal([]byte(str), &gotV)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("json.Unmarshal() error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(gotV, wantV) {
|
|
|
|
|
t.Errorf("json.Unmarshal() = %v; want %v", gotV, wantV)
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-04-13 16:17:22 +03:00
|
|
|
|
|
|
|
|
func TestParseNull(t *testing.T) {
|
|
|
|
|
var got, want SubStruct
|
|
|
|
|
if err := easyjson.Unmarshal([]byte("null"), &got); err != nil {
|
|
|
|
|
t.Errorf("Unmarshal() error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(got, want) {
|
|
|
|
|
t.Errorf("Unmarshal() = %+v; want %+v", got, want)
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-14 20:56:03 +03:00
|
|
|
|
2016-07-14 13:47:41 +03:00
|
|
|
var testSpecialCases = []struct {
|
|
|
|
|
EncodedString string
|
2016-07-18 16:21:03 +03:00
|
|
|
Value string
|
2016-06-14 20:56:03 +03:00
|
|
|
}{
|
2016-07-14 13:47:41 +03:00
|
|
|
{`"Username \u003cuser@example.com\u003e"`, `Username <user@example.com>`},
|
|
|
|
|
{`"Username\ufffd"`, "Username\xc5"},
|
|
|
|
|
{`"тестzтест"`, "тестzтест"},
|
|
|
|
|
{`"тест\ufffdтест"`, "тест\xc5тест"},
|
|
|
|
|
{`"绿茶"`, "绿茶"},
|
|
|
|
|
{`"绿\ufffd茶"`, "绿\xc5茶"},
|
|
|
|
|
{`"тест\u2028"`, "тест\xE2\x80\xA8"},
|
|
|
|
|
{`"\\\r\n\t\""`, "\\\r\n\t\""},
|
2020-04-24 20:26:02 +03:00
|
|
|
{`"text\\\""`, "text\\\""},
|
2016-07-14 13:47:41 +03:00
|
|
|
{`"ü"`, "ü"},
|
2016-06-14 20:56:03 +03:00
|
|
|
}
|
|
|
|
|
|
2016-07-14 13:47:41 +03:00
|
|
|
func TestSpecialCases(t *testing.T) {
|
|
|
|
|
for i, test := range testSpecialCases {
|
|
|
|
|
w := jwriter.Writer{}
|
|
|
|
|
w.String(test.Value)
|
|
|
|
|
got := string(w.Buffer.BuildBytes())
|
|
|
|
|
if got != test.EncodedString {
|
|
|
|
|
t.Errorf("[%d] Encoded() = %+v; want %+v", i, got, test.EncodedString)
|
2016-06-14 20:56:03 +03:00
|
|
|
}
|
|
|
|
|
}
|
2016-07-18 16:21:03 +03:00
|
|
|
}
|
2016-09-23 21:05:30 -07:00
|
|
|
|
|
|
|
|
func TestOverflowArray(t *testing.T) {
|
|
|
|
|
var a Arrays
|
|
|
|
|
err := easyjson.Unmarshal([]byte(arrayOverflowString), &a)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Error(err)
|
|
|
|
|
}
|
|
|
|
|
if a != arrayValue {
|
|
|
|
|
t.Errorf("Unmarshal(%v) = %+v; want %+v", arrayOverflowString, a, arrayValue)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestUnderflowArray(t *testing.T) {
|
|
|
|
|
var a Arrays
|
|
|
|
|
err := easyjson.Unmarshal([]byte(arrayUnderflowString), &a)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Error(err)
|
|
|
|
|
}
|
|
|
|
|
if a != arrayUnderflowValue {
|
|
|
|
|
t.Errorf("Unmarshal(%v) = %+v; want %+v", arrayUnderflowString, a, arrayUnderflowValue)
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-11 12:16:52 +03:00
|
|
|
|
2016-11-03 17:18:12 +03:00
|
|
|
func TestEncodingFlags(t *testing.T) {
|
|
|
|
|
for i, test := range []struct {
|
|
|
|
|
Flags jwriter.Flags
|
|
|
|
|
In easyjson.Marshaler
|
|
|
|
|
Want string
|
|
|
|
|
}{
|
|
|
|
|
{0, EncodingFlagsTestMap{}, `{"F":null}`},
|
|
|
|
|
{0, EncodingFlagsTestSlice{}, `{"F":null}`},
|
|
|
|
|
{jwriter.NilMapAsEmpty, EncodingFlagsTestMap{}, `{"F":{}}`},
|
|
|
|
|
{jwriter.NilSliceAsEmpty, EncodingFlagsTestSlice{}, `{"F":[]}`},
|
|
|
|
|
} {
|
|
|
|
|
w := &jwriter.Writer{Flags: test.Flags}
|
|
|
|
|
test.In.MarshalEasyJSON(w)
|
|
|
|
|
|
|
|
|
|
data, err := w.BuildBytes()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("[%v] easyjson.Marshal(%+v) error: %v", i, test.In, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v := string(data)
|
|
|
|
|
if v != test.Want {
|
|
|
|
|
t.Errorf("[%v] easyjson.Marshal(%+v) = %v; want %v", i, test.In, v, test.Want)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-11-07 10:53:49 +03:00
|
|
|
|
2016-10-11 12:16:52 +03:00
|
|
|
func TestNestedEasyJsonMarshal(t *testing.T) {
|
|
|
|
|
n := map[string]*NestedEasyMarshaler{
|
|
|
|
|
"Value": {},
|
|
|
|
|
"Slice1": {},
|
|
|
|
|
"Slice2": {},
|
|
|
|
|
"Map1": {},
|
|
|
|
|
"Map2": {},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ni := NestedInterfaces{
|
|
|
|
|
Value: n["Value"],
|
|
|
|
|
Slice: []interface{}{n["Slice1"], n["Slice2"]},
|
|
|
|
|
Map: map[string]interface{}{"1": n["Map1"], "2": n["Map2"]},
|
|
|
|
|
}
|
|
|
|
|
easyjson.Marshal(ni)
|
|
|
|
|
|
|
|
|
|
for k, v := range n {
|
|
|
|
|
if !v.EasilyMarshaled {
|
|
|
|
|
t.Errorf("Nested interface %s wasn't easily marshaled", k)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-13 12:06:02 +03:00
|
|
|
|
2020-07-14 17:27:06 +03:00
|
|
|
func TestNestedMarshaler(t *testing.T) {
|
|
|
|
|
s := NestedMarshaler{
|
|
|
|
|
Value: &StructWithMarshaler{
|
|
|
|
|
Value: 5,
|
|
|
|
|
},
|
|
|
|
|
Value2: 10,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data, err := s.MarshalJSON()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("Can't marshal NestedMarshaler: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s2 := NestedMarshaler {
|
|
|
|
|
Value: &StructWithMarshaler{},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = s2.UnmarshalJSON(data)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("Can't unmarshal NestedMarshaler: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(s2, s) {
|
|
|
|
|
t.Errorf("easyjson.Unmarshal() = %#v; want %#v", s2, s)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-14 11:45:40 +03:00
|
|
|
func TestUnmarshalStructWithEmbeddedPtrStruct(t *testing.T) {
|
|
|
|
|
var s = StructWithInterface{Field2: &EmbeddedStruct{}}
|
|
|
|
|
var err error
|
|
|
|
|
err = easyjson.Unmarshal([]byte(structWithInterfaceString), &s)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("easyjson.Unmarshal() error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(s, structWithInterfaceValueFilled) {
|
|
|
|
|
t.Errorf("easyjson.Unmarshal() = %#v; want %#v", s, structWithInterfaceValueFilled)
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-05-29 16:32:28 +00:00
|
|
|
|
|
|
|
|
func TestDisallowUnknown(t *testing.T) {
|
|
|
|
|
var d DisallowUnknown
|
|
|
|
|
err := easyjson.Unmarshal([]byte(disallowUnknownString), &d)
|
|
|
|
|
if err == nil {
|
|
|
|
|
t.Error("want error, got nil")
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-28 15:25:01 +01:00
|
|
|
|
|
|
|
|
var testNotGeneratedTypeCases = []interface{}{
|
|
|
|
|
TypeNotDeclared{},
|
2020-05-10 13:34:43 +03:00
|
|
|
TypeSkipped{},
|
2019-03-28 15:25:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestMethodsNoGenerated(t *testing.T) {
|
|
|
|
|
var ok bool
|
|
|
|
|
for i, instance := range testNotGeneratedTypeCases {
|
|
|
|
|
_, ok = instance.(json.Marshaler)
|
|
|
|
|
if ok {
|
|
|
|
|
t.Errorf("[%d, %T] Unexpected MarshalJSON()", i, instance)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_, ok = instance.(json.Unmarshaler)
|
|
|
|
|
if ok {
|
|
|
|
|
t.Errorf("[%d, %T] Unexpected Unmarshaler()", i, instance)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-12 18:10:39 +03:00
|
|
|
|
2019-07-17 18:16:32 +01:00
|
|
|
func TestNil(t *testing.T) {
|
|
|
|
|
var p *PrimitiveTypes
|
|
|
|
|
|
|
|
|
|
data, err := easyjson.Marshal(p)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("easyjson.Marshal() error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if string(data) != "null" {
|
|
|
|
|
t.Errorf("Wanted null, got %q", string(data))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var b bytes.Buffer
|
|
|
|
|
if n, err := easyjson.MarshalToWriter(p, &b); err != nil || n != 4 {
|
|
|
|
|
t.Errorf("easyjson.MarshalToWriter() error: %v, written %d", err, n)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if s := b.String(); s != "null" {
|
|
|
|
|
t.Errorf("Wanted null, got %q", s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
started, written, err := easyjson.MarshalToHTTPResponseWriter(p, w)
|
|
|
|
|
if !started || written != 4 || err != nil {
|
|
|
|
|
t.Errorf("easyjson.MarshalToHTTPResponseWriter() error: %v, written %d, started %t",
|
|
|
|
|
err, written, started)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if s := w.Body.String(); s != "null" {
|
|
|
|
|
t.Errorf("Wanted null, got %q", s)
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-18 21:43:31 -08:00
|
|
|
|
|
|
|
|
func TestUnmarshalNull(t *testing.T) {
|
2025-01-09 11:27:28 -08:00
|
|
|
p := PrimitiveTypes{
|
|
|
|
|
String: str,
|
|
|
|
|
Ptr: &str,
|
|
|
|
|
}
|
2024-12-18 21:43:31 -08:00
|
|
|
|
2025-01-09 11:27:28 -08:00
|
|
|
data := `{"String":null,"Ptr":null}`
|
2024-12-18 21:43:31 -08:00
|
|
|
|
|
|
|
|
if err := easyjson.Unmarshal([]byte(data), &p); err != nil {
|
|
|
|
|
t.Errorf("easyjson.Unmarshal() error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-09 11:27:28 -08:00
|
|
|
if p.String != str {
|
|
|
|
|
t.Errorf("Wanted %q, got %q", str, p.String)
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-18 21:43:31 -08:00
|
|
|
if p.Ptr != nil {
|
|
|
|
|
t.Errorf("Wanted nil, got %q", *p.Ptr)
|
|
|
|
|
}
|
|
|
|
|
}
|