github.com/Finschia/finschia-sdk@v0.48.1/codec/types/types_test.go (about) 1 package types_test 2 3 import ( 4 "strings" 5 "testing" 6 7 "github.com/gogo/protobuf/jsonpb" 8 "github.com/gogo/protobuf/proto" 9 "github.com/stretchr/testify/require" 10 11 "github.com/Finschia/finschia-sdk/codec/types" 12 "github.com/Finschia/finschia-sdk/testutil/testdata" 13 ) 14 15 func TestAnyPackUnpack(t *testing.T) { 16 registry := testdata.NewTestInterfaceRegistry() 17 18 spot := &testdata.Dog{Name: "Spot"} 19 var animal testdata.Animal 20 21 // with cache 22 any, err := types.NewAnyWithValue(spot) 23 require.NoError(t, err) 24 require.Equal(t, spot, any.GetCachedValue()) 25 err = registry.UnpackAny(any, &animal) 26 require.NoError(t, err) 27 require.Equal(t, spot, animal) 28 } 29 30 type TestI interface { 31 DoSomething() 32 } 33 34 // A struct that has the same typeURL as testdata.Dog, but is actually another 35 // concrete type. 36 type FakeDog struct{} 37 38 var ( 39 _ proto.Message = &FakeDog{} 40 _ testdata.Animal = &FakeDog{} 41 ) 42 43 // dummy implementation of proto.Message and testdata.Animal 44 func (dog FakeDog) Reset() {} 45 func (dog FakeDog) String() string { return "fakedog" } 46 func (dog FakeDog) ProtoMessage() {} 47 func (dog FakeDog) XXX_MessageName() string { return proto.MessageName(&testdata.Dog{}) } 48 func (dog FakeDog) Greet() string { return "fakedog" } 49 50 func TestRegister(t *testing.T) { 51 registry := types.NewInterfaceRegistry() 52 registry.RegisterInterface("Animal", (*testdata.Animal)(nil)) 53 registry.RegisterInterface("TestI", (*TestI)(nil)) 54 55 // Happy path. 56 require.NotPanics(t, func() { 57 registry.RegisterImplementations((*testdata.Animal)(nil), &testdata.Dog{}) 58 }) 59 60 // testdata.Dog doesn't implement TestI 61 require.Panics(t, func() { 62 registry.RegisterImplementations((*TestI)(nil), &testdata.Dog{}) 63 }) 64 65 // nil proto message 66 require.Panics(t, func() { 67 registry.RegisterImplementations((*TestI)(nil), nil) 68 }) 69 70 // Not an interface. 71 require.Panics(t, func() { 72 registry.RegisterInterface("not_an_interface", (*testdata.Dog)(nil)) 73 }) 74 75 // Duplicate registration with same concrete type. 76 require.NotPanics(t, func() { 77 registry.RegisterImplementations((*testdata.Animal)(nil), &testdata.Dog{}) 78 }) 79 80 // Duplicate registration with different concrete type on same typeURL. 81 require.PanicsWithError( 82 t, 83 "concrete type *testdata.Dog has already been registered under typeURL /testdata.Dog, cannot register *types_test.FakeDog under same typeURL. "+ 84 "This usually means that there are conflicting modules registering different concrete types for a same interface implementation", 85 func() { 86 registry.RegisterImplementations((*testdata.Animal)(nil), &FakeDog{}) 87 }, 88 ) 89 } 90 91 func TestUnpackInterfaces(t *testing.T) { 92 registry := testdata.NewTestInterfaceRegistry() 93 94 spot := &testdata.Dog{Name: "Spot"} 95 any, err := types.NewAnyWithValue(spot) 96 require.NoError(t, err) 97 98 hasAny := testdata.HasAnimal{ 99 Animal: any, 100 X: 1, 101 } 102 bz, err := hasAny.Marshal() 103 require.NoError(t, err) 104 105 var hasAny2 testdata.HasAnimal 106 err = hasAny2.Unmarshal(bz) 107 require.NoError(t, err) 108 109 err = types.UnpackInterfaces(hasAny2, registry) 110 require.NoError(t, err) 111 112 require.Equal(t, spot, hasAny2.Animal.GetCachedValue()) 113 } 114 115 func TestNested(t *testing.T) { 116 registry := testdata.NewTestInterfaceRegistry() 117 118 spot := &testdata.Dog{Name: "Spot"} 119 any, err := types.NewAnyWithValue(spot) 120 require.NoError(t, err) 121 122 ha := &testdata.HasAnimal{Animal: any} 123 any2, err := types.NewAnyWithValue(ha) 124 require.NoError(t, err) 125 126 hha := &testdata.HasHasAnimal{HasAnimal: any2} 127 any3, err := types.NewAnyWithValue(hha) 128 require.NoError(t, err) 129 130 hhha := testdata.HasHasHasAnimal{HasHasAnimal: any3} 131 132 // marshal 133 bz, err := hhha.Marshal() 134 require.NoError(t, err) 135 136 // unmarshal 137 var hhha2 testdata.HasHasHasAnimal 138 err = hhha2.Unmarshal(bz) 139 require.NoError(t, err) 140 err = types.UnpackInterfaces(hhha2, registry) 141 require.NoError(t, err) 142 143 require.Equal(t, spot, hhha2.TheHasHasAnimal().TheHasAnimal().TheAnimal()) 144 } 145 146 func TestAny_ProtoJSON(t *testing.T) { 147 spot := &testdata.Dog{Name: "Spot"} 148 any, err := types.NewAnyWithValue(spot) 149 require.NoError(t, err) 150 151 jm := &jsonpb.Marshaler{} 152 json, err := jm.MarshalToString(any) 153 require.NoError(t, err) 154 require.Equal(t, "{\"@type\":\"/testdata.Dog\",\"name\":\"Spot\"}", json) 155 156 registry := testdata.NewTestInterfaceRegistry() 157 jum := &jsonpb.Unmarshaler{} 158 var any2 types.Any 159 err = jum.Unmarshal(strings.NewReader(json), &any2) 160 require.NoError(t, err) 161 var animal testdata.Animal 162 err = registry.UnpackAny(&any2, &animal) 163 require.NoError(t, err) 164 require.Equal(t, spot, animal) 165 166 ha := &testdata.HasAnimal{ 167 Animal: any, 168 } 169 err = ha.UnpackInterfaces(types.ProtoJSONPacker{JSONPBMarshaler: jm}) 170 require.NoError(t, err) 171 json, err = jm.MarshalToString(ha) 172 require.NoError(t, err) 173 require.Equal(t, "{\"animal\":{\"@type\":\"/testdata.Dog\",\"name\":\"Spot\"}}", json) 174 175 require.NoError(t, err) 176 var ha2 testdata.HasAnimal 177 err = jum.Unmarshal(strings.NewReader(json), &ha2) 178 require.NoError(t, err) 179 err = ha2.UnpackInterfaces(registry) 180 require.NoError(t, err) 181 require.Equal(t, spot, ha2.Animal.GetCachedValue()) 182 }