Skip to content

Commit 2a383b6

Browse files
committed
Add a CompileTest for "multi module" generation.
- Add basic infrastructure to have Compile Tests. - Add a specific MultiModule CompileTest. - This ensure that with `import public` is properly handle and the generated code compiles even when a needed type is coming from a public import. - So the any relevant code changes are more visible, check the the generated code so the diffs for an changes related to the test will be easily reviewed. - The SPM plugin doesn't support multi module generation (#1450), which is also why the code needs to be checked in, otherwise, it might simplify the tests. Note: The whole concept of CompileTests doesn't have to be a set up as distinct Swift Packages, but if we put the required targets in the main Package.swift, all projects using swift-protobuf would end up having the "overhead" of those test only targets, so I've errored on the side of a distinct package to make sure there is no impact of these tests on the folks using swift-protobuf.
1 parent da0566a commit 2a383b6

File tree

23 files changed

+1229
-1
lines changed

23 files changed

+1229
-1
lines changed

.github/workflows/build.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ jobs:
102102
- name: Test SPM plugin
103103
working-directory: main
104104
run: make test-spm-plugin PROTOC=../protobuf/cmake_build/protoc
105+
- name: Compilation Tests
106+
working-directory: main
107+
run: make compile-tests PROTOC=../protobuf/cmake_build/protoc
105108

106109
sanitizer_testing:
107110
runs-on: ubuntu-latest

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ xcbaselines
99
/docs
1010
/build
1111
mined_words.txt
12+
/CompileTests/MultiModule/.build
13+
/CompileTests/MultiModule/.swiftpm
1214
/*DescriptorTestData.bin
1315
/Package.resolved
1416

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// swift-tools-version: 5.6
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "CompileTests",
7+
dependencies: [
8+
.package(name: "swift-protobuf", path: "../..")
9+
],
10+
targets: [
11+
.testTarget(
12+
name: "Test1",
13+
dependencies: ["ImportsAPublicly"]
14+
),
15+
.testTarget(
16+
name: "Test2",
17+
dependencies: ["ImportsImportsAPublicly"]
18+
),
19+
.target(
20+
name: "ModuleA",
21+
dependencies: [
22+
.product(name: "SwiftProtobuf", package: "swift-protobuf"),
23+
]
24+
),
25+
.target(
26+
name: "ImportsAPublicly",
27+
dependencies: [
28+
.product(name: "SwiftProtobuf", package: "swift-protobuf"),
29+
.target(name: "ModuleA"),
30+
]
31+
),
32+
.target(
33+
name: "ImportsImportsAPublicly",
34+
dependencies: [
35+
.product(name: "SwiftProtobuf", package: "swift-protobuf"),
36+
.target(name: "ImportsAPublicly"),
37+
]
38+
),
39+
]
40+
)

CompileTests/MultiModule/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# CompileTests/MultiModule
2+
3+
This is a test case that uses sources generated into multiple modules and
4+
ensures the generated code compiles with the cross modules references.
5+
6+
This can't use the SwiftPM Plugin as that currently doesn't have support for the
7+
module mappings.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// DO NOT EDIT.
2+
// swift-format-ignore-file
3+
//
4+
// Generated by the Swift generator plugin for the protocol buffer compiler.
5+
// Source: Sources/ImportsAPublicly/imports_a_publicly.proto
6+
//
7+
// For information on using the generated types, please see the documentation:
8+
// https://github.com/apple/swift-protobuf/
9+
10+
import Foundation
11+
import SwiftProtobuf
12+
13+
import ModuleA
14+
15+
// If the compiler emits an error on this type, it is because this file
16+
// was generated by a version of the `protoc` Swift plug-in that is
17+
// incompatible with the version of SwiftProtobuf to which you are linking.
18+
// Please ensure that you are building against the same version of the API
19+
// that was used to generate this file.
20+
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
21+
struct _3: SwiftProtobuf.ProtobufAPIVersion_3 {}
22+
typealias Version = _3
23+
}
24+
25+
public struct ImportsAPublicly: Sendable {
26+
// SwiftProtobuf.Message conformance is added in an extension below. See the
27+
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
28+
// methods supported on all messages.
29+
30+
public var a: ModuleA.A {
31+
get {return _a ?? ModuleA.A()}
32+
set {_a = newValue}
33+
}
34+
/// Returns true if `a` has been explicitly set.
35+
public var hasA: Bool {return self._a != nil}
36+
/// Clears the value of `a`. Subsequent reads from it will return its default value.
37+
public mutating func clearA() {self._a = nil}
38+
39+
public var e: ModuleA.E {
40+
get {return _e ?? .unset}
41+
set {_e = newValue}
42+
}
43+
/// Returns true if `e` has been explicitly set.
44+
public var hasE: Bool {return self._e != nil}
45+
/// Clears the value of `e`. Subsequent reads from it will return its default value.
46+
public mutating func clearE() {self._e = nil}
47+
48+
public var unknownFields = SwiftProtobuf.UnknownStorage()
49+
50+
public init() {}
51+
52+
fileprivate var _a: ModuleA.A? = nil
53+
fileprivate var _e: ModuleA.E? = nil
54+
}
55+
56+
// MARK: - Code below here is support for the SwiftProtobuf runtime.
57+
58+
extension ImportsAPublicly: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
59+
public static let protoMessageName: String = "ImportsAPublicly"
60+
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
61+
11: .same(proto: "a"),
62+
12: .same(proto: "e"),
63+
]
64+
65+
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
66+
while let fieldNumber = try decoder.nextFieldNumber() {
67+
// The use of inline closures is to circumvent an issue where the compiler
68+
// allocates stack space for every case branch when no optimizations are
69+
// enabled. https://github.com/apple/swift-protobuf/issues/1034
70+
switch fieldNumber {
71+
case 11: try { try decoder.decodeSingularMessageField(value: &self._a) }()
72+
case 12: try { try decoder.decodeSingularEnumField(value: &self._e) }()
73+
default: break
74+
}
75+
}
76+
}
77+
78+
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
79+
// The use of inline closures is to circumvent an issue where the compiler
80+
// allocates stack space for every if/case branch local when no optimizations
81+
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
82+
// https://github.com/apple/swift-protobuf/issues/1182
83+
try { if let v = self._a {
84+
try visitor.visitSingularMessageField(value: v, fieldNumber: 11)
85+
} }()
86+
try { if let v = self._e {
87+
try visitor.visitSingularEnumField(value: v, fieldNumber: 12)
88+
} }()
89+
try unknownFields.traverse(visitor: &visitor)
90+
}
91+
92+
public static func ==(lhs: ImportsAPublicly, rhs: ImportsAPublicly) -> Bool {
93+
if lhs._a != rhs._a {return false}
94+
if lhs._e != rhs._e {return false}
95+
if lhs.unknownFields != rhs.unknownFields {return false}
96+
return true
97+
}
98+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// DO NOT EDIT.
2+
// swift-format-ignore-file
3+
//
4+
// Generated by the Swift generator plugin for the protocol buffer compiler.
5+
// Source: Sources/ImportsImportsAPublicly/imports_imports_a_publicly.proto
6+
//
7+
// For information on using the generated types, please see the documentation:
8+
// https://github.com/apple/swift-protobuf/
9+
10+
import Foundation
11+
import SwiftProtobuf
12+
13+
import ImportsAPublicly
14+
import ModuleA
15+
16+
// If the compiler emits an error on this type, it is because this file
17+
// was generated by a version of the `protoc` Swift plug-in that is
18+
// incompatible with the version of SwiftProtobuf to which you are linking.
19+
// Please ensure that you are building against the same version of the API
20+
// that was used to generate this file.
21+
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
22+
struct _3: SwiftProtobuf.ProtobufAPIVersion_3 {}
23+
typealias Version = _3
24+
}
25+
26+
public struct ImportsImportsAPublicly: Sendable {
27+
// SwiftProtobuf.Message conformance is added in an extension below. See the
28+
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
29+
// methods supported on all messages.
30+
31+
public var a: ModuleA.A {
32+
get {return _a ?? ModuleA.A()}
33+
set {_a = newValue}
34+
}
35+
/// Returns true if `a` has been explicitly set.
36+
public var hasA: Bool {return self._a != nil}
37+
/// Clears the value of `a`. Subsequent reads from it will return its default value.
38+
public mutating func clearA() {self._a = nil}
39+
40+
public var e: ModuleA.E {
41+
get {return _e ?? .unset}
42+
set {_e = newValue}
43+
}
44+
/// Returns true if `e` has been explicitly set.
45+
public var hasE: Bool {return self._e != nil}
46+
/// Clears the value of `e`. Subsequent reads from it will return its default value.
47+
public mutating func clearE() {self._e = nil}
48+
49+
public var unknownFields = SwiftProtobuf.UnknownStorage()
50+
51+
public init() {}
52+
53+
fileprivate var _a: ModuleA.A? = nil
54+
fileprivate var _e: ModuleA.E? = nil
55+
}
56+
57+
// MARK: - Code below here is support for the SwiftProtobuf runtime.
58+
59+
extension ImportsImportsAPublicly: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
60+
public static let protoMessageName: String = "ImportsImportsAPublicly"
61+
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
62+
21: .same(proto: "a"),
63+
22: .same(proto: "e"),
64+
]
65+
66+
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
67+
while let fieldNumber = try decoder.nextFieldNumber() {
68+
// The use of inline closures is to circumvent an issue where the compiler
69+
// allocates stack space for every case branch when no optimizations are
70+
// enabled. https://github.com/apple/swift-protobuf/issues/1034
71+
switch fieldNumber {
72+
case 21: try { try decoder.decodeSingularMessageField(value: &self._a) }()
73+
case 22: try { try decoder.decodeSingularEnumField(value: &self._e) }()
74+
default: break
75+
}
76+
}
77+
}
78+
79+
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
80+
// The use of inline closures is to circumvent an issue where the compiler
81+
// allocates stack space for every if/case branch local when no optimizations
82+
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
83+
// https://github.com/apple/swift-protobuf/issues/1182
84+
try { if let v = self._a {
85+
try visitor.visitSingularMessageField(value: v, fieldNumber: 21)
86+
} }()
87+
try { if let v = self._e {
88+
try visitor.visitSingularEnumField(value: v, fieldNumber: 22)
89+
} }()
90+
try unknownFields.traverse(visitor: &visitor)
91+
}
92+
93+
public static func ==(lhs: ImportsImportsAPublicly, rhs: ImportsImportsAPublicly) -> Bool {
94+
if lhs._a != rhs._a {return false}
95+
if lhs._e != rhs._e {return false}
96+
if lhs.unknownFields != rhs.unknownFields {return false}
97+
return true
98+
}
99+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// DO NOT EDIT.
2+
// swift-format-ignore-file
3+
//
4+
// Generated by the Swift generator plugin for the protocol buffer compiler.
5+
// Source: Sources/ModuleA/a.proto
6+
//
7+
// For information on using the generated types, please see the documentation:
8+
// https://github.com/apple/swift-protobuf/
9+
10+
import Foundation
11+
import SwiftProtobuf
12+
13+
// If the compiler emits an error on this type, it is because this file
14+
// was generated by a version of the `protoc` Swift plug-in that is
15+
// incompatible with the version of SwiftProtobuf to which you are linking.
16+
// Please ensure that you are building against the same version of the API
17+
// that was used to generate this file.
18+
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
19+
struct _3: SwiftProtobuf.ProtobufAPIVersion_3 {}
20+
typealias Version = _3
21+
}
22+
23+
public enum E: SwiftProtobuf.Enum {
24+
public typealias RawValue = Int
25+
case unset // = 0
26+
case a // = 1
27+
case b // = 2
28+
29+
public init() {
30+
self = .unset
31+
}
32+
33+
public init?(rawValue: Int) {
34+
switch rawValue {
35+
case 0: self = .unset
36+
case 1: self = .a
37+
case 2: self = .b
38+
default: return nil
39+
}
40+
}
41+
42+
public var rawValue: Int {
43+
switch self {
44+
case .unset: return 0
45+
case .a: return 1
46+
case .b: return 2
47+
}
48+
}
49+
50+
}
51+
52+
public struct A: Sendable {
53+
// SwiftProtobuf.Message conformance is added in an extension below. See the
54+
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
55+
// methods supported on all messages.
56+
57+
public var e: E {
58+
get {return _e ?? .unset}
59+
set {_e = newValue}
60+
}
61+
/// Returns true if `e` has been explicitly set.
62+
public var hasE: Bool {return self._e != nil}
63+
/// Clears the value of `e`. Subsequent reads from it will return its default value.
64+
public mutating func clearE() {self._e = nil}
65+
66+
public var unknownFields = SwiftProtobuf.UnknownStorage()
67+
68+
public init() {}
69+
70+
fileprivate var _e: E? = nil
71+
}
72+
73+
// MARK: - Code below here is support for the SwiftProtobuf runtime.
74+
75+
extension E: SwiftProtobuf._ProtoNameProviding {
76+
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
77+
0: .same(proto: "E_UNSET"),
78+
1: .same(proto: "E_A"),
79+
2: .same(proto: "E_B"),
80+
]
81+
}
82+
83+
extension A: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
84+
public static let protoMessageName: String = "A"
85+
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
86+
1: .same(proto: "e"),
87+
]
88+
89+
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
90+
while let fieldNumber = try decoder.nextFieldNumber() {
91+
// The use of inline closures is to circumvent an issue where the compiler
92+
// allocates stack space for every case branch when no optimizations are
93+
// enabled. https://github.com/apple/swift-protobuf/issues/1034
94+
switch fieldNumber {
95+
case 1: try { try decoder.decodeSingularEnumField(value: &self._e) }()
96+
default: break
97+
}
98+
}
99+
}
100+
101+
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
102+
// The use of inline closures is to circumvent an issue where the compiler
103+
// allocates stack space for every if/case branch local when no optimizations
104+
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
105+
// https://github.com/apple/swift-protobuf/issues/1182
106+
try { if let v = self._e {
107+
try visitor.visitSingularEnumField(value: v, fieldNumber: 1)
108+
} }()
109+
try unknownFields.traverse(visitor: &visitor)
110+
}
111+
112+
public static func ==(lhs: A, rhs: A) -> Bool {
113+
if lhs._e != rhs._e {return false}
114+
if lhs.unknownFields != rhs.unknownFields {return false}
115+
return true
116+
}
117+
}

0 commit comments

Comments
 (0)