Skip to content

Commit aab4b8a

Browse files
authored
Merge pull request #1442 from spevans/pr_sr_7017
2 parents bae2c8b + f3658e4 commit aab4b8a

File tree

3 files changed

+74
-12
lines changed

3 files changed

+74
-12
lines changed

Foundation/Codable.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ internal extension DecodingError {
3939
return "an array"
4040
} else if value is [String : Any] {
4141
return "a dictionary"
42+
} else if value is Bool {
43+
return "a boolean"
4244
} else {
4345
// This should never happen -- we somehow have a non-JSON type here.
4446
preconditionFailure("Invalid storage type \(type(of: value)).")

Foundation/JSONEncoder.swift

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,6 +1746,7 @@ extension _JSONDecoder : SingleValueDecodingContainer {
17461746
// MARK: - Concrete Value Representations
17471747

17481748
extension _JSONDecoder {
1749+
17491750
/// Returns the given value unboxed from a container.
17501751
fileprivate func unbox(_ value: Any, as type: Bool.Type) throws -> Bool? {
17511752
guard !(value is NSNull) else { return nil }
@@ -1765,7 +1766,7 @@ extension _JSONDecoder {
17651766
fileprivate func unbox(_ value: Any, as type: Int.Type) throws -> Int? {
17661767
guard !(value is NSNull) else { return nil }
17671768

1768-
guard let number = value as? NSNumber else {
1769+
guard let number = value as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else {
17691770
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
17701771
}
17711772

@@ -1780,7 +1781,7 @@ extension _JSONDecoder {
17801781
fileprivate func unbox(_ value: Any, as type: Int8.Type) throws -> Int8? {
17811782
guard !(value is NSNull) else { return nil }
17821783

1783-
guard let number = value as? NSNumber else {
1784+
guard let number = value as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else {
17841785
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
17851786
}
17861787

@@ -1795,7 +1796,7 @@ extension _JSONDecoder {
17951796
fileprivate func unbox(_ value: Any, as type: Int16.Type) throws -> Int16? {
17961797
guard !(value is NSNull) else { return nil }
17971798

1798-
guard let number = value as? NSNumber else {
1799+
guard let number = value as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else {
17991800
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
18001801
}
18011802

@@ -1810,7 +1811,7 @@ extension _JSONDecoder {
18101811
fileprivate func unbox(_ value: Any, as type: Int32.Type) throws -> Int32? {
18111812
guard !(value is NSNull) else { return nil }
18121813

1813-
guard let number = value as? NSNumber else {
1814+
guard let number = value as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else {
18141815
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
18151816
}
18161817

@@ -1825,7 +1826,7 @@ extension _JSONDecoder {
18251826
fileprivate func unbox(_ value: Any, as type: Int64.Type) throws -> Int64? {
18261827
guard !(value is NSNull) else { return nil }
18271828

1828-
guard let number = value as? NSNumber else {
1829+
guard let number = value as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else {
18291830
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
18301831
}
18311832

@@ -1840,7 +1841,7 @@ extension _JSONDecoder {
18401841
fileprivate func unbox(_ value: Any, as type: UInt.Type) throws -> UInt? {
18411842
guard !(value is NSNull) else { return nil }
18421843

1843-
guard let number = value as? NSNumber else {
1844+
guard let number = value as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else {
18441845
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
18451846
}
18461847

@@ -1855,7 +1856,7 @@ extension _JSONDecoder {
18551856
fileprivate func unbox(_ value: Any, as type: UInt8.Type) throws -> UInt8? {
18561857
guard !(value is NSNull) else { return nil }
18571858

1858-
guard let number = value as? NSNumber else {
1859+
guard let number = value as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else {
18591860
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
18601861
}
18611862

@@ -1870,7 +1871,7 @@ extension _JSONDecoder {
18701871
fileprivate func unbox(_ value: Any, as type: UInt16.Type) throws -> UInt16? {
18711872
guard !(value is NSNull) else { return nil }
18721873

1873-
guard let number = value as? NSNumber else {
1874+
guard let number = value as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else {
18741875
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
18751876
}
18761877

@@ -1885,7 +1886,7 @@ extension _JSONDecoder {
18851886
fileprivate func unbox(_ value: Any, as type: UInt32.Type) throws -> UInt32? {
18861887
guard !(value is NSNull) else { return nil }
18871888

1888-
guard let number = value as? NSNumber else {
1889+
guard let number = value as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else {
18891890
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
18901891
}
18911892

@@ -1900,7 +1901,7 @@ extension _JSONDecoder {
19001901
fileprivate func unbox(_ value: Any, as type: UInt64.Type) throws -> UInt64? {
19011902
guard !(value is NSNull) else { return nil }
19021903

1903-
guard let number = value as? NSNumber else {
1904+
guard let number = value as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else {
19041905
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
19051906
}
19061907

@@ -1915,7 +1916,7 @@ extension _JSONDecoder {
19151916
fileprivate func unbox(_ value: Any, as type: Float.Type) throws -> Float? {
19161917
guard !(value is NSNull) else { return nil }
19171918

1918-
if let number = value as? NSNumber {
1919+
if let number = value as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse {
19191920
// We are willing to return a Float by losing precision:
19201921
// * If the original value was integral,
19211922
// * and the integral value was > Float.greatestFiniteMagnitude, we will fail
@@ -1961,7 +1962,7 @@ extension _JSONDecoder {
19611962
fileprivate func unbox(_ value: Any, as type: Double.Type) throws -> Double? {
19621963
guard !(value is NSNull) else { return nil }
19631964

1964-
if let number = value as? NSNumber {
1965+
if let number = value as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse {
19651966
// We are always willing to return the number as a Double:
19661967
// * If the original value was integral, it is guaranteed to fit in a Double; we are willing to lose precision past 2^53 if you encoded a UInt64 but requested a Double
19671968
// * If it was a Float or Double, you will get back the precise value

TestFoundation/TestJSONEncoder.swift

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,65 @@ class TestJSONEncoder : XCTestCase {
334334
_ = try JSONDecoder().decode([Bool].self, from: "[1]".data(using: .utf8)!)
335335
XCTFail("Coercing non-boolean numbers into Bools was expected to fail")
336336
} catch { }
337+
338+
339+
// Check that a Bool false or true isnt converted to 0 or 1
340+
struct Foo: Decodable {
341+
var intValue: Int?
342+
var int8Value: Int8?
343+
var int16Value: Int16?
344+
var int32Value: Int32?
345+
var int64Value: Int64?
346+
var uintValue: UInt?
347+
var uint8Value: UInt8?
348+
var uint16Value: UInt16?
349+
var uint32Value: UInt32?
350+
var uint64Value: UInt64?
351+
var floatValue: Float?
352+
var doubleValue: Double?
353+
var decimalValue: Decimal?
354+
let boolValue: Bool
355+
}
356+
357+
func testValue(_ valueName: String) {
358+
do {
359+
let jsonData = "{ \"\(valueName)\": false }".data(using: .utf8)!
360+
_ = try JSONDecoder().decode(Foo.self, from: jsonData)
361+
XCTFail("Decoded 'false' as non Bool for \(valueName)")
362+
} catch {}
363+
do {
364+
let jsonData = "{ \"\(valueName)\": true }".data(using: .utf8)!
365+
_ = try JSONDecoder().decode(Foo.self, from: jsonData)
366+
XCTFail("Decoded 'true' as non Bool for \(valueName)")
367+
} catch {}
368+
}
369+
370+
testValue("intValue")
371+
testValue("int8Value")
372+
testValue("int16Value")
373+
testValue("int32Value")
374+
testValue("int64Value")
375+
testValue("uintValue")
376+
testValue("uint8Value")
377+
testValue("uint16Value")
378+
testValue("uint32Value")
379+
testValue("uint64Value")
380+
testValue("floatValue")
381+
testValue("doubleValue")
382+
testValue("decimalValue")
383+
let falseJsonData = "{ \"boolValue\": false }".data(using: .utf8)!
384+
if let falseFoo = try? JSONDecoder().decode(Foo.self, from: falseJsonData) {
385+
XCTAssertFalse(falseFoo.boolValue)
386+
} else {
387+
XCTFail("Could not decode 'false' as a Bool")
388+
}
389+
390+
let trueJsonData = "{ \"boolValue\": true }".data(using: .utf8)!
391+
if let trueFoo = try? JSONDecoder().decode(Foo.self, from: trueJsonData) {
392+
XCTAssertTrue(trueFoo.boolValue)
393+
} else {
394+
XCTFail("Could not decode 'true' as a Bool")
395+
}
337396
}
338397

339398
func test_codingOfInt8() {

0 commit comments

Comments
 (0)