Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore unknown enum values and return nil instead when ignoreUnknownFields flag is ON #1

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 13 additions & 4 deletions Sources/SwiftProtobuf/JSONDecoder.swift
Expand Up @@ -476,7 +476,11 @@ internal struct JSONDecoder: Decoder {
value = nil
return
}
value = try scanner.nextEnumValue() as E
if let v: E = try scanner.nextEnumValue() {
value = v
} else {
value = nil
}
}

mutating func decodeSingularEnumField<E: Enum>(value: inout E) throws
Expand All @@ -489,7 +493,11 @@ internal struct JSONDecoder: Decoder {
value = E()
return
}
value = try scanner.nextEnumValue()
if let v: E = try scanner.nextEnumValue() {
value = v
} else {
value = E()
}
}

mutating func decodeRepeatedEnumField<E: Enum>(value: inout [E]) throws
Expand All @@ -511,8 +519,9 @@ internal struct JSONDecoder: Decoder {
throw JSONDecodingError.illegalNull
}
} else {
let e: E = try scanner.nextEnumValue()
value.append(e)
if let e: E = try scanner.nextEnumValue() {
value.append(e)
}
}
if scanner.skipOptionalArrayEnd() {
return
Expand Down
4 changes: 3 additions & 1 deletion Sources/SwiftProtobuf/JSONScanner.swift
Expand Up @@ -1300,7 +1300,7 @@ internal struct JSONScanner {
/// Parse the next token as a string or numeric enum value. Throws
/// unrecognizedEnumValue if the string/number can't initialize the
/// enum. Will throw other errors if the JSON is malformed.
internal mutating func nextEnumValue<E: Enum>() throws -> E {
internal mutating func nextEnumValue<E: Enum>() throws -> E? {
skipWhitespace()
guard hasMoreContent else {
throw JSONDecodingError.truncated
Expand All @@ -1324,6 +1324,8 @@ internal struct JSONScanner {
if let i = Int(exactly: n) {
if let e = E(rawValue: i) {
return e
} else if options.ignoreUnknownFields {
return nil
} else {
throw JSONDecodingError.unrecognizedEnumValue
}
Expand Down
38 changes: 38 additions & 0 deletions Tests/SwiftProtobufTests/Test_JSONDecodingOptions.swift
Expand Up @@ -157,4 +157,42 @@ class Test_JSONDecodingOptions: XCTestCase {
}
}

func testIgnoreUnknownFields_ignoresUnknownEnumValues() {
// (isValidJSON, jsonInput)
// isValidJSON - if the input is otherwise valid protobuf JSON, and
// hence should parse when ignoring unknown fields.
// jsonInput - The JSON string to parse.
let jsonInputs: [(Bool, String)] = [
(true, "{\"values1\":[1, 3]}"),
]

var options = JSONDecodingOptions()
options.ignoreUnknownFields = true

for (i, (isValidJSON, jsonInput)) in jsonInputs.enumerated() {
// Default options (error on unknown fields)
do {
let _ = try ProtobufUnittest_SwiftEnumTest(jsonString: jsonInput)
XCTFail("Input \(i): Should not have gotten here! Input: \(jsonInput)")
} catch JSONDecodingError.unrecognizedEnumValue {
XCTAssertTrue(true, "Input \(i): got an unknown enum value, input \(jsonInput).")
} catch let e {
XCTFail("Input \(i): Error \(e) decoding into an empty message \(jsonInput)")
}

// Ignoring unknown fields
do {
let _ = try ProtobufUnittest_SwiftEnumTest(jsonString: jsonInput,
options:options)
XCTAssertTrue(isValidJSON,
"Input \(i): Should not have been able to parse: \(jsonInput)")
} catch JSONDecodingError.unrecognizedEnumValue {
XCTFail("Input \(i): should not have gotten unknown enum value, input \(jsonInput)")
} catch let e {
XCTAssertFalse(isValidJSON,
"Input \(i): Error \(e): Should have been able to parse: \(jsonInput)")
}
}
}

}