internal/descfmt: always include type name in FormatList

FormatList previously formatted output inconsistently when called on
EnumDescriptors, ServiceDescriptors and ExtensionDescriptors: other
types included the type name before {{; these types did not.

Add a default case that includes the type in these (and any other)
cases also.

Expanded tests to demonstrate and verify the new behaviour.

Change-Id: I9f53cb6548c4448a12c17d519639357ebdfa809b
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/286132
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
Trust: Joe Tsai <joetsai@google.com>
Trust: Matthew Dempsky <mdempsky@google.com>
diff --git a/internal/descfmt/stringer.go b/internal/descfmt/stringer.go
index e7af0fe..360c633 100644
--- a/internal/descfmt/stringer.go
+++ b/internal/descfmt/stringer.go
@@ -42,6 +42,8 @@
 			name = "FileImports"
 		case pref.Descriptor:
 			name = reflect.ValueOf(vs).MethodByName("Get").Type().Out(0).Name() + "s"
+		default:
+			name = reflect.ValueOf(vs).Elem().Type().Name()
 		}
 		start, end = name+"{", "}"
 	}
diff --git a/internal/filedesc/desc_test.go b/internal/filedesc/desc_test.go
index e490446..4f204f8 100644
--- a/internal/filedesc/desc_test.go
+++ b/internal/filedesc/desc_test.go
@@ -600,7 +600,7 @@
 }
 
 func testFileFormat(t *testing.T, fd pref.FileDescriptor) {
-	const want = `FileDescriptor{
+	const wantFileDescriptor = `FileDescriptor{
 	Syntax:  proto2
 	Path:    "path/to/file.proto"
 	Package: test
@@ -763,11 +763,72 @@
 		}]
 	}]
 }`
-	tests := []struct{ fmt, want string }{{"%v", compactMultiFormat(want)}, {"%+v", want}}
+
+	const wantEnums = `Enums{{
+	Name: E1
+	Values: [
+		{Name: FOO}
+		{Name: BAR, Number: 1}
+	]
+	ReservedNames:  [FIZZ, BUZZ]
+	ReservedRanges: [10:20, 30]
+}}`
+
+	const wantExtensions = `Extensions{{
+	Name:        X
+	Number:      1000
+	Cardinality: repeated
+	Kind:        enum
+	JSONName:    "[test.X]"
+	IsExtension: true
+	IsPacked:    true
+	IsList:      true
+	Extendee:    test.B
+	Enum:        test.E1
+}}`
+
+	const wantImports = `FileImports{}`
+
+	const wantReservedNames = "Names{fizz, buzz}"
+
+	const wantReservedRanges = "FieldRanges{100:200, 300}"
+
+	const wantServices = `Services{{
+	Name: S
+	Methods: [{
+		Name:              M
+		Input:             test.A
+		Output:            test.C.A
+		IsStreamingClient: true
+		IsStreamingServer: true
+	}]
+}}`
+
+	tests := []struct {
+		path string
+		fmt  string
+		want string
+		val  interface{}
+	}{
+		{"fd", "%v", compactMultiFormat(wantFileDescriptor), fd},
+		{"fd", "%+v", wantFileDescriptor, fd},
+		{"fd.Enums()", "%v", compactMultiFormat(wantEnums), fd.Enums()},
+		{"fd.Enums()", "%+v", wantEnums, fd.Enums()},
+		{"fd.Extensions()", "%v", compactMultiFormat(wantExtensions), fd.Extensions()},
+		{"fd.Extensions()", "%+v", wantExtensions, fd.Extensions()},
+		{"fd.Imports()", "%v", compactMultiFormat(wantImports), fd.Imports()},
+		{"fd.Imports()", "%+v", wantImports, fd.Imports()},
+		{"fd.Messages(B).ReservedNames()", "%v", compactMultiFormat(wantReservedNames), fd.Messages().ByName("B").ReservedNames()},
+		{"fd.Messages(B).ReservedNames()", "%+v", wantReservedNames, fd.Messages().ByName("B").ReservedNames()},
+		{"fd.Messages(B).ReservedRanges()", "%v", compactMultiFormat(wantReservedRanges), fd.Messages().ByName("B").ReservedRanges()},
+		{"fd.Messages(B).ReservedRanges()", "%+v", wantReservedRanges, fd.Messages().ByName("B").ReservedRanges()},
+		{"fd.Services()", "%v", compactMultiFormat(wantServices), fd.Services()},
+		{"fd.Services()", "%+v", wantServices, fd.Services()},
+	}
 	for _, tt := range tests {
-		got := fmt.Sprintf(tt.fmt, fd)
+		got := fmt.Sprintf(tt.fmt, tt.val)
 		if diff := cmp.Diff(got, tt.want); diff != "" {
-			t.Errorf("fmt.Sprintf(%q, fd) mismatch (-got +want):\n%s", tt.fmt, diff)
+			t.Errorf("fmt.Sprintf(%q, %s) mismatch (-got +want):\n%s", tt.fmt, tt.path, diff)
 		}
 	}
 }