github.com/cosmos/cosmos-proto@v1.0.0-beta.3/testpb/range_test.go (about)

     1  package testpb
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/require"
     7  	"google.golang.org/protobuf/proto"
     8  	"google.golang.org/protobuf/reflect/protoreflect"
     9  	"google.golang.org/protobuf/types/dynamicpb"
    10  )
    11  
    12  func TestRange(t *testing.T) {
    13  	t.Run("empty", func(t *testing.T) {
    14  		dyn := dynamicpb.NewMessage(md_A)
    15  		msg := (&A{}).ProtoReflect()
    16  
    17  		dynV := map[protoreflect.FieldDescriptor]protoreflect.Value{}
    18  		msgV := map[protoreflect.FieldDescriptor]protoreflect.Value{}
    19  
    20  		dyn.Range(func(descriptor protoreflect.FieldDescriptor, value protoreflect.Value) bool {
    21  			dynV[descriptor] = value
    22  			return true
    23  		})
    24  
    25  		msg.Range(func(descriptor protoreflect.FieldDescriptor, value protoreflect.Value) bool {
    26  			msgV[descriptor] = protoreflect.Value{}
    27  			return true
    28  		})
    29  
    30  		require.Equal(t, len(dynV), len(msgV))
    31  		require.Equal(t, len(msgV), 0)
    32  	})
    33  
    34  	t.Run("all fields filled", func(t *testing.T) {
    35  		// create a message which has all fields set
    36  		// and copy it to dynamicpb message
    37  		msg := &A{
    38  			Enum:        Enumeration_Two,
    39  			SomeBoolean: true,
    40  			INT32:       1,
    41  			SINT32:      2,
    42  			UINT32:      3,
    43  			INT64:       4,
    44  			SING64:      5,
    45  			UINT64:      6,
    46  			SFIXED32:    7,
    47  			FIXED32:     8,
    48  			FLOAT:       9,
    49  			SFIXED64:    10,
    50  			FIXED64:     11,
    51  			DOUBLE:      12,
    52  			STRING:      "a string",
    53  			BYTES:       []byte("test bytes"),
    54  			MESSAGE: &B{
    55  				X: "something else",
    56  			},
    57  			MAP:       map[string]*B{"item": {X: "inside_map_item"}},
    58  			LIST:      []*B{{X: "part of list"}},
    59  			ONEOF:     &A_ONEOF_B{ONEOF_B: &B{X: "1"}},
    60  			LIST_ENUM: []Enumeration{Enumeration_One, Enumeration_One},
    61  		}
    62  
    63  		dyn := dynamicpb.NewMessage(msg.ProtoReflect().Descriptor())
    64  
    65  		b, err := proto.MarshalOptions{}.Marshal(msg)
    66  		require.NoError(t, err)
    67  		require.NoError(t, proto.Unmarshal(b, dyn))
    68  
    69  		dynV := map[protoreflect.FieldDescriptor]protoreflect.Value{}
    70  		msgV := map[protoreflect.FieldDescriptor]protoreflect.Value{}
    71  
    72  		dyn.Range(func(descriptor protoreflect.FieldDescriptor, value protoreflect.Value) bool {
    73  			dynV[descriptor] = value
    74  			return true
    75  		})
    76  
    77  		msg.ProtoReflect().Range(func(descriptor protoreflect.FieldDescriptor, value protoreflect.Value) bool {
    78  			msgV[descriptor] = value
    79  			return true
    80  		})
    81  
    82  		require.Equal(t, len(dynV), len(msgV))
    83  
    84  		// assert field equality
    85  		for field, dynValue := range dynV {
    86  			msgValue, exists := msgV[field]
    87  			require.True(t, exists, "field ", field.FullName(), "not found")
    88  
    89  			valueEquality(t, field, dynValue, msgValue)
    90  		}
    91  	})
    92  }
    93  
    94  func valueEquality(t *testing.T, field protoreflect.FieldDescriptor, v1, v2 protoreflect.Value) {
    95  	if !v1.IsValid() {
    96  		require.False(t, v2.IsValid())
    97  		return
    98  	}
    99  
   100  	switch {
   101  	case field.IsList():
   102  		list1 := v1.List()
   103  		list2 := v2.List()
   104  
   105  		if !list1.IsValid() {
   106  			require.False(t, list2.IsValid())
   107  			return
   108  		}
   109  
   110  		require.Equal(t, list1.Len(), list2.Len())
   111  
   112  		for i := 0; i < list1.Len(); i++ {
   113  			elem1 := list1.Get(i)
   114  			elem2 := list2.Get(i)
   115  
   116  			// note: we cannot call again valueEquality otherwise we end up in a loop
   117  			switch {
   118  			case field.Kind() == protoreflect.MessageKind:
   119  				require.True(t, proto.Equal(elem1.Message().Interface(), elem2.Message().Interface()))
   120  			default:
   121  				require.Equal(t, elem1.Interface(), elem2.Interface())
   122  			}
   123  		}
   124  	case field.IsMap():
   125  		map1 := v1.Map()
   126  		map2 := v2.Map()
   127  
   128  		if !map1.IsValid() {
   129  			require.False(t, map2.IsValid())
   130  			return
   131  		}
   132  
   133  		require.Equal(t, map1.Len(), map2.Len())
   134  
   135  		map1.Range(func(key protoreflect.MapKey, map1Value protoreflect.Value) bool {
   136  			// assert map2 has the key from map1
   137  			map2Value := map2.Get(key)
   138  			require.True(t, map2Value.IsValid(), "key not found", key)
   139  
   140  			// assert the values are equal
   141  			valueEquality(t, field.MapValue(), map1Value, map2Value)
   142  			return true
   143  		})
   144  	case field.Kind() == protoreflect.MessageKind:
   145  		if !v1.Message().IsValid() {
   146  			require.False(t, v2.Message().IsValid())
   147  			return
   148  		}
   149  		require.True(t, proto.Equal(v1.Message().Interface(), v2.Message().Interface()))
   150  	default:
   151  		require.Equal(t, v1.Interface(), v2.Interface())
   152  	}
   153  }