| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package hessian |
| |
| import ( |
| "reflect" |
| "testing" |
| ) |
| |
| import ( |
| "github.com/stretchr/testify/assert" |
| ) |
| |
| type circular struct { |
| Num int |
| Previous *circular |
| Next *circular |
| } |
| |
| // JavaClassName java fully qualified path |
| func (circular) JavaClassName() string { |
| return "circular" |
| } |
| |
| func TestRef(t *testing.T) { |
| c := &circular{} |
| c.Num = 12345 |
| c.Previous = c |
| c.Next = c |
| |
| e := NewEncoder() |
| err := e.Encode(c) |
| if err != nil { |
| panic(err) |
| } |
| |
| bytes := e.Buffer() |
| t.Logf("circular bytes hex: %x, string: %s", bytes, string(bytes)) |
| res, err := NewDecoder(bytes).Decode() |
| if err != nil { |
| panic(err) |
| } |
| c1, ok := res.(*circular) |
| if !ok { |
| t.Fatalf("res:%T is not of type circular", c1) |
| } |
| t.Logf("encode object: %+v, decode object: %+v", c, c1) |
| if c.Num != c1.Num { |
| t.Errorf("encoded value %d != decoded value %d", c.Num, c1.Num) |
| } |
| if c1.Previous != c1.Next { |
| t.Errorf("decoded value previous %p != decoded value next %p", c1.Previous, c1.Next) |
| } |
| } |
| |
| type personT struct { |
| Name string |
| Relations []*personT |
| Parent *personT |
| Marks *map[string]*personT |
| Tags map[string]*personT |
| } |
| |
| // JavaClassName java fully qualified path |
| func (personT) JavaClassName() string { |
| return "person" |
| } |
| |
| func logRefObject(t *testing.T, n string, i interface{}) { |
| t.Logf("ref obj[%s]: %p, %v", n, i, i) |
| } |
| |
| func doTestRef(t *testing.T, c interface{}, name string) interface{} { |
| e := NewEncoder() |
| err := e.Encode(c) |
| if err != nil { |
| assert.FailNowf(t, "failed to encode", "error: %v", err) |
| } |
| bytes := e.Buffer() |
| |
| t.Logf("%s ref bytes: %s", name, string(bytes)) |
| t.Logf("%s ref bytes: %x", name, bytes) |
| |
| d := NewDecoder(bytes) |
| decoded, err := EnsureInterface(d.Decode()) |
| if err != nil { |
| assert.FailNowf(t, "failed to encode", "error: %v", err) |
| } |
| t.Logf("%s ref decoded: %v", name, decoded) |
| return decoded |
| } |
| |
| func buildComplexLevelPerson() *personT { |
| p1 := &personT{Name: "p1"} |
| p2 := &personT{Name: "p2"} |
| p3 := &personT{Name: "p3"} |
| p4 := &personT{Name: "p4"} |
| p5 := &personT{Name: "p5"} |
| p6 := &personT{Name: "p6"} |
| |
| p1.Parent = p2 |
| p2.Parent = p3 |
| p3.Parent = p4 |
| |
| relations := []*personT{p5, p6} |
| p3.Relations = relations |
| p4.Relations = relations |
| |
| marks := &map[string]*personT{ |
| "beautiful": p1, |
| "tall": p2, |
| "fat": p3, |
| } |
| p4.Marks = marks |
| p5.Marks = marks |
| |
| tags := map[string]*personT{ |
| "man": p3, |
| "woman": p4, |
| } |
| p5.Tags = tags |
| p6.Tags = tags |
| |
| return p1 |
| } |
| |
| func TestComplexLevelRef(t *testing.T) { |
| p1 := buildComplexLevelPerson() |
| decoded := doTestRef(t, p1, "person") |
| |
| t.Logf("decoded object type: %v", reflect.TypeOf(decoded)) |
| d1, ok := decoded.(*personT) |
| if !ok { |
| assert.FailNow(t, "decode object is not a pointer of person") |
| } |
| logRefObject(t, "d1", d1) |
| |
| d2 := d1.Parent |
| assert.NotNil(t, d2) |
| logRefObject(t, "d2", d2) |
| |
| d3 := d2.Parent |
| assert.NotNil(t, d3) |
| logRefObject(t, "d3", d3) |
| |
| d4 := d3.Parent |
| logRefObject(t, "d4", d4) |
| |
| assert.Equal(t, 2, len(d3.Relations)) |
| if len(d3.Relations) != 2 { |
| assert.FailNow(t, "the length of relation array should be 2") |
| } |
| d5 := d3.Relations[0] |
| logRefObject(t, "d5", d5) |
| d6 := d3.Relations[1] |
| logRefObject(t, "d6", d6) |
| |
| assert.NotNil(t, d4) |
| assert.NotNil(t, d5) |
| assert.NotNil(t, d6) |
| |
| assert.Equal(t, "p1", d1.Name) |
| assert.Equal(t, "p2", d2.Name) |
| assert.Equal(t, "p3", d3.Name) |
| assert.Equal(t, "p4", d4.Name) |
| assert.Equal(t, "p5", d5.Name) |
| assert.Equal(t, "p6", d6.Name) |
| |
| // value equal |
| assert.True(t, reflect.DeepEqual(d3.Relations, d4.Relations)) |
| |
| if d4.Marks == nil { |
| assert.FailNow(t, "d4.Marks should not be nil") |
| } |
| |
| assert.Equal(t, 3, len(*d4.Marks)) |
| assert.True(t, AddrEqual(d4.Marks, d5.Marks)) |
| assert.True(t, AddrEqual(d1, (*d4.Marks)["beautiful"])) |
| assert.True(t, AddrEqual(d2, (*d4.Marks)["tall"])) |
| assert.True(t, AddrEqual(d3, (*d4.Marks)["fat"])) |
| |
| if d5.Tags == nil { |
| assert.FailNow(t, "d5.Tags should not be nil") |
| } |
| assert.Equal(t, 2, len(d5.Tags)) |
| assert.True(t, reflect.DeepEqual(d5.Tags, d6.Tags)) |
| assert.False(t, AddrEqual(d5.Tags, d6.Tags)) |
| assert.True(t, AddrEqual(d3, d5.Tags["man"])) |
| assert.True(t, AddrEqual(d4, d5.Tags["woman"])) |
| } |