encoding/textpb: unmarshal Any

Also fix marshaling Any in expanded form to contain the correct type_url
value.

Change-Id: I4b467e74bb1d73255effd9cc4cfff9cf4558940f
Reviewed-on: https://go-review.googlesource.com/c/156342
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/encoding/textpb/other_test.go b/encoding/textpb/other_test.go
index 4092976..4200ac1 100644
--- a/encoding/textpb/other_test.go
+++ b/encoding/textpb/other_test.go
@@ -7,10 +7,13 @@
 	"github.com/golang/protobuf/v2/encoding/textpb"
 	"github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb2"
 	"github.com/golang/protobuf/v2/proto"
+	preg "github.com/golang/protobuf/v2/reflect/protoregistry"
 
 	// The legacy package must be imported prior to use of any legacy messages.
 	// TODO: Remove this when protoV1 registers these hooks for you.
+	"github.com/golang/protobuf/v2/internal/impl"
 	_ "github.com/golang/protobuf/v2/internal/legacy"
+	"github.com/golang/protobuf/v2/internal/scalar"
 
 	anypb "github.com/golang/protobuf/ptypes/any"
 	durpb "github.com/golang/protobuf/ptypes/duration"
@@ -22,8 +25,9 @@
 
 func TestRoundTrip(t *testing.T) {
 	tests := []struct {
-		desc    string
-		message proto.Message
+		desc     string
+		resolver *preg.Types
+		message  proto.Message
 	}{{
 		desc: "well-known type fields set to empty messages",
 		message: &pb2.KnownTypes{
@@ -88,7 +92,7 @@
 			},
 		},
 	}, {
-		desc: "well-known type struct field and different Value types",
+		desc: "Struct field and different Value types",
 		message: &pb2.KnownTypes{
 			OptStruct: &stpb.Struct{
 				Fields: map[string]*stpb.Value{
@@ -146,21 +150,101 @@
 				},
 			},
 		},
+	}, {
+		desc:     "Any field without registered type",
+		resolver: preg.NewTypes(),
+		message: func() proto.Message {
+			m := &pb2.Nested{
+				OptString: scalar.String("embedded inside Any"),
+				OptNested: &pb2.Nested{
+					OptString: scalar.String("inception"),
+				},
+			}
+			// TODO: Switch to V2 marshal when ready.
+			b, err := protoV1.Marshal(m)
+			if err != nil {
+				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
+			}
+			return &pb2.KnownTypes{
+				OptAny: &anypb.Any{
+					TypeUrl: string(m.ProtoReflect().Type().FullName()),
+					Value:   b,
+				},
+			}
+		}(),
+	}, {
+		desc:     "Any field with registered type",
+		resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
+		message: func() proto.Message {
+			m := &pb2.Nested{
+				OptString: scalar.String("embedded inside Any"),
+				OptNested: &pb2.Nested{
+					OptString: scalar.String("inception"),
+				},
+			}
+			// TODO: Switch to V2 marshal when ready.
+			b, err := protoV1.Marshal(m)
+			if err != nil {
+				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
+			}
+			return &pb2.KnownTypes{
+				OptAny: &anypb.Any{
+					TypeUrl: string(m.ProtoReflect().Type().FullName()),
+					Value:   b,
+				},
+			}
+		}(),
+	}, {
+		desc: "Any field containing Any message",
+		resolver: func() *preg.Types {
+			mt1 := (&pb2.Nested{}).ProtoReflect().Type()
+			mt2 := impl.Export{}.MessageTypeOf(&anypb.Any{})
+			return preg.NewTypes(mt1, mt2)
+		}(),
+		message: func() proto.Message {
+			m1 := &pb2.Nested{
+				OptString: scalar.String("message inside Any of another Any field"),
+			}
+			// TODO: Switch to V2 marshal when ready.
+			b1, err := protoV1.Marshal(m1)
+			if err != nil {
+				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
+			}
+			m2 := &anypb.Any{
+				TypeUrl: "pb2.Nested",
+				Value:   b1,
+			}
+			// TODO: Switch to V2 marshal when ready.
+			b2, err := protoV1.Marshal(m2)
+			if err != nil {
+				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
+			}
+			return &pb2.KnownTypes{
+				OptAny: &anypb.Any{
+					TypeUrl: "google.protobuf.Any",
+					Value:   b2,
+				},
+			}
+		}(),
 	}}
 
 	for _, tt := range tests {
 		tt := tt
 		t.Run(tt.desc, func(t *testing.T) {
 			t.Parallel()
-			b, err := textpb.Marshal(tt.message)
+			mo := textpb.MarshalOptions{Resolver: tt.resolver}
+			umo := textpb.UnmarshalOptions{Resolver: tt.resolver}
+
+			b, err := mo.Marshal(tt.message)
 			if err != nil {
 				t.Errorf("Marshal() returned error: %v\n\n", err)
 			}
 			gotMessage := tt.message.ProtoReflect().Type().New().Interface()
-			err = textpb.Unmarshal(gotMessage, b)
+			err = umo.Unmarshal(gotMessage, b)
 			if err != nil {
 				t.Errorf("Unmarshal() returned error: %v\n\n", err)
 			}
+
 			if !protoV1.Equal(gotMessage.(protoV1.Message), tt.message.(protoV1.Message)) {
 				t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", gotMessage, tt.message)
 			}