Browse Source

Fix namespace name for nested package names (#1806)

Motivation:

The current implementation of the ProtobufParser replaces the dots with
their scalar value for the CodeGenerationRequest names. We want the dots
to be replaced by "_"s.

Modifications:

- updated the Name object generation for packages in the ProtobufCodeGenParser to handle correctly nested package names
- added more ProtobufCodeGen tests for a simple package name, a nested one and an empty one

Result:

Tha dots from the package name will be replaced by underscores in the input and output types, as well as in the generated protocols and extensions.
Stefana-Ioana Dranca 1 year ago
parent
commit
ac0083c21e

+ 34 - 4
Sources/GRPCProtobufCodeGen/ProtobufCodeGenParser.swift

@@ -68,7 +68,8 @@ internal struct ProtobufCodeGenParser {
       CodeGenerationRequest.ServiceDescriptor(
         descriptor: $0,
         package: input.package,
-        protobufNamer: self.namer
+        protobufNamer: self.namer,
+        file: self.input
       )
     }
 
@@ -107,7 +108,8 @@ extension CodeGenerationRequest.ServiceDescriptor {
   fileprivate init(
     descriptor: ServiceDescriptor,
     package: String,
-    protobufNamer: SwiftProtobufNamer
+    protobufNamer: SwiftProtobufNamer,
+    file: FileDescriptor
   ) {
     let methods = descriptor.methods.map {
       CodeGenerationRequest.ServiceDescriptor.MethodDescriptor(
@@ -120,10 +122,13 @@ extension CodeGenerationRequest.ServiceDescriptor {
       generatedUpperCase: NamingUtils.toUpperCamelCase(descriptor.name),
       generatedLowerCase: NamingUtils.toLowerCamelCase(descriptor.name)
     )
+
+    // Packages that are based on the path of the '.proto' file usually
+    // contain dots. For example: "grpc.test".
     let namespace = CodeGenerationRequest.Name(
       base: package,
-      generatedUpperCase: NamingUtils.toUpperCamelCase(package),
-      generatedLowerCase: NamingUtils.toLowerCamelCase(package)
+      generatedUpperCase: protobufNamer.formattedUpperCasePackage(file: file),
+      generatedLowerCase: protobufNamer.formattedLowerCasePackage(file: file)
     )
     let documentation = descriptor.protoSourceComments()
     self.init(documentation: documentation, name: name, namespace: namespace, methods: methods)
@@ -166,3 +171,28 @@ extension FileDescriptor {
     return header
   }
 }
+
+extension SwiftProtobufNamer {
+  internal func formattedUpperCasePackage(file: FileDescriptor) -> String {
+    let unformattedPackage = self.typePrefix(forFile: file)
+    return unformattedPackage.trimTrailingUnderscores()
+  }
+
+  internal func formattedLowerCasePackage(file: FileDescriptor) -> String {
+    let upperCasePackage = self.formattedUpperCasePackage(file: file)
+    let lowerCaseComponents = upperCasePackage.split(separator: "_").map { component in
+      NamingUtils.toLowerCamelCase(String(component))
+    }
+    return lowerCaseComponents.joined(separator: "_")
+  }
+}
+
+extension String {
+  internal func trimTrailingUnderscores() -> String {
+    if let index = self.lastIndex(where: { $0 != "_" }) {
+      return String(self[...index])
+    } else {
+      return ""
+    }
+  }
+}

+ 243 - 35
Tests/GRPCProtobufCodeGenTests/ProtobufCodeGenParserTests.swift

@@ -57,42 +57,8 @@ final class ProtobufCodeGenParserTests: XCTestCase {
       protoFileModuleMappings: ProtoFileToModuleMappings(moduleMappingsProto: moduleMappings),
       extraModuleImports: ["ExtraModule"]
     ).parse()
-    XCTAssertEqual(parsedCodeGenRequest.fileName, "helloworld.proto")
-    XCTAssertEqual(
-      parsedCodeGenRequest.leadingTrivia,
-      """
-      // Copyright 2015 gRPC authors.
-      //
-      // Licensed under the Apache License, Version 2.0 (the "License");
-      // you may not use this file except in compliance with the License.
-      // You may obtain a copy of the License at
-      //
-      //     http://www.apache.org/licenses/LICENSE-2.0
-      //
-      // Unless required by applicable law or agreed to in writing, software
-      // distributed under the License is distributed on an "AS IS" BASIS,
-      // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-      // See the License for the specific language governing permissions and
-      // limitations under the License.
 
-      // DO NOT EDIT.
-      // swift-format-ignore-file
-      //
-      // Generated by the gRPC Swift generator plugin for the protocol buffer compiler.
-      // Source: helloworld.proto
-      //
-      // For information on using the generated types, please see the documentation:
-      //   https://github.com/grpc/grpc-swift
-
-      """
-    )
-
-    XCTAssertEqual(parsedCodeGenRequest.dependencies.count, 3)
-    let expectedDependencyNames = ["GRPCProtobuf", "DifferentModule", "ExtraModule"]
-    let parsedDependencyNames = parsedCodeGenRequest.dependencies.map { $0.module }
-    XCTAssertEqual(parsedDependencyNames, expectedDependencyNames)
-
-    XCTAssertEqual(parsedCodeGenRequest.services.count, 1)
+    self.testCommonHelloworldParsedRequestFields(for: parsedCodeGenRequest)
 
     let expectedMethod = CodeGenerationRequest.ServiceDescriptor.MethodDescriptor(
       documentation: "/// Sends a greeting.\n",
@@ -127,6 +93,168 @@ final class ProtobufCodeGenParserTests: XCTestCase {
     XCTAssertEqual(service, expectedService)
     XCTAssertEqual(service.methods.count, 1)
 
+    XCTAssertEqual(
+      parsedCodeGenRequest.lookupSerializer("Helloworld_HelloRequest"),
+      "ProtobufSerializer<Helloworld_HelloRequest>()"
+    )
+    XCTAssertEqual(
+      parsedCodeGenRequest.lookupDeserializer("Helloworld_HelloRequest"),
+      "ProtobufDeserializer<Helloworld_HelloRequest>()"
+    )
+  }
+
+  func testParserNestedPackage() throws {
+    let descriptorSet = DescriptorSet(
+      protos: [
+        Google_Protobuf_FileDescriptorProto(
+          name: "same-module.proto",
+          package: "same-package"
+        ),
+        Google_Protobuf_FileDescriptorProto(
+          name: "different-module.proto",
+          package: "different-package"
+        ),
+        Google_Protobuf_FileDescriptorProto.helloWorldNestedPackage,
+      ]
+    )
+
+    guard let fileDescriptor = descriptorSet.fileDescriptor(named: "helloworld.proto") else {
+      return XCTFail(
+        """
+        Could not find the file descriptor of "helloworld.proto".
+        """
+      )
+    }
+    let moduleMappings = SwiftProtobuf_GenSwift_ModuleMappings.with {
+      $0.mapping = [
+        SwiftProtobuf_GenSwift_ModuleMappings.Entry.with {
+          $0.protoFilePath = ["different-module.proto"]
+          $0.moduleName = "DifferentModule"
+        }
+      ]
+    }
+    let parsedCodeGenRequest = try ProtobufCodeGenParser(
+      input: fileDescriptor,
+      protoFileModuleMappings: ProtoFileToModuleMappings(moduleMappingsProto: moduleMappings),
+      extraModuleImports: ["ExtraModule"]
+    ).parse()
+
+    self.testCommonHelloworldParsedRequestFields(for: parsedCodeGenRequest)
+
+    let expectedMethod = CodeGenerationRequest.ServiceDescriptor.MethodDescriptor(
+      documentation: "/// Sends a greeting.\n",
+      name: CodeGenerationRequest.Name(
+        base: "SayHello",
+        generatedUpperCase: "SayHello",
+        generatedLowerCase: "sayHello"
+      ),
+      isInputStreaming: false,
+      isOutputStreaming: false,
+      inputType: "Hello_World_HelloRequest",
+      outputType: "Hello_World_HelloReply"
+    )
+    guard let method = parsedCodeGenRequest.services.first?.methods.first else { return XCTFail() }
+    XCTAssertEqual(method, expectedMethod)
+
+    let expectedService = CodeGenerationRequest.ServiceDescriptor(
+      documentation: "/// The greeting service definition.\n",
+      name: CodeGenerationRequest.Name(
+        base: "Greeter",
+        generatedUpperCase: "Greeter",
+        generatedLowerCase: "greeter"
+      ),
+      namespace: CodeGenerationRequest.Name(
+        base: "hello.world",
+        generatedUpperCase: "Hello_World",
+        generatedLowerCase: "hello_world"
+      ),
+      methods: [expectedMethod]
+    )
+    guard let service = parsedCodeGenRequest.services.first else { return XCTFail() }
+    XCTAssertEqual(service, expectedService)
+    XCTAssertEqual(service.methods.count, 1)
+
+    XCTAssertEqual(
+      parsedCodeGenRequest.lookupSerializer("Hello_World_HelloRequest"),
+      "ProtobufSerializer<Hello_World_HelloRequest>()"
+    )
+    XCTAssertEqual(
+      parsedCodeGenRequest.lookupDeserializer("Hello_World_HelloRequest"),
+      "ProtobufDeserializer<Hello_World_HelloRequest>()"
+    )
+  }
+
+  func testParserEmptyPackage() throws {
+    let descriptorSet = DescriptorSet(
+      protos: [
+        Google_Protobuf_FileDescriptorProto(
+          name: "same-module.proto",
+          package: "same-package"
+        ),
+        Google_Protobuf_FileDescriptorProto(
+          name: "different-module.proto",
+          package: "different-package"
+        ),
+        Google_Protobuf_FileDescriptorProto.helloWorldEmptyPackage,
+      ]
+    )
+
+    guard let fileDescriptor = descriptorSet.fileDescriptor(named: "helloworld.proto") else {
+      return XCTFail(
+        """
+        Could not find the file descriptor of "helloworld.proto".
+        """
+      )
+    }
+    let moduleMappings = SwiftProtobuf_GenSwift_ModuleMappings.with {
+      $0.mapping = [
+        SwiftProtobuf_GenSwift_ModuleMappings.Entry.with {
+          $0.protoFilePath = ["different-module.proto"]
+          $0.moduleName = "DifferentModule"
+        }
+      ]
+    }
+    let parsedCodeGenRequest = try ProtobufCodeGenParser(
+      input: fileDescriptor,
+      protoFileModuleMappings: ProtoFileToModuleMappings(moduleMappingsProto: moduleMappings),
+      extraModuleImports: ["ExtraModule"]
+    ).parse()
+
+    self.testCommonHelloworldParsedRequestFields(for: parsedCodeGenRequest)
+
+    let expectedMethod = CodeGenerationRequest.ServiceDescriptor.MethodDescriptor(
+      documentation: "/// Sends a greeting.\n",
+      name: CodeGenerationRequest.Name(
+        base: "SayHello",
+        generatedUpperCase: "SayHello",
+        generatedLowerCase: "sayHello"
+      ),
+      isInputStreaming: false,
+      isOutputStreaming: false,
+      inputType: "HelloRequest",
+      outputType: "HelloReply"
+    )
+    guard let method = parsedCodeGenRequest.services.first?.methods.first else { return XCTFail() }
+    XCTAssertEqual(method, expectedMethod)
+
+    let expectedService = CodeGenerationRequest.ServiceDescriptor(
+      documentation: "/// The greeting service definition.\n",
+      name: CodeGenerationRequest.Name(
+        base: "Greeter",
+        generatedUpperCase: "Greeter",
+        generatedLowerCase: "greeter"
+      ),
+      namespace: CodeGenerationRequest.Name(
+        base: "",
+        generatedUpperCase: "",
+        generatedLowerCase: ""
+      ),
+      methods: [expectedMethod]
+    )
+    guard let service = parsedCodeGenRequest.services.first else { return XCTFail() }
+    XCTAssertEqual(service, expectedService)
+    XCTAssertEqual(service.methods.count, 1)
+
     XCTAssertEqual(
       parsedCodeGenRequest.lookupSerializer("HelloRequest"),
       "ProtobufSerializer<HelloRequest>()"
@@ -138,6 +266,45 @@ final class ProtobufCodeGenParserTests: XCTestCase {
   }
 }
 
+extension ProtobufCodeGenParserTests {
+  func testCommonHelloworldParsedRequestFields(for request: CodeGenerationRequest) {
+    XCTAssertEqual(request.fileName, "helloworld.proto")
+    XCTAssertEqual(
+      request.leadingTrivia,
+      """
+      // Copyright 2015 gRPC authors.
+      //
+      // Licensed under the Apache License, Version 2.0 (the "License");
+      // you may not use this file except in compliance with the License.
+      // You may obtain a copy of the License at
+      //
+      //     http://www.apache.org/licenses/LICENSE-2.0
+      //
+      // Unless required by applicable law or agreed to in writing, software
+      // distributed under the License is distributed on an "AS IS" BASIS,
+      // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      // See the License for the specific language governing permissions and
+      // limitations under the License.
+
+      // DO NOT EDIT.
+      // swift-format-ignore-file
+      //
+      // Generated by the gRPC Swift generator plugin for the protocol buffer compiler.
+      // Source: helloworld.proto
+      //
+      // For information on using the generated types, please see the documentation:
+      //   https://github.com/grpc/grpc-swift
+
+      """
+    )
+    XCTAssertEqual(request.dependencies.count, 3)
+    let expectedDependencyNames = ["GRPCProtobuf", "DifferentModule", "ExtraModule"]
+    let parsedDependencyNames = request.dependencies.map { $0.module }
+    XCTAssertEqual(parsedDependencyNames, expectedDependencyNames)
+    XCTAssertEqual(request.services.count, 1)
+  }
+}
+
 extension Google_Protobuf_FileDescriptorProto {
   static var helloWorld: Google_Protobuf_FileDescriptorProto {
     let requestType = Google_Protobuf_DescriptorProto.with {
@@ -224,6 +391,47 @@ extension Google_Protobuf_FileDescriptorProto {
     }
   }
 
+  static var helloWorldNestedPackage: Google_Protobuf_FileDescriptorProto {
+    let service = Google_Protobuf_ServiceDescriptorProto.with {
+      $0.name = "Greeter"
+      $0.method = [
+        Google_Protobuf_MethodDescriptorProto.with {
+          $0.name = "SayHello"
+          $0.inputType = ".hello.world.HelloRequest"
+          $0.outputType = ".hello.world.HelloReply"
+          $0.clientStreaming = false
+          $0.serverStreaming = false
+        }
+      ]
+    }
+
+    var helloWorldCopy = self.helloWorld
+    helloWorldCopy.package = "hello.world"
+    helloWorldCopy.service = [service]
+
+    return helloWorldCopy
+  }
+
+  static var helloWorldEmptyPackage: Google_Protobuf_FileDescriptorProto {
+    let service = Google_Protobuf_ServiceDescriptorProto.with {
+      $0.name = "Greeter"
+      $0.method = [
+        Google_Protobuf_MethodDescriptorProto.with {
+          $0.name = "SayHello"
+          $0.inputType = ".HelloRequest"
+          $0.outputType = ".HelloReply"
+          $0.clientStreaming = false
+          $0.serverStreaming = false
+        }
+      ]
+    }
+    var helloWorldCopy = self.helloWorld
+    helloWorldCopy.package = ""
+    helloWorldCopy.service = [service]
+
+    return helloWorldCopy
+  }
+
   internal init(name: String, package: String) {
     self.init()
     self.name = name

+ 62 - 58
Tests/GRPCProtobufCodeGenTests/ProtobufCodeGeneratorTests.swift

@@ -25,6 +25,7 @@ import XCTest
 final class ProtobufCodeGeneratorTests: XCTestCase {
   func testProtobufCodeGenerator() throws {
     try testCodeGeneration(
+      proto: Google_Protobuf_FileDescriptorProto.helloWorldNestedPackage,
       indentation: 4,
       visibility: .internal,
       client: true,
@@ -58,13 +59,13 @@ final class ProtobufCodeGeneratorTests: XCTestCase {
         import DifferentModule
         import ExtraModule
 
-        internal enum Helloworld_Greeter {
+        internal enum Hello_World_Greeter {
             internal enum Method {
                 internal enum SayHello {
-                    internal typealias Input = Helloworld_HelloRequest
-                    internal typealias Output = Helloworld_HelloReply
+                    internal typealias Input = Hello_World_HelloRequest
+                    internal typealias Output = Hello_World_HelloReply
                     internal static let descriptor = MethodDescriptor(
-                        service: "helloworld.Greeter",
+                        service: "hello.world.Greeter",
                         method: "SayHello"
                     )
                 }
@@ -73,33 +74,33 @@ final class ProtobufCodeGeneratorTests: XCTestCase {
                 ]
             }
             @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-            internal typealias ClientProtocol = Helloworld_GreeterClientProtocol
+            internal typealias ClientProtocol = Hello_World_GreeterClientProtocol
             @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-            internal typealias Client = Helloworld_GreeterClient
+            internal typealias Client = Hello_World_GreeterClient
         }
 
         /// The greeting service definition.
         @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-        internal protocol Helloworld_GreeterClientProtocol: Sendable {
+        internal protocol Hello_World_GreeterClientProtocol: Sendable {
             /// Sends a greeting.
             func sayHello<R>(
-                request: ClientRequest.Single<Helloworld_Greeter.Method.SayHello.Input>,
-                serializer: some MessageSerializer<Helloworld_Greeter.Method.SayHello.Input>,
-                deserializer: some MessageDeserializer<Helloworld_Greeter.Method.SayHello.Output>,
-                _ body: @Sendable @escaping (ClientResponse.Single<Helloworld_Greeter.Method.SayHello.Output>) async throws -> R
+                request: ClientRequest.Single<Hello_World_Greeter.Method.SayHello.Input>,
+                serializer: some MessageSerializer<Hello_World_Greeter.Method.SayHello.Input>,
+                deserializer: some MessageDeserializer<Hello_World_Greeter.Method.SayHello.Output>,
+                _ body: @Sendable @escaping (ClientResponse.Single<Hello_World_Greeter.Method.SayHello.Output>) async throws -> R
             ) async throws -> R where R: Sendable
         }
 
         @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-        extension Helloworld_Greeter.ClientProtocol {
+        extension Hello_World_Greeter.ClientProtocol {
             internal func sayHello<R>(
-                request: ClientRequest.Single<Helloworld_Greeter.Method.SayHello.Input>,
-                _ body: @Sendable @escaping (ClientResponse.Single<Helloworld_Greeter.Method.SayHello.Output>) async throws -> R
+                request: ClientRequest.Single<Hello_World_Greeter.Method.SayHello.Input>,
+                _ body: @Sendable @escaping (ClientResponse.Single<Hello_World_Greeter.Method.SayHello.Output>) async throws -> R
             ) async throws -> R where R: Sendable {
                 try await self.sayHello(
                     request: request,
-                    serializer: ProtobufSerializer<Helloworld_Greeter.Method.SayHello.Input>(),
-                    deserializer: ProtobufDeserializer<Helloworld_Greeter.Method.SayHello.Output>(),
+                    serializer: ProtobufSerializer<Hello_World_Greeter.Method.SayHello.Input>(),
+                    deserializer: ProtobufDeserializer<Hello_World_Greeter.Method.SayHello.Output>(),
                     body
                 )
             }
@@ -107,7 +108,7 @@ final class ProtobufCodeGeneratorTests: XCTestCase {
 
         /// The greeting service definition.
         @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-        internal struct Helloworld_GreeterClient: Helloworld_Greeter.ClientProtocol {
+        internal struct Hello_World_GreeterClient: Hello_World_Greeter.ClientProtocol {
             private let client: GRPCCore.GRPCClient
             
             internal init(client: GRPCCore.GRPCClient) {
@@ -116,14 +117,14 @@ final class ProtobufCodeGeneratorTests: XCTestCase {
             
             /// Sends a greeting.
             internal func sayHello<R>(
-                request: ClientRequest.Single<Helloworld_Greeter.Method.SayHello.Input>,
-                serializer: some MessageSerializer<Helloworld_Greeter.Method.SayHello.Input>,
-                deserializer: some MessageDeserializer<Helloworld_Greeter.Method.SayHello.Output>,
-                _ body: @Sendable @escaping (ClientResponse.Single<Helloworld_Greeter.Method.SayHello.Output>) async throws -> R
+                request: ClientRequest.Single<Hello_World_Greeter.Method.SayHello.Input>,
+                serializer: some MessageSerializer<Hello_World_Greeter.Method.SayHello.Input>,
+                deserializer: some MessageDeserializer<Hello_World_Greeter.Method.SayHello.Output>,
+                _ body: @Sendable @escaping (ClientResponse.Single<Hello_World_Greeter.Method.SayHello.Output>) async throws -> R
             ) async throws -> R where R: Sendable {
                 try await self.client.unary(
                     request: request,
-                    descriptor: Helloworld_Greeter.Method.SayHello.descriptor,
+                    descriptor: Hello_World_Greeter.Method.SayHello.descriptor,
                     serializer: serializer,
                     deserializer: deserializer,
                     handler: body
@@ -134,6 +135,7 @@ final class ProtobufCodeGeneratorTests: XCTestCase {
     )
 
     try testCodeGeneration(
+      proto: Google_Protobuf_FileDescriptorProto.helloWorld,
       indentation: 2,
       visibility: .public,
       client: false,
@@ -228,6 +230,7 @@ final class ProtobufCodeGeneratorTests: XCTestCase {
         """
     )
     try testCodeGeneration(
+      proto: Google_Protobuf_FileDescriptorProto.helloWorldEmptyPackage,
       indentation: 2,
       visibility: .package,
       client: true,
@@ -261,13 +264,13 @@ final class ProtobufCodeGeneratorTests: XCTestCase {
         import DifferentModule
         import ExtraModule
 
-        package enum Helloworld_Greeter {
+        package enum Greeter {
           package enum Method {
             package enum SayHello {
-              package typealias Input = Helloworld_HelloRequest
-              package typealias Output = Helloworld_HelloReply
+              package typealias Input = HelloRequest
+              package typealias Output = HelloReply
               package static let descriptor = MethodDescriptor(
-                service: "helloworld.Greeter",
+                service: "Greeter",
                 method: "SayHello"
               )
             }
@@ -276,31 +279,31 @@ final class ProtobufCodeGeneratorTests: XCTestCase {
             ]
           }
           @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-          package typealias StreamingServiceProtocol = Helloworld_GreeterStreamingServiceProtocol
+          package typealias StreamingServiceProtocol = GreeterStreamingServiceProtocol
           @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-          package typealias ServiceProtocol = Helloworld_GreeterServiceProtocol
+          package typealias ServiceProtocol = GreeterServiceProtocol
           @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-          package typealias ClientProtocol = Helloworld_GreeterClientProtocol
+          package typealias ClientProtocol = GreeterClientProtocol
           @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-          package typealias Client = Helloworld_GreeterClient
+          package typealias Client = GreeterClient
         }
 
         /// The greeting service definition.
         @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-        package protocol Helloworld_GreeterStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
+        package protocol GreeterStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
           /// Sends a greeting.
-          func sayHello(request: ServerRequest.Stream<Helloworld_Greeter.Method.SayHello.Input>) async throws -> ServerResponse.Stream<Helloworld_Greeter.Method.SayHello.Output>
+          func sayHello(request: ServerRequest.Stream<Greeter.Method.SayHello.Input>) async throws -> ServerResponse.Stream<Greeter.Method.SayHello.Output>
         }
 
         /// Conformance to `GRPCCore.RegistrableRPCService`.
         @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-        extension Helloworld_Greeter.StreamingServiceProtocol {
+        extension Greeter.StreamingServiceProtocol {
           @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
           package func registerMethods(with router: inout GRPCCore.RPCRouter) {
             router.registerHandler(
-              forMethod: Helloworld_Greeter.Method.SayHello.descriptor,
-              deserializer: ProtobufDeserializer<Helloworld_Greeter.Method.SayHello.Input>(),
-              serializer: ProtobufSerializer<Helloworld_Greeter.Method.SayHello.Output>(),
+              forMethod: Greeter.Method.SayHello.descriptor,
+              deserializer: ProtobufDeserializer<Greeter.Method.SayHello.Input>(),
+              serializer: ProtobufSerializer<Greeter.Method.SayHello.Output>(),
               handler: { request in
                 try await self.sayHello(request: request)
               }
@@ -310,15 +313,15 @@ final class ProtobufCodeGeneratorTests: XCTestCase {
 
         /// The greeting service definition.
         @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-        package protocol Helloworld_GreeterServiceProtocol: Helloworld_Greeter.StreamingServiceProtocol {
+        package protocol GreeterServiceProtocol: Greeter.StreamingServiceProtocol {
           /// Sends a greeting.
-          func sayHello(request: ServerRequest.Single<Helloworld_Greeter.Method.SayHello.Input>) async throws -> ServerResponse.Single<Helloworld_Greeter.Method.SayHello.Output>
+          func sayHello(request: ServerRequest.Single<Greeter.Method.SayHello.Input>) async throws -> ServerResponse.Single<Greeter.Method.SayHello.Output>
         }
 
-        /// Partial conformance to `Helloworld_GreeterStreamingServiceProtocol`.
+        /// Partial conformance to `GreeterStreamingServiceProtocol`.
         @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-        extension Helloworld_Greeter.ServiceProtocol {
-          package func sayHello(request: ServerRequest.Stream<Helloworld_Greeter.Method.SayHello.Input>) async throws -> ServerResponse.Stream<Helloworld_Greeter.Method.SayHello.Output> {
+        extension Greeter.ServiceProtocol {
+          package func sayHello(request: ServerRequest.Stream<Greeter.Method.SayHello.Input>) async throws -> ServerResponse.Stream<Greeter.Method.SayHello.Output> {
             let response = try await self.sayHello(request: ServerRequest.Single(stream: request))
             return ServerResponse.Stream(single: response)
           }
@@ -326,26 +329,26 @@ final class ProtobufCodeGeneratorTests: XCTestCase {
 
         /// The greeting service definition.
         @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-        package protocol Helloworld_GreeterClientProtocol: Sendable {
+        package protocol GreeterClientProtocol: Sendable {
           /// Sends a greeting.
           func sayHello<R>(
-            request: ClientRequest.Single<Helloworld_Greeter.Method.SayHello.Input>,
-            serializer: some MessageSerializer<Helloworld_Greeter.Method.SayHello.Input>,
-            deserializer: some MessageDeserializer<Helloworld_Greeter.Method.SayHello.Output>,
-            _ body: @Sendable @escaping (ClientResponse.Single<Helloworld_Greeter.Method.SayHello.Output>) async throws -> R
+            request: ClientRequest.Single<Greeter.Method.SayHello.Input>,
+            serializer: some MessageSerializer<Greeter.Method.SayHello.Input>,
+            deserializer: some MessageDeserializer<Greeter.Method.SayHello.Output>,
+            _ body: @Sendable @escaping (ClientResponse.Single<Greeter.Method.SayHello.Output>) async throws -> R
           ) async throws -> R where R: Sendable
         }
 
         @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-        extension Helloworld_Greeter.ClientProtocol {
+        extension Greeter.ClientProtocol {
           package func sayHello<R>(
-            request: ClientRequest.Single<Helloworld_Greeter.Method.SayHello.Input>,
-            _ body: @Sendable @escaping (ClientResponse.Single<Helloworld_Greeter.Method.SayHello.Output>) async throws -> R
+            request: ClientRequest.Single<Greeter.Method.SayHello.Input>,
+            _ body: @Sendable @escaping (ClientResponse.Single<Greeter.Method.SayHello.Output>) async throws -> R
           ) async throws -> R where R: Sendable {
             try await self.sayHello(
               request: request,
-              serializer: ProtobufSerializer<Helloworld_Greeter.Method.SayHello.Input>(),
-              deserializer: ProtobufDeserializer<Helloworld_Greeter.Method.SayHello.Output>(),
+              serializer: ProtobufSerializer<Greeter.Method.SayHello.Input>(),
+              deserializer: ProtobufDeserializer<Greeter.Method.SayHello.Output>(),
               body
             )
           }
@@ -353,7 +356,7 @@ final class ProtobufCodeGeneratorTests: XCTestCase {
 
         /// The greeting service definition.
         @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
-        package struct Helloworld_GreeterClient: Helloworld_Greeter.ClientProtocol {
+        package struct GreeterClient: Greeter.ClientProtocol {
           private let client: GRPCCore.GRPCClient
           
           package init(client: GRPCCore.GRPCClient) {
@@ -362,14 +365,14 @@ final class ProtobufCodeGeneratorTests: XCTestCase {
           
           /// Sends a greeting.
           package func sayHello<R>(
-            request: ClientRequest.Single<Helloworld_Greeter.Method.SayHello.Input>,
-            serializer: some MessageSerializer<Helloworld_Greeter.Method.SayHello.Input>,
-            deserializer: some MessageDeserializer<Helloworld_Greeter.Method.SayHello.Output>,
-            _ body: @Sendable @escaping (ClientResponse.Single<Helloworld_Greeter.Method.SayHello.Output>) async throws -> R
+            request: ClientRequest.Single<Greeter.Method.SayHello.Input>,
+            serializer: some MessageSerializer<Greeter.Method.SayHello.Input>,
+            deserializer: some MessageDeserializer<Greeter.Method.SayHello.Output>,
+            _ body: @Sendable @escaping (ClientResponse.Single<Greeter.Method.SayHello.Output>) async throws -> R
           ) async throws -> R where R: Sendable {
             try await self.client.unary(
               request: request,
-              descriptor: Helloworld_Greeter.Method.SayHello.descriptor,
+              descriptor: Greeter.Method.SayHello.descriptor,
               serializer: serializer,
               deserializer: deserializer,
               handler: body
@@ -381,6 +384,7 @@ final class ProtobufCodeGeneratorTests: XCTestCase {
   }
 
   func testCodeGeneration(
+    proto: Google_Protobuf_FileDescriptorProto,
     indentation: Int,
     visibility: SourceGenerator.Configuration.AccessLevel,
     client: Bool,
@@ -400,7 +404,7 @@ final class ProtobufCodeGeneratorTests: XCTestCase {
           name: "different-module.proto",
           package: "different-package"
         ),
-        Google_Protobuf_FileDescriptorProto.helloWorld,
+        proto,
       ])
     guard let fileDescriptor = descriptorSet.fileDescriptor(named: "helloworld.proto") else {
       return XCTFail(