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  }