Skip to content

Commit e56ffc3

Browse files
committed
Basic test for nested messages with extension fields
1 parent e328952 commit e56ffc3

File tree

9 files changed

+108
-60
lines changed

9 files changed

+108
-60
lines changed

Protos/unittest_swift_extension.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ message Msg2 {
5353

5454
extend Msg1 {
5555
optional int32 a_b = 1;
56+
optional Msg2 m2 = 2;
5657
}
5758

5859
extend Msg2 {

Reference/unittest_swift_extension.pb.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,21 @@ extension ProtobufUnittest_Extend_Msg1 {
236236
mutating func clearProtobufUnittest_Extend_aB() {
237237
clearExtensionValue(ext: ProtobufUnittest_Extend_Extensions_a_b)
238238
}
239+
240+
var ProtobufUnittest_Extend_m2: ProtobufUnittest_Extend_Msg2 {
241+
get {return getExtensionValue(ext: ProtobufUnittest_Extend_Extensions_m2) ?? ProtobufUnittest_Extend_Msg2()}
242+
set {setExtensionValue(ext: ProtobufUnittest_Extend_Extensions_m2, value: newValue)}
243+
}
244+
/// Returns true if extension `ProtobufUnittest_Extend_Extensions_m2`
245+
/// has been explicitly set.
246+
var hasProtobufUnittest_Extend_m2: Bool {
247+
return hasExtensionValue(ext: ProtobufUnittest_Extend_Extensions_m2)
248+
}
249+
/// Clears the value of extension `ProtobufUnittest_Extend_Extensions_m2`.
250+
/// Subsequent reads from it will return its default value.
251+
mutating func clearProtobufUnittest_Extend_m2() {
252+
clearExtensionValue(ext: ProtobufUnittest_Extend_Extensions_m2)
253+
}
239254
}
240255

241256
extension ProtobufUnittest_Extend_Msg2 {
@@ -333,6 +348,7 @@ let ProtobufUnittest_Extend_UnittestSwiftExtension_Extensions: SwiftProtobuf.Sim
333348
ProtobufUnittest_Extend_Extensions_b,
334349
ProtobufUnittest_Extend_Extensions_C,
335350
ProtobufUnittest_Extend_Extensions_a_b,
351+
ProtobufUnittest_Extend_Extensions_m2,
336352
ProtobufUnittest_Extend_Extensions_aB,
337353
ProtobufUnittest_Extend_Extensions_ext_a,
338354
ProtobufUnittest_Extend_Extensions_ext_b,
@@ -359,6 +375,11 @@ let ProtobufUnittest_Extend_Extensions_a_b = SwiftProtobuf.MessageExtension<Swif
359375
fieldName: "protobuf_unittest.extend.a_b"
360376
)
361377

378+
let ProtobufUnittest_Extend_Extensions_m2 = SwiftProtobuf.MessageExtension<SwiftProtobuf.OptionalMessageExtensionField<ProtobufUnittest_Extend_Msg2>, ProtobufUnittest_Extend_Msg1>(
379+
_protobuf_fieldNumber: 2,
380+
fieldName: "protobuf_unittest.extend.m2"
381+
)
382+
362383
let ProtobufUnittest_Extend_Extensions_aB = SwiftProtobuf.MessageExtension<SwiftProtobuf.OptionalExtensionField<SwiftProtobuf.ProtobufInt32>, ProtobufUnittest_Extend_Msg2>(
363384
_protobuf_fieldNumber: 1,
364385
fieldName: "protobuf_unittest.extend.aB"

Sources/SwiftProtobuf/JSONDecoder.swift

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,6 @@ internal struct JSONDecoder: Decoder {
2727
throw JSONDecodingError.conflictingOneOf
2828
}
2929

30-
internal init(source: UnsafeRawBufferPointer, options: JSONDecodingOptions) {
31-
self.options = options
32-
self.scanner = JSONScanner(source: source,
33-
messageDepthLimit: self.options.messageDepthLimit,
34-
ignoreUnknownFields: self.options.ignoreUnknownFields)
35-
}
36-
3730
internal init(source: UnsafeRawBufferPointer, options: JSONDecodingOptions,
3831
messageType: Message.Type, extensions: ExtensionMap?) {
3932
self.options = options
@@ -44,11 +37,12 @@ internal struct JSONDecoder: Decoder {
4437
self.extensions = extensions
4538
}
4639

47-
private init(decoder: JSONDecoder) {
40+
private init(decoder: JSONDecoder, messageType: Message.Type) {
4841
// The scanner is copied over along with the options.
49-
scanner = decoder.scanner
50-
options = decoder.options
51-
extensions = decoder.extensions
42+
self.scanner = decoder.scanner
43+
self.options = decoder.options
44+
self.extensions = decoder.extensions
45+
self.messageType = messageType
5246
}
5347

5448
mutating func nextFieldNumber() throws -> Int? {
@@ -545,7 +539,7 @@ internal struct JSONDecoder: Decoder {
545539
if value == nil {
546540
value = M()
547541
}
548-
var subDecoder = JSONDecoder(decoder: self)
542+
var subDecoder = JSONDecoder(decoder: self, messageType: M.self)
549543
try subDecoder.decodeFullObject(message: &value!)
550544
assert(scanner.recursionBudget == subDecoder.scanner.recursionBudget)
551545
scanner = subDecoder.scanner
@@ -576,7 +570,7 @@ internal struct JSONDecoder: Decoder {
576570
}
577571
} else {
578572
var message = M()
579-
var subDecoder = JSONDecoder(decoder: self)
573+
var subDecoder = JSONDecoder(decoder: self, messageType: M.self)
580574
try subDecoder.decodeFullObject(message: &message)
581575
value.append(message)
582576
assert(scanner.recursionBudget == subDecoder.scanner.recursionBudget)
@@ -713,19 +707,20 @@ internal struct JSONDecoder: Decoder {
713707
messageType: Message.Type,
714708
fieldNumber: Int
715709
) throws {
716-
if let ext = extensions?[messageType, fieldNumber] {
717-
var fieldValue = values[fieldNumber]
718-
if fieldValue != nil {
719-
try fieldValue!.decodeExtensionField(decoder: &self)
720-
} else {
721-
fieldValue = try ext._protobuf_newField(decoder: &self)
722-
}
723-
if fieldValue != nil {
724-
values[fieldNumber] = fieldValue
725-
} else {
726-
// This most likely indicates a bug in our extension support.
727-
throw TextFormatDecodingError.internalExtensionError
728-
}
710+
guard let ext = extensions?[messageType, fieldNumber] else {
711+
return
712+
}
713+
var fieldValue = values[fieldNumber]
714+
if fieldValue != nil {
715+
try fieldValue!.decodeExtensionField(decoder: &self)
716+
} else {
717+
fieldValue = try ext._protobuf_newField(decoder: &self)
718+
}
719+
if fieldValue != nil {
720+
values[fieldNumber] = fieldValue
721+
} else {
722+
// This most likely indicates a bug in our extension support.
723+
throw TextFormatDecodingError.internalExtensionError
729724
}
730725
}
731726
}

Sources/SwiftProtobuf/JSONEncodingVisitor.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,17 @@ internal struct JSONEncodingVisitor: Visitor {
173173
encoder.append(text: json)
174174
} else if let newNameMap = (M.self as? _ProtoNameProviding.Type)?._protobuf_nameMap {
175175
encoder.startNestedObject()
176+
// Preserve outer object's name and extension maps; restore them before returning
176177
let oldNameMap = self.nameMap
178+
let oldExtensions = self.extensions
179+
defer {
180+
self.nameMap = oldNameMap
181+
self.extensions = oldExtensions
182+
}
183+
// Install inner object's name and extension maps
177184
self.nameMap = newNameMap
185+
self.extensions = (value as? ExtensibleMessage)?._protobuf_extensionFieldValues
178186
try value.traverse(visitor: &self)
179-
self.nameMap = oldNameMap
180187
endObject()
181188
} else {
182189
throw JSONEncodingError.missingFieldNames
@@ -300,17 +307,22 @@ internal struct JSONEncodingVisitor: Visitor {
300307
encoder.append(text: json)
301308
}
302309
} else if let newNameMap = (M.self as? _ProtoNameProviding.Type)?._protobuf_nameMap {
303-
// Install inner object's name map
310+
// Preserve name and extension maps for outer object
304311
let oldNameMap = self.nameMap
312+
let oldExtensions = self.extensions
313+
// Restore outer object's name and extension maps before returning
314+
defer {
315+
self.nameMap = oldNameMap
316+
self.extensions = oldExtensions
317+
}
305318
self.nameMap = newNameMap
306-
// Restore outer object's name map before returning
307-
defer { self.nameMap = oldNameMap }
308319
for v in value {
309320
if comma {
310321
encoder.comma()
311322
}
312323
comma = true
313324
encoder.startNestedObject()
325+
self.extensions = (v as? ExtensibleMessage)?._protobuf_extensionFieldValues
314326
try v.traverse(visitor: &self)
315327
encoder.endObject()
316328
}

Sources/SwiftProtobuf/Message+JSONAdditions.swift

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,7 @@ extension Message {
7070
jsonString: String,
7171
options: JSONDecodingOptions = JSONDecodingOptions()
7272
) throws {
73-
if jsonString.isEmpty {
74-
throw JSONDecodingError.truncated
75-
}
76-
if let data = jsonString.data(using: String.Encoding.utf8) {
77-
try self.init(jsonUTF8Data: data, options: options)
78-
} else {
79-
throw JSONDecodingError.truncated
80-
}
73+
try self.init(jsonString: jsonString, extensions: nil, options: options)
8174
}
8275

8376
/// Creates a new message by decoding the given string containing a
@@ -114,27 +107,7 @@ extension Message {
114107
jsonUTF8Data: Data,
115108
options: JSONDecodingOptions = JSONDecodingOptions()
116109
) throws {
117-
self.init()
118-
try jsonUTF8Data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
119-
// Empty input is valid for binary, but not for JSON.
120-
guard body.count > 0 else {
121-
throw JSONDecodingError.truncated
122-
}
123-
var decoder = JSONDecoder(source: body, options: options)
124-
if decoder.scanner.skipOptionalNull() {
125-
if let customCodable = Self.self as? _CustomJSONCodable.Type,
126-
let message = try customCodable.decodedFromJSONNull() {
127-
self = message as! Self
128-
} else {
129-
throw JSONDecodingError.illegalNull
130-
}
131-
} else {
132-
try decoder.decodeFullObject(message: &self)
133-
}
134-
if !decoder.scanner.complete {
135-
throw JSONDecodingError.trailingGarbage
136-
}
137-
}
110+
try self.init(jsonUTF8Data: jsonUTF8Data, extensions: nil, options: options)
138111
}
139112

140113
/// Creates a new message by decoding the given `Data` containing a

Sources/SwiftProtobuf/Message+JSONArrayAdditions.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ extension Message {
9595
var array = [Self]()
9696

9797
if body.count > 0 {
98-
var decoder = JSONDecoder(source: body, options: options)
98+
var decoder = JSONDecoder(source: body, options: options,
99+
messageType: Self.self, extensions: nil)
99100
try decoder.decodeRepeatedMessageField(value: &array)
100101
if !decoder.scanner.complete {
101102
throw JSONDecodingError.trailingGarbage

Tests/LinuxMain.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,12 @@ extension Test_JSON_Extensions {
649649
]
650650
}
651651

652+
extension Test_JSON_RecursiveNested_Extensions {
653+
static var allTests = [
654+
("test_nestedMessage", test_nestedMessage)
655+
]
656+
}
657+
652658
extension Test_JSON_Group {
653659
static var allTests = [
654660
("testOptionalGroup", testOptionalGroup),
@@ -1193,6 +1199,7 @@ XCTMain(
11931199
testCase(Test_JSON_Array.allTests),
11941200
testCase(Test_JSON_Conformance.allTests),
11951201
testCase(Test_JSON_Extensions.allTests),
1202+
testCase(Test_JSON_RecursiveNested_Extensions.allTests),
11961203
testCase(Test_JSON_Group.allTests),
11971204
testCase(Test_Map.allTests),
11981205
testCase(Test_MapFields_Access_Proto2.allTests),

Tests/SwiftProtobufTests/Test_JSON_Extensions.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,22 @@ class Test_JSON_Extensions: XCTestCase, PBTestHelpers {
4141
o.ProtobufUnittest_optionalInt32Extension = 17
4242
}
4343
}
44+
}
4445

46+
class Test_JSON_RecursiveNested_Extensions: XCTestCase, PBTestHelpers {
47+
typealias MessageTestType = ProtobufUnittest_Extend_Msg1
48+
let extensions = ProtobufUnittest_Extend_UnittestSwiftExtension_Extensions
49+
50+
func test_nestedMessage() throws {
51+
assertJSONEncode("{\"[protobuf_unittest.extend.a_b]\":12}",
52+
extensions: extensions) {
53+
(o: inout MessageTestType) in
54+
o.ProtobufUnittest_Extend_aB = 12
55+
}
56+
57+
assertJSONDecodeSucceeds("{\"[protobuf_unittest.extend.m2]\":{\"[protobuf_unittest.extend.aB]\":23}}", extensions: extensions) {
58+
$0.ProtobufUnittest_Extend_m2.ProtobufUnittest_Extend_aB == 23
59+
}
60+
}
61+
4562
}

Tests/SwiftProtobufTests/unittest_swift_extension.pb.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,21 @@ extension ProtobufUnittest_Extend_Msg1 {
236236
mutating func clearProtobufUnittest_Extend_aB() {
237237
clearExtensionValue(ext: ProtobufUnittest_Extend_Extensions_a_b)
238238
}
239+
240+
var ProtobufUnittest_Extend_m2: ProtobufUnittest_Extend_Msg2 {
241+
get {return getExtensionValue(ext: ProtobufUnittest_Extend_Extensions_m2) ?? ProtobufUnittest_Extend_Msg2()}
242+
set {setExtensionValue(ext: ProtobufUnittest_Extend_Extensions_m2, value: newValue)}
243+
}
244+
/// Returns true if extension `ProtobufUnittest_Extend_Extensions_m2`
245+
/// has been explicitly set.
246+
var hasProtobufUnittest_Extend_m2: Bool {
247+
return hasExtensionValue(ext: ProtobufUnittest_Extend_Extensions_m2)
248+
}
249+
/// Clears the value of extension `ProtobufUnittest_Extend_Extensions_m2`.
250+
/// Subsequent reads from it will return its default value.
251+
mutating func clearProtobufUnittest_Extend_m2() {
252+
clearExtensionValue(ext: ProtobufUnittest_Extend_Extensions_m2)
253+
}
239254
}
240255

241256
extension ProtobufUnittest_Extend_Msg2 {
@@ -333,6 +348,7 @@ let ProtobufUnittest_Extend_UnittestSwiftExtension_Extensions: SwiftProtobuf.Sim
333348
ProtobufUnittest_Extend_Extensions_b,
334349
ProtobufUnittest_Extend_Extensions_C,
335350
ProtobufUnittest_Extend_Extensions_a_b,
351+
ProtobufUnittest_Extend_Extensions_m2,
336352
ProtobufUnittest_Extend_Extensions_aB,
337353
ProtobufUnittest_Extend_Extensions_ext_a,
338354
ProtobufUnittest_Extend_Extensions_ext_b,
@@ -359,6 +375,11 @@ let ProtobufUnittest_Extend_Extensions_a_b = SwiftProtobuf.MessageExtension<Swif
359375
fieldName: "protobuf_unittest.extend.a_b"
360376
)
361377

378+
let ProtobufUnittest_Extend_Extensions_m2 = SwiftProtobuf.MessageExtension<SwiftProtobuf.OptionalMessageExtensionField<ProtobufUnittest_Extend_Msg2>, ProtobufUnittest_Extend_Msg1>(
379+
_protobuf_fieldNumber: 2,
380+
fieldName: "protobuf_unittest.extend.m2"
381+
)
382+
362383
let ProtobufUnittest_Extend_Extensions_aB = SwiftProtobuf.MessageExtension<SwiftProtobuf.OptionalExtensionField<SwiftProtobuf.ProtobufInt32>, ProtobufUnittest_Extend_Msg2>(
363384
_protobuf_fieldNumber: 1,
364385
fieldName: "protobuf_unittest.extend.aB"

0 commit comments

Comments
 (0)