ソースを参照

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 年 前
コミット
c8210b2555
2 ファイル変更64 行追加7 行削除
  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) {
 	testOnce.Do(testInitAll)
 	fneg := func() int64 {
@@ -1904,6 +1945,26 @@ func TestSimpleDecodeNilMapValue(t *testing.T) {
 	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) {
 	for _, i := range []uint8{'L', 'A', 0} {
 		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?
 }
 
-// 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) {
 	if v, valid := si.field(v, false); valid {
 		v.Set(reflect.Zero(v.Type()))
@@ -1292,13 +1288,13 @@ LOOP:
 func rgetResolveSFI(x []*structFieldInfo, pv []sfiIdx) (y, z []*structFieldInfo, anyOmitEmpty bool) {
 	var n int
 	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
 		for j, k := range pv {
 			if k.name == xn {
 				// 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
 					if x[k.index] != nil {
 						x[k.index] = nil