Jelajahi Sumber

goprotobuf: Fixes for Clone and Equal.

R=r
CC=golang-dev
http://codereview.appspot.com/6419071
David Symonds 13 tahun lalu
induk
melakukan
007ed9dc8e
6 mengubah file dengan 27 tambahan dan 3 penghapusan
  1. 4 0
      proto/clone.go
  2. 1 1
      proto/encode.go
  3. 14 0
      proto/equal.go
  4. 4 0
      proto/equal_test.go
  5. 3 1
      proto/text_parser.go
  6. 1 1
      proto/text_parser_test.go

+ 4 - 0
proto/clone.go

@@ -70,6 +70,10 @@ func copyStruct(out, in reflect.Value) {
 }
 
 func copyAny(out, in reflect.Value) {
+	if in.Type() == protoMessageType {
+		out.Set(reflect.ValueOf(Clone(in.Interface().(Message))))
+		return
+	}
 	switch in.Kind() {
 	case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
 		reflect.String, reflect.Uint32, reflect.Uint64:

+ 1 - 1
proto/encode.go

@@ -263,7 +263,7 @@ func (o *Buffer) enc_string(p *Properties, base uintptr) error {
 // All protocol buffer fields are nillable, but be careful.
 func isNil(v reflect.Value) bool {
 	switch v.Kind() {
-	case reflect.Map, reflect.Ptr, reflect.Slice:
+	case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
 		return v.IsNil()
 	}
 	return false

+ 14 - 0
proto/equal.go

@@ -65,11 +65,20 @@ Equality is defined in this way:
 The return value is undefined if a and b are not protocol buffers.
 */
 func Equal(a, b Message) bool {
+	if a == nil || b == nil {
+		return a == b
+	}
 	v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b)
 	if v1.Type() != v2.Type() {
 		return false
 	}
 	if v1.Kind() == reflect.Ptr {
+		if v1.IsNil() {
+			return v2.IsNil()
+		}
+		if v2.IsNil() {
+			return false
+		}
 		v1, v2 = v1.Elem(), v2.Elem()
 	}
 	if v1.Kind() != reflect.Struct {
@@ -124,6 +133,11 @@ func equalStruct(v1, v2 reflect.Value) bool {
 
 // v1 and v2 are known to have the same type.
 func equalAny(v1, v2 reflect.Value) bool {
+	if v1.Type() == protoMessageType {
+		m1, _ := v1.Interface().(Message)
+		m2, _ := v2.Interface().(Message)
+		return Equal(m1, m2)
+	}
 	switch v1.Kind() {
 	case reflect.Bool:
 		return v1.Bool() == v2.Bool()

+ 4 - 0
proto/equal_test.go

@@ -92,6 +92,10 @@ var EqualTests = []struct {
 }{
 	{"different types", &pb.GoEnum{}, &pb.GoTestField{}, false},
 	{"equal empty", &pb.GoEnum{}, &pb.GoEnum{}, true},
+	{"nil vs nil", nil, nil, true},
+	{"typed nil vs typed nil", (*pb.GoEnum)(nil), (*pb.GoEnum)(nil), true},
+	{"typed nil vs empty", (*pb.GoEnum)(nil), &pb.GoEnum{}, false},
+	{"different typed nil", (*pb.GoEnum)(nil), (*pb.GoTestField)(nil), false},
 
 	{"one set field, one unset field", &pb.GoTestField{Label: String("foo")}, &pb.GoTestField{}, false},
 	{"one set field zero, one unset field", &pb.GoTest{Param: Int32(0)}, &pb.GoTest{}, false},

+ 3 - 1
proto/text_parser.go

@@ -416,8 +416,10 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) *ParseError
 				return err
 			}
 
+			dst := sv.Field(fi)
+
 			// Parse into the field.
-			if err := p.readAny(sv.Field(fi), props); err != nil {
+			if err := p.readAny(dst, props); err != nil {
 				return err
 			}
 

+ 1 - 1
proto/text_parser_test.go

@@ -359,7 +359,7 @@ func TestRepeatedEnum(t *testing.T) {
 	exp := &RepeatedEnum{
 		Color: []RepeatedEnum_Color{RepeatedEnum_RED},
 	}
-	if !reflect.DeepEqual(pb, exp) {
+	if !Equal(pb, exp) {
 		t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp)
 	}
 }