// Copyright 2019-present Facebook Inc. All rights reserved. // This source code is licensed under the Apache 2.0 license found // in the LICENSE file in the root directory of this source tree. package graphson import ( "bytes" "fmt" "strings" "testing" "github.com/modern-go/reflect2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestEncodeArray(t *testing.T) { t.Parallel() got, err := MarshalToString([...]string{"a", "b", "c"}) require.NoError(t, err) want := `{ "@type": "g:List", "@value": ["a", "b", "c"]}` assert.JSONEq(t, want, got) } func TestEncodeSlice(t *testing.T) { tests := []struct { in interface{} want string }{ { in: []int32{5, 6, 7, 8}, want: `{ "@type": "g:List", "@value": [ { "@type": "g:Int32", "@value": 5 }, { "@type": "g:Int32", "@value": 6 }, { "@type": "g:Int32", "@value": 7 }, { "@type": "g:Int32", "@value": 8 } ] }`, }, { in: []byte{1, 2, 3, 4, 5}, want: `{ "@type": "gx:ByteBuffer", "@value": "AQIDBAU=" }`, }, { in: [...]byte{4, 5}, want: `{ "@type": "g:List", "@value": [ { "@type": "gx:Byte", "@value": 4 }, { "@type": "gx:Byte", "@value": 5 } ] }`, }, { in: []uint64(nil), want: "null", }, } for _, tc := range tests { tc := tc t.Run(fmt.Sprintf("%T", tc.in), func(t *testing.T) { t.Parallel() var got bytes.Buffer err := NewEncoder(&got).Encode(tc.in) assert.NoError(t, err) assert.JSONEq(t, tc.want, got.String()) }) } } func TestDecodeSlice(t *testing.T) { tests := []struct { in string want interface{} }{ { in: `{ "@type": "g:List", "@value": [ { "@type": "g:Int32", "@value": 3 }, { "@type": "g:Int32", "@value": -2 }, { "@type": "g:Int32", "@value": 1 } ] }`, want: []int32{3, -2, 1}, }, { in: `{ "@type": "g:List", "@value": ["a", "b", "c"] }`, want: []string{"a", "b", "c"}, }, { in: `{ "@type": "gx:ByteBuffer", "@value": "AQIDBAU=" }`, want: []byte{1, 2, 3, 4, 5}, }, { in: `{ "@type": "g:List", "@value": [ { "@type": "gx:Byte", "@value": 42 }, { "@type": "gx:Byte", "@value": 55 }, { "@type": "gx:Byte", "@value": 94 } ] }`, want: [...]byte{42, 55}, }, { in: `{ "@type": "g:List", "@value": null }`, want: []int(nil), }, } for _, tc := range tests { tc := tc t.Run(fmt.Sprintf("%T", tc.want), func(t *testing.T) { t.Parallel() typ := reflect2.TypeOf(tc.want) got := typ.New() err := NewDecoder(strings.NewReader(tc.in)).Decode(got) require.NoError(t, err) assert.Equal(t, tc.want, typ.Indirect(got)) }) } } func TestDecodeBadSlice(t *testing.T) { tests := []struct { name string in string new func() interface{} }{ { name: "TypeMismatch", in: `{ "@type": "g:List", "@value": [ { "@type": "g:Int32", "@value": 3 }, { "@type": "g:Int64", "@value": 2 } ] }`, new: func() interface{} { return &[]int{} }, }, { name: "BadValue", in: `{ "@type": "g:List", "@value": [ { "@type": "g:Int32", "@value": 3 }, { "@type": "g:Int32", "@value": "2" } ] }`, new: func() interface{} { return &[2]int{} }, }, } for _, tc := range tests { tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() err := NewDecoder(strings.NewReader(tc.in)).Decode(tc.new()) assert.Error(t, err) }) } }