Skip to content

Commit

Permalink
Simplify and update code gen tests (#14)
Browse files Browse the repository at this point in the history
Motivation:

The protobuf code generator doesn't actually do a lot: it parses a
protobuf file descriptor and turns that into a request for the code
generator provided by the GRPCCodeGen module. This means that the tests
should focus on the conversion rather than the generated code (although
this is still useful to test at a high level).

As it stands all tests are done on the generated code rather than the
conversion to a code generator request. The existing tests also hand
roll a protobuf file descriptor which is tedious and error prone.

The upstream code generator also has changes which aren't yet reflected
here.

Modifications:

- Define some test proto files for which we generate serialized protobuf
file descriptor sets.
- Add a suite of code gen parser tests which check the request created
from the file descriptor proto.
- Add a single code generator test.
- Downgrade an access level from public to package as public wasn't
necessary.

Result:

Better tests
  • Loading branch information
glbrntt authored Dec 3, 2024
1 parent eaebe06 commit 66dd0ce
Show file tree
Hide file tree
Showing 16 changed files with 1,395 additions and 963 deletions.
2 changes: 2 additions & 0 deletions .licenseignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ Dockerfile
Snippets/*
dev/git.commit.template
dev/version-bump.commit.template
dev/protos/local/*
.unacceptablelanguageignore
LICENSE
**/*.swift
*.pb
3 changes: 3 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ let targets: [Target] = [
.product(name: "SwiftProtobuf", package: "swift-protobuf"),
.product(name: "SwiftProtobufPluginLibrary", package: "swift-protobuf"),
],
resources: [
.copy("Generated")
],
swiftSettings: defaultSwiftSettings
),
]
Expand Down
56 changes: 32 additions & 24 deletions Sources/GRPCProtobufCodeGen/ProtobufCodeGenParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,45 +15,50 @@
*/

internal import Foundation
internal import GRPCCodeGen
internal import SwiftProtobufPluginLibrary
internal import SwiftProtobuf
package import SwiftProtobufPluginLibrary

package import struct GRPCCodeGen.CodeGenerationRequest
package import struct GRPCCodeGen.Dependency
package import struct GRPCCodeGen.MethodDescriptor
package import struct GRPCCodeGen.Name
package import struct GRPCCodeGen.ServiceDescriptor
package import struct GRPCCodeGen.SourceGenerator

/// Parses a ``FileDescriptor`` object into a ``CodeGenerationRequest`` object.
internal struct ProtobufCodeGenParser {
let input: FileDescriptor
let namer: SwiftProtobufNamer
package struct ProtobufCodeGenParser {
let extraModuleImports: [String]
let protoToModuleMappings: ProtoFileToModuleMappings
let accessLevel: SourceGenerator.Config.AccessLevel

internal init(
input: FileDescriptor,
package init(
protoFileModuleMappings: ProtoFileToModuleMappings,
extraModuleImports: [String],
accessLevel: SourceGenerator.Config.AccessLevel
) {
self.input = input
self.extraModuleImports = extraModuleImports
self.protoToModuleMappings = protoFileModuleMappings
self.namer = SwiftProtobufNamer(
currentFile: input,
protoFileToModuleMappings: protoFileModuleMappings
)
self.accessLevel = accessLevel
}

internal func parse() throws -> CodeGenerationRequest {
var header = self.input.header
package func parse(descriptor: FileDescriptor) throws -> CodeGenerationRequest {
let namer = SwiftProtobufNamer(
currentFile: descriptor,
protoFileToModuleMappings: self.protoToModuleMappings
)

var header = descriptor.header
// Ensuring there is a blank line after the header.
if !header.isEmpty && !header.hasSuffix("\n\n") {
header.append("\n")
}

let leadingTrivia = """
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the gRPC Swift generator plugin for the protocol buffer compiler.
// Source: \(self.input.name)
// Source: \(descriptor.name)
//
// For information on using the generated types, please see the documentation:
// https://github.com/grpc/grpc-swift
Expand All @@ -65,19 +70,20 @@ internal struct ProtobufCodeGenParser {
let lookupDeserializer: (String) -> String = { messageType in
"GRPCProtobuf.ProtobufDeserializer<\(messageType)>()"
}
let services = self.input.services.map {
ServiceDescriptor(

let services = descriptor.services.map {
GRPCCodeGen.ServiceDescriptor(
descriptor: $0,
package: input.package,
protobufNamer: self.namer,
file: self.input
package: descriptor.package,
protobufNamer: namer,
file: descriptor
)
}

return CodeGenerationRequest(
fileName: self.input.name,
fileName: descriptor.name,
leadingTrivia: header + leadingTrivia,
dependencies: self.codeDependencies,
dependencies: self.codeDependencies(file: descriptor),
services: services,
lookupSerializer: lookupSerializer,
lookupDeserializer: lookupDeserializer
Expand All @@ -86,14 +92,16 @@ internal struct ProtobufCodeGenParser {
}

extension ProtobufCodeGenParser {
fileprivate var codeDependencies: [Dependency] {
fileprivate func codeDependencies(
file: FileDescriptor
) -> [Dependency] {
var codeDependencies: [Dependency] = [
.init(module: "GRPCProtobuf", accessLevel: .internal)
]
// Adding as dependencies the modules containing generated code or types for
// '.proto' files imported in the '.proto' file we are parsing.
codeDependencies.append(
contentsOf: (self.protoToModuleMappings.neededModules(forFile: self.input) ?? []).map {
contentsOf: (self.protoToModuleMappings.neededModules(forFile: file) ?? []).map {
Dependency(module: $0, accessLevel: self.accessLevel)
}
)
Expand Down
25 changes: 12 additions & 13 deletions Sources/GRPCProtobufCodeGen/ProtobufCodeGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,31 @@
* limitations under the License.
*/

public import GRPCCodeGen
public import SwiftProtobufPluginLibrary
package import GRPCCodeGen
package import SwiftProtobufPluginLibrary

public struct ProtobufCodeGenerator {
internal var configuration: SourceGenerator.Config
package struct ProtobufCodeGenerator {
internal var config: SourceGenerator.Config

public init(
configuration: SourceGenerator.Config
package init(
config: SourceGenerator.Config
) {
self.configuration = configuration
self.config = config
}

public func generateCode(
from fileDescriptor: FileDescriptor,
package func generateCode(
fileDescriptor: FileDescriptor,
protoFileModuleMappings: ProtoFileToModuleMappings,
extraModuleImports: [String]
) throws -> String {
let parser = ProtobufCodeGenParser(
input: fileDescriptor,
protoFileModuleMappings: protoFileModuleMappings,
extraModuleImports: extraModuleImports,
accessLevel: self.configuration.accessLevel
accessLevel: self.config.accessLevel
)
let sourceGenerator = SourceGenerator(config: self.configuration)
let sourceGenerator = SourceGenerator(config: self.config)

let codeGenerationRequest = try parser.parse()
let codeGenerationRequest = try parser.parse(descriptor: fileDescriptor)
let sourceFile = try sourceGenerator.generate(codeGenerationRequest)
return sourceFile.contents
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/protoc-gen-grpc-swift/GenerateGRPC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ final class GenerateGRPC: CodeGenerator {
)

let config = SourceGenerator.Config(options: options)
let fileGenerator = ProtobufCodeGenerator(configuration: config)
let fileGenerator = ProtobufCodeGenerator(config: config)
let contents = try fileGenerator.generateCode(
from: descriptor,
fileDescriptor: descriptor,
protoFileModuleMappings: options.protoToModuleMappings,
extraModuleImports: options.extraModuleImports
)
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 66dd0ce

Please sign in to comment.