Browse Source

codec: eliminate duplicate fields when loading structFieldInfo's.

This bug was introduced when we moved from using slices to denote
levels of embedding, to use arrays. We now track the length of the
actual embedding depth via a field.

This part of the code was not reflected in the change. Fixed now.

Fixes #209
Ugorji Nwoke 8 years ago
parent
commit
c8210b2555
2 changed files with 64 additions and 7 deletions
  1. 61 0
      codec/codec_test.go
  2. 3 7
      codec/helper.go

+ 61 - 0
codec/codec_test.go

@@ -1571,6 +1571,47 @@ func doTestDecodeNilMapValue(t *testing.T, handle Handle) {
 	}
 	}
 }
 }
 
 
+func doTestEmbeddedFieldPrecedence(t *testing.T, h Handle) {
+	type Embedded struct {
+		Field byte
+	}
+	type Struct struct {
+		Field byte
+		Embedded
+	}
+	toEncode := Struct{
+		Field:    1,
+		Embedded: Embedded{Field: 2},
+	}
+	_, isJsonHandle := h.(*JsonHandle)
+	handle := h.getBasicHandle()
+	oldMapType := handle.MapType
+	defer func() { handle.MapType = oldMapType }()
+
+	handle.MapType = reflect.TypeOf(map[interface{}]interface{}(nil))
+
+	bs, err := testMarshal(toEncode, h)
+	if err != nil {
+		logT(t, "Error encoding: %v, Err: %v", toEncode, err)
+		failT(t)
+	}
+
+	var decoded Struct
+	err = testUnmarshal(&decoded, bs, h)
+	if err != nil {
+		logT(t, "Error decoding: %v", err)
+		failT(t)
+	}
+
+	if decoded.Field != toEncode.Field {
+		logT(t, "Decoded result %v != %v", decoded.Field, toEncode.Field) // hex to look at what was encoded
+		if isJsonHandle {
+			logT(t, "JSON encoded as: %s", bs) // hex to look at what was encoded
+		}
+		failT(t)
+	}
+}
+
 func testRandomFillRV(v reflect.Value) {
 func testRandomFillRV(v reflect.Value) {
 	testOnce.Do(testInitAll)
 	testOnce.Do(testInitAll)
 	fneg := func() int64 {
 	fneg := func() int64 {
@@ -1904,6 +1945,26 @@ func TestSimpleDecodeNilMapValue(t *testing.T) {
 	doTestDecodeNilMapValue(t, testSimpleH)
 	doTestDecodeNilMapValue(t, testSimpleH)
 }
 }
 
 
+func TestJsonEmbeddedFieldPrecedence(t *testing.T) {
+	doTestEmbeddedFieldPrecedence(t, testJsonH)
+}
+
+func TestCborEmbeddedFieldPrecedence(t *testing.T) {
+	doTestEmbeddedFieldPrecedence(t, testCborH)
+}
+
+func TestMsgpackEmbeddedFieldPrecedence(t *testing.T) {
+	doTestEmbeddedFieldPrecedence(t, testMsgpackH)
+}
+
+func TestBincEmbeddedFieldPrecedence(t *testing.T) {
+	doTestEmbeddedFieldPrecedence(t, testBincH)
+}
+
+func TestSimpleEmbeddedFieldPrecedence(t *testing.T) {
+	doTestEmbeddedFieldPrecedence(t, testSimpleH)
+}
+
 func TestJsonLargeInteger(t *testing.T) {
 func TestJsonLargeInteger(t *testing.T) {
 	for _, i := range []uint8{'L', 'A', 0} {
 	for _, i := range []uint8{'L', 'A', 0} {
 		for _, j := range []interface{}{
 		for _, j := range []interface{}{

+ 3 - 7
codec/helper.go

@@ -772,10 +772,6 @@ type structFieldInfo struct {
 	toArray   bool // if field is _struct, is the toArray set?
 	toArray   bool // if field is _struct, is the toArray set?
 }
 }
 
 
-// func (si *structFieldInfo) isZero() bool {
-// 	return si.encName == "" && len(si.is) == 0 && si.i == 0 && !si.omitEmpty && !si.toArray
-// }
-
 func (si *structFieldInfo) setToZeroValue(v reflect.Value) {
 func (si *structFieldInfo) setToZeroValue(v reflect.Value) {
 	if v, valid := si.field(v, false); valid {
 	if v, valid := si.field(v, false); valid {
 		v.Set(reflect.Zero(v.Type()))
 		v.Set(reflect.Zero(v.Type()))
@@ -1292,13 +1288,13 @@ LOOP:
 func rgetResolveSFI(x []*structFieldInfo, pv []sfiIdx) (y, z []*structFieldInfo, anyOmitEmpty bool) {
 func rgetResolveSFI(x []*structFieldInfo, pv []sfiIdx) (y, z []*structFieldInfo, anyOmitEmpty bool) {
 	var n int
 	var n int
 	for i, v := range x {
 	for i, v := range x {
-		xn := v.encName //TODO: fieldName or encName? use encName for now.
+		xn := v.encName // TODO: fieldName or encName? use encName for now.
 		var found bool
 		var found bool
 		for j, k := range pv {
 		for j, k := range pv {
 			if k.name == xn {
 			if k.name == xn {
 				// one of them must be reset to nil, and the index updated appropriately to the other one
 				// one of them must be reset to nil, and the index updated appropriately to the other one
-				if len(v.is) == len(x[k.index].is) {
-				} else if len(v.is) < len(x[k.index].is) {
+				if v.nis == x[k.index].nis {
+				} else if v.nis < x[k.index].nis {
 					pv[j].index = i
 					pv[j].index = i
 					if x[k.index] != nil {
 					if x[k.index] != nil {
 						x[k.index] = nil
 						x[k.index] = nil