@@ -99,6 +99,53 @@ extension RedisDataDecoderTests {
99
99
}
100
100
}
101
101
102
+ // MARK: BulkString Parsing
103
+
104
+ extension RedisDataDecoderTests {
105
+ func testParsing_bulkString_handlesMissingEndings( ) throws {
106
+ XCTAssertEqual ( try parseTestBulkString ( " $6 " ) , . notYetParsed)
107
+ XCTAssertEqual ( try parseTestBulkString ( " $6 \r \n " ) , . notYetParsed)
108
+ XCTAssertEqual ( try parseTestBulkString ( " $6 \r \n abcdef " ) , . notYetParsed)
109
+ }
110
+
111
+ func testParsing_bulkString_withNoSize_returnsEmpty( ) throws {
112
+ XCTAssertEqual ( try parseTestBulkString ( " $0 \r \n " ) , . parsed)
113
+ }
114
+
115
+ func testParsing_bulkString_withSize_returnsContent( ) throws {
116
+ XCTAssertEqual ( try parseTestBulkString ( " $1 \r \n 1 \r \n " ) , . parsed)
117
+ }
118
+
119
+ func testParsing_bulkString_withNull_returnsNil( ) throws {
120
+ XCTAssertEqual ( try parseTestBulkString ( " $-1 \r \n " ) , . parsed)
121
+ }
122
+
123
+ func testParsing_bulkString_handlesRawBytes( ) throws {
124
+ let bytes : [ UInt8 ] = [ 0x00 , 0x01 , 0x02 , 0x03 , 0x0A , 0xFF ]
125
+ let data = " $ \( bytes. count) \r \n " . convertedToData ( ) + Data( bytes: bytes) + " \r \n " . convertedToData ( )
126
+ XCTAssertEqual ( try parseTestBulkString ( data) , . parsed)
127
+ }
128
+
129
+ func testParsing_bulkString_handlesLargeSizes( ) throws {
130
+ let bytes = [ UInt8 ] . init ( repeating: . dollar, count: 10_000_000 )
131
+ let data = " $ \( bytes. count) \r \n " . convertedToData ( ) + Data( bytes: bytes) + " \r \n " . convertedToData ( )
132
+ XCTAssertEqual ( try parseTestBulkString ( data) , . parsed)
133
+ }
134
+
135
+ private func parseTestBulkString( _ input: String ) throws -> RedisDataDecoder . _RedisDataDecodingState {
136
+ return try parseTestBulkString ( input. convertedToData ( ) )
137
+ }
138
+
139
+ private func parseTestBulkString( _ input: Data ) throws -> RedisDataDecoder . _RedisDataDecodingState {
140
+ var buffer = allocator. buffer ( capacity: input. count)
141
+ buffer. write ( bytes: input)
142
+
143
+ var position = 1 // "trim" token
144
+
145
+ return try RedisDataDecoder ( ) . _parseBulkString ( at: & position, from: buffer)
146
+ }
147
+ }
148
+
102
149
// MARK: Message Parsing
103
150
104
151
extension RedisDataDecoderTests {
@@ -118,10 +165,28 @@ extension RedisDataDecoderTests {
118
165
try parseTest_recursive ( withChunks: [ " :300 \r " , " \n :-10135135 \r " , " \n :1 \r " , " \n " ] )
119
166
}
120
167
168
+ func testParsing_with_bulkString( ) throws {
169
+ try parseTest_singleValue ( input: " $-1 \r " )
170
+ try parseTest_singleValue ( input: " $0 \r " )
171
+ try parseTest_singleValue ( input: " $1 \r \n ! \r " )
172
+ try parseTest_singleValue ( input: " $1 \r \n " . convertedToData ( ) + Data( bytes: [ 0xff ] + " \r " . convertedToData ( ) ) )
173
+ }
174
+
175
+ func testParsing_with_bulkString_recursively( ) throws {
176
+ try parseTest_recursive ( withChunks: [ " $3 \r " , " \n aaa \r \n $ " , " 4 \r \n nio! \r \n " ] )
177
+ }
178
+
179
+ /// See parse_Test_singleValue(input:) String
121
180
private func parseTest_singleValue( input: String ) throws {
181
+ try parseTest_singleValue ( input: input. convertedToData ( ) )
182
+ }
183
+
184
+ /// Takes a collection of bytes representing an incomplete message to assert decoding states
185
+ /// This method will add the appropriate \n terminator to the end of the byte stream
186
+ private func parseTest_singleValue( input: Data ) throws {
122
187
let decoder = RedisDataDecoder ( )
123
188
var buffer = allocator. buffer ( capacity: input. count + 1 )
124
- buffer. write ( string : input)
189
+ buffer. write ( bytes : input)
125
190
126
191
var position = 0
127
192
@@ -133,10 +198,18 @@ extension RedisDataDecoderTests {
133
198
XCTAssertEqual ( try decoder. _parse ( at: & position, from: buffer) , . parsed)
134
199
}
135
200
201
+ /// See parseTest_recursive(withCunks:) [Data]
136
202
private func parseTest_recursive( withChunks messageChunks: [ String ] ) throws {
203
+ try parseTest_recursive ( withChunks: messageChunks. map ( { $0. convertedToData ( ) } ) )
204
+ }
205
+
206
+ /// Takes a collection of byte streams to write to a buffer and assert decoding states in between
207
+ /// buffer writes.
208
+ /// The expected pattern of messages should be [incomplete, remaining, incomplete, remaining]
209
+ private func parseTest_recursive( withChunks messageChunks: [ Data ] ) throws {
137
210
let decoder = RedisDataDecoder ( )
138
211
var buffer = allocator. buffer ( capacity: messageChunks. joined ( ) . count)
139
- buffer. write ( string : messageChunks [ 0 ] )
212
+ buffer. write ( bytes : messageChunks [ 0 ] )
140
213
141
214
var position = 0
142
215
@@ -145,7 +218,7 @@ extension RedisDataDecoderTests {
145
218
for index in 1 ..< messageChunks. count {
146
219
position = 0
147
220
148
- buffer. write ( string : messageChunks [ index] )
221
+ buffer. write ( bytes : messageChunks [ index] )
149
222
150
223
XCTAssertEqual ( try decoder. _parse ( at: & position, from: buffer) , . parsed)
151
224
0 commit comments