@@ -8,7 +8,6 @@ class MapTests: XCTestCase {
8
8
XCTAssertEqual ( try Map . bool ( false ) . boolValue ( ) , false )
9
9
XCTAssertEqual ( try Map . bool ( true ) . boolValue ( ) , true )
10
10
XCTAssertEqual ( try Map . string ( " Hello world " ) . stringValue ( ) , " Hello world " )
11
-
12
11
}
13
12
14
13
func testOptionalConversion( ) {
@@ -36,16 +35,117 @@ class MapTests: XCTestCase {
36
35
[
37
36
" first " : . number( 1 ) ,
38
37
" second " : . number( 4 ) ,
39
- " third " : . number( 9 )
38
+ " third " : . number( 9 ) ,
39
+ " fourth " : . null,
40
+ " fifth " : . undefined
40
41
]
41
42
)
42
- XCTAssertEqual ( map. dictionary? . count, 3 )
43
+ XCTAssertEqual ( map. dictionary? . count, 5 )
43
44
44
45
let dictionary = try map. dictionaryValue ( )
45
46
46
- XCTAssertEqual ( dictionary. count, 3 )
47
+ XCTAssertEqual ( dictionary. count, 5 )
47
48
XCTAssertEqual ( try dictionary [ " first " ] ? . intValue ( ) , 1 )
48
49
XCTAssertEqual ( try dictionary [ " second " ] ? . intValue ( ) , 4 )
49
50
XCTAssertEqual ( try dictionary [ " third " ] ? . intValue ( ) , 9 )
51
+ XCTAssertEqual ( dictionary [ " fourth " ] ? . isNull, true )
52
+ XCTAssertEqual ( dictionary [ " fifth " ] ? . isUndefined, true )
53
+ }
54
+
55
+ // Ensure that default decoding preserves undefined becoming nil
56
+ func testNilAndUndefinedDecodeToNilByDefault( ) throws {
57
+ struct DecodableTest : Codable {
58
+ let first : Int ?
59
+ let second : Int ?
60
+ let third : Int ?
61
+ let fourth : Int ?
62
+ }
63
+
64
+ let map = Map . dictionary (
65
+ [
66
+ " first " : . number( 1 ) ,
67
+ " second " : . null,
68
+ " third " : . undefined
69
+ // fourth not included
70
+ ]
71
+ )
72
+
73
+ let decodable = try MapDecoder ( ) . decode ( DecodableTest . self, from: map)
74
+ XCTAssertEqual ( decodable. first, 1 )
75
+ XCTAssertEqual ( decodable. second, nil )
76
+ XCTAssertEqual ( decodable. third, nil )
77
+ XCTAssertEqual ( decodable. fourth, nil )
78
+ }
79
+
80
+ // Ensure that, if custom decoding is defined, provided nulls and unset values can be differentiated.
81
+ // This should match JSON in that values set to `null` should be 'contained' by the container, but
82
+ // values expected by the result that are undefined or not present should not be.
83
+ func testNilAndUndefinedDecoding( ) throws {
84
+ struct DecodableTest : Codable {
85
+ let first : Int ?
86
+ let second : Int ?
87
+ let third : Int ?
88
+ let fourth : Int ?
89
+
90
+ init (
91
+ first: Int ? ,
92
+ second: Int ? ,
93
+ third: Int ? ,
94
+ fourth: Int ?
95
+ ) {
96
+ self . first = first
97
+ self . second = second
98
+ self . third = third
99
+ self . fourth = fourth
100
+ }
101
+
102
+ init ( from decoder: Decoder ) throws {
103
+ let container = try decoder. container ( keyedBy: CodingKeys . self)
104
+
105
+ XCTAssertTrue ( container. contains ( . first) )
106
+ // Null value should be contained, but decode to nil
107
+ XCTAssertTrue ( container. contains ( . second) )
108
+ // Undefined value should not be contained
109
+ XCTAssertFalse ( container. contains ( . third) )
110
+ // Missing value should operate the same as undefined
111
+ XCTAssertFalse ( container. contains ( . fourth) )
112
+
113
+ first = try container. decodeIfPresent ( Int . self, forKey: . first)
114
+ second = try container. decodeIfPresent ( Int . self, forKey: . second)
115
+ third = try container. decodeIfPresent ( Int . self, forKey: . third)
116
+ fourth = try container. decodeIfPresent ( Int . self, forKey: . fourth)
117
+ }
118
+ }
119
+
120
+ let map = Map . dictionary (
121
+ [
122
+ " first " : . number( 1 ) ,
123
+ " second " : . null,
124
+ " third " : . undefined
125
+ // fourth not included
126
+ ]
127
+ )
128
+
129
+ _ = try MapDecoder ( ) . decode ( DecodableTest . self, from: map)
130
+ }
131
+
132
+ // Ensure that map encoding includes defined nulls, but skips undefined values
133
+ func testMapEncoding( ) throws {
134
+ let map = Map . dictionary (
135
+ [
136
+ " first " : . number( 1 ) ,
137
+ " second " : . null,
138
+ " third " : . undefined
139
+ ]
140
+ )
141
+
142
+ let data = try JSONEncoder ( ) . encode ( map)
143
+ let json = String ( data: data, encoding: . utf8)
144
+ XCTAssertEqual (
145
+ json,
146
+ """
147
+ { " first " :1, " second " :null}
148
+ """
149
+ )
50
150
}
51
151
}
0 commit comments