@@ -87,3 +87,114 @@ extension CurrencyAmount: ExpressibleByFloatLiteral {
87
87
self . value = Decimal ( value)
88
88
}
89
89
}
90
+
91
+ private func assertThat( _ dictionary: [ String : Any ] ,
92
+ file: StaticString = #file,
93
+ line: UInt = #line) -> DictionarySubject {
94
+ return DictionarySubject ( dictionary, file: file, line: line)
95
+ }
96
+
97
+ func assertThat< X: Equatable & Codable > ( _ model: X , file: StaticString = #file,
98
+ line: UInt = #line) -> CodableSubject < X > {
99
+ return CodableSubject ( model, file: file, line: line)
100
+ }
101
+
102
+ func assertThat< X: Equatable & Encodable > ( _ model: X , file: StaticString = #file,
103
+ line: UInt = #line) -> EncodableSubject < X > {
104
+ return EncodableSubject ( model, file: file, line: line)
105
+ }
106
+
107
+ class EncodableSubject < X: Equatable & Encodable > {
108
+ var subject : X
109
+ var file : StaticString
110
+ var line : UInt
111
+
112
+ init ( _ subject: X , file: StaticString , line: UInt ) {
113
+ self . subject = subject
114
+ self . file = file
115
+ self . line = line
116
+ }
117
+
118
+ @discardableResult
119
+ func encodes( to expected: [ String : Any ] ,
120
+ using encoder: Database . Encoder = . init( ) ) -> DictionarySubject {
121
+ let encoded = assertEncodes ( to: expected, using: encoder)
122
+ return DictionarySubject ( encoded, file: file, line: line)
123
+ }
124
+
125
+ func failsToEncode( ) {
126
+ do {
127
+ let encoder = Database . Encoder ( )
128
+ encoder. keyEncodingStrategy = . convertToSnakeCase
129
+ _ = try encoder. encode ( subject)
130
+ } catch {
131
+ return
132
+ }
133
+ XCTFail ( " Failed to throw " )
134
+ }
135
+
136
+ func failsEncodingAtTopLevel( ) {
137
+ do {
138
+ let encoder = Database . Encoder ( )
139
+ encoder. keyEncodingStrategy = . convertToSnakeCase
140
+ _ = try encoder. encode ( subject)
141
+ XCTFail ( " Failed to throw " , file: file, line: line)
142
+ } catch EncodingError . invalidValue( _, _) {
143
+ return
144
+ } catch {
145
+ XCTFail ( " Unrecognized error: \( error) " , file: file, line: line)
146
+ }
147
+ }
148
+
149
+ private func assertEncodes( to expected: [ String : Any ] ,
150
+ using encoder: Database . Encoder = . init( ) ) -> [ String : Any ] {
151
+ do {
152
+ let enc = try encoder. encode ( subject)
153
+ XCTAssertEqual ( enc as? NSDictionary , expected as NSDictionary , file: file, line: line)
154
+ return ( enc as! NSDictionary ) as! [ String : Any ]
155
+ } catch {
156
+ XCTFail ( " Failed to encode \( X . self) : error: \( error) " )
157
+ return [ " " : - 1 ]
158
+ }
159
+ }
160
+ }
161
+
162
+ class CodableSubject < X: Equatable & Codable > : EncodableSubject < X > {
163
+ func roundTrips( to expected: [ String : Any ] ,
164
+ using encoder: Database . Encoder = . init( ) ,
165
+ decoder: Database . Decoder = . init( ) ) {
166
+ let reverseSubject = encodes ( to: expected, using: encoder)
167
+ reverseSubject. decodes ( to: subject, using: decoder)
168
+ }
169
+ }
170
+
171
+ class DictionarySubject {
172
+ var subject : [ String : Any ]
173
+ var file : StaticString
174
+ var line : UInt
175
+
176
+ init ( _ subject: [ String : Any ] , file: StaticString , line: UInt ) {
177
+ self . subject = subject
178
+ self . file = file
179
+ self . line = line
180
+ }
181
+
182
+ func decodes< X: Equatable & Codable > ( to expected: X ,
183
+ using decoder: Database . Decoder = . init( ) ) -> Void {
184
+ do {
185
+ let decoded = try decoder. decode ( X . self, from: subject)
186
+ XCTAssertEqual ( decoded, expected)
187
+ } catch {
188
+ XCTFail ( " Failed to decode \( X . self) : \( error) " , file: file, line: line)
189
+ }
190
+ }
191
+
192
+ func failsDecoding< X: Equatable & Codable > ( to _: X . Type ,
193
+ using decoder: Database . Decoder = . init( ) ) -> Void {
194
+ XCTAssertThrowsError (
195
+ try decoder. decode ( X . self, from: subject) ,
196
+ file: file,
197
+ line: line
198
+ )
199
+ }
200
+ }
0 commit comments