mirror of
https://github.com/swift-server/RediStack.git
synced 2026-06-02 07:37:33 +00:00
Add decoding of arrays
This commit is contained in:
@@ -59,6 +59,8 @@ extension RedisDataDecoder {
|
||||
return .parsed
|
||||
case .dollar:
|
||||
return try _parseBulkString(at: &position, from: buffer)
|
||||
case .asterisk:
|
||||
return try _parseArray(at: &position, from: buffer)
|
||||
default: return .notYetParsed
|
||||
}
|
||||
}
|
||||
@@ -139,6 +141,31 @@ extension RedisDataDecoder {
|
||||
|
||||
return .parsed // bulkString(Data(bytes[ ..<(size - 1) ]))
|
||||
}
|
||||
|
||||
/// See https://redis.io/topics/protocol#resp-arrays
|
||||
func _parseArray(at position: inout Int, from buffer: ByteBuffer) throws -> _RedisDataDecodingState {
|
||||
guard let arraySize = try _parseInteger(at: &position, from: buffer) else { return .notYetParsed }
|
||||
#warning("TODO: return null array")
|
||||
guard arraySize > -1 else { return .parsed }
|
||||
#warning("TODO: return empty array")
|
||||
guard arraySize > 0 else { return .parsed }
|
||||
|
||||
var array = [_RedisDataDecodingState](repeating: .notYetParsed, count: arraySize)
|
||||
for index in 0..<arraySize {
|
||||
guard buffer.readableBytes - position > 0 else { return .notYetParsed }
|
||||
|
||||
let parseResult = try _parse(at: &position, from: buffer)
|
||||
switch parseResult {
|
||||
case .parsed:
|
||||
array[index] = parseResult
|
||||
default:
|
||||
return .notYetParsed
|
||||
}
|
||||
}
|
||||
|
||||
#warning("TODO: Mapping to data and return the array of values")
|
||||
return .parsed
|
||||
}
|
||||
}
|
||||
|
||||
private extension ByteBuffer {
|
||||
|
||||
@@ -41,6 +41,18 @@ final class RedisDataDecoderParsingTests: XCTestCase {
|
||||
])
|
||||
}
|
||||
|
||||
func testParsing_with_arrays() throws {
|
||||
try parseTest_singleValue(input: "*1\r\n+!\r\n")
|
||||
try parseTest_singleValue(input: "*2\r\n*1\r\n:1\r\n:3\r\n")
|
||||
try parseTest_singleValue(input: "*0\r\n".convertedToData())
|
||||
try parseTest_singleValue(input: "*-1\r\n".convertedToData())
|
||||
}
|
||||
|
||||
func testParsing_with_arrays_recursively() throws {
|
||||
try parseTest_recursive(withChunks: ["*2\r", "\n+a\r\n+a\r\n*", "0\r\n"])
|
||||
try parseTest_recursive(withChunks: ["*-1\r".convertedToData(), "\n".convertedToData()])
|
||||
}
|
||||
|
||||
/// See parse_Test_singleValue(input:) String
|
||||
private func parseTest_singleValue(input: String) throws {
|
||||
try parseTest_singleValue(input: input.convertedToData())
|
||||
@@ -208,7 +220,7 @@ extension RedisDataDecoderParsingTests {
|
||||
}
|
||||
|
||||
func testParsing_bulkString_handlesLargeSizes() throws {
|
||||
let bytes = [UInt8].init(repeating: .dollar, count: 10_000_000)
|
||||
let bytes = [UInt8].init(repeating: .dollar, count: 1_000_000)
|
||||
let data = "$\(bytes.count)\r\n".convertedToData() + Data(bytes: bytes) + "\r\n".convertedToData()
|
||||
XCTAssertEqual(try parseTestBulkString(data), .parsed)
|
||||
}
|
||||
@@ -227,6 +239,55 @@ extension RedisDataDecoderParsingTests {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Array Parsing
|
||||
|
||||
extension RedisDataDecoderParsingTests {
|
||||
func testParsing_array_whenNull_returnsNil() {
|
||||
XCTAssertEqual(try parseTestArray("*-1\r\n"), .parsed)
|
||||
}
|
||||
|
||||
func testParsing_array_whenEmpty_returnsEmpty() {
|
||||
XCTAssertEqual(try parseTestArray("*0\r\n"), .parsed)
|
||||
}
|
||||
|
||||
func testParsing_array_handlesLargeSizes() {
|
||||
let range = 0..<1000
|
||||
var data = "*\(range.endIndex)\r\n".convertedToData()
|
||||
range.forEach { _ in
|
||||
data += "$5\r\n".convertedToData()
|
||||
data += Data(bytes: [0xaa, 0xbb, 0xcc, 0xab, 0xff])
|
||||
data += "\r\n".convertedToData()
|
||||
}
|
||||
|
||||
XCTAssertEqual(try parseTestArray(data), .parsed)
|
||||
}
|
||||
|
||||
func testParsing_array_handlesMixedTypes() {
|
||||
XCTAssertEqual(try parseTestArray("*3\r\n:3\r\n+OK\r\n$1\r\na\r\n"), .parsed)
|
||||
}
|
||||
|
||||
func testParsing_array_handlesNullElements() {
|
||||
XCTAssertEqual(try parseTestArray("*3\r\n:3\r\n$-1\r\n:30\r\n"), .parsed)
|
||||
}
|
||||
|
||||
func testParsing_array_handlesNestedArrays() {
|
||||
XCTAssertEqual(try parseTestArray("*2\r\n:3\r\n*2\r\n:30\r\n:15\r\n"), .parsed)
|
||||
}
|
||||
|
||||
private func parseTestArray(_ input: String) throws -> RedisDataDecoder._RedisDataDecodingState {
|
||||
return try parseTestArray(input.convertedToData())
|
||||
}
|
||||
|
||||
private func parseTestArray(_ input: Data) throws -> RedisDataDecoder._RedisDataDecodingState {
|
||||
var buffer = allocator.buffer(capacity: input.count)
|
||||
buffer.write(bytes: input)
|
||||
|
||||
var position = 1 // "trim" token
|
||||
|
||||
return try RedisDataDecoder()._parseArray(at: &position, from: buffer)
|
||||
}
|
||||
}
|
||||
|
||||
extension RedisDataDecoderParsingTests {
|
||||
static var allTests = [
|
||||
("testParsing_with_simpleString", testParsing_with_simpleString),
|
||||
@@ -235,6 +296,8 @@ extension RedisDataDecoderParsingTests {
|
||||
("testParsing_with_integer_recursively", testParsing_with_integer_recursively),
|
||||
("testParsing_with_bulkString", testParsing_with_bulkString),
|
||||
("testParsing_with_bulkString_recursively", testParsing_with_bulkString_recursively),
|
||||
("testParsing_with_arrays", testParsing_with_arrays),
|
||||
("testParsing_with_arrays_recursively", testParsing_with_arrays_recursively),
|
||||
("testParsing_simpleString_missingEndings_returnsNil", testParsing_simpleString_missingEndings_returnsNil),
|
||||
("testParsing_simpleString_withNoContent_returnsEmpty", testParsing_simpleString_withNoContent_returnsEmpty),
|
||||
("testParsing_simpleString_withContent_returnsExpectedContent", testParsing_simpleString_withContent_returnsExpectedContent),
|
||||
@@ -247,5 +310,11 @@ extension RedisDataDecoderParsingTests {
|
||||
("testParsing_bulkString_withNull_returnsNil", testParsing_bulkString_withNull_returnsNil),
|
||||
("testParsing_bulkString_handlesRawBytes", testParsing_bulkString_handlesRawBytes),
|
||||
("testParsing_bulkString_handlesLargeSizes", testParsing_bulkString_handlesLargeSizes),
|
||||
("testParsing_array_whenNull_returnsNil", testParsing_array_whenNull_returnsNil),
|
||||
("testParsing_array_whenEmpty_returnsEmpty", testParsing_array_whenEmpty_returnsEmpty),
|
||||
("testParsing_array_handlesLargeSizes", testParsing_array_handlesLargeSizes),
|
||||
("testParsing_array_handlesMixedTypes", testParsing_array_handlesMixedTypes),
|
||||
("testParsing_array_handlesNullElements", testParsing_array_handlesNullElements),
|
||||
("testParsing_array_handlesNestedArrays", testParsing_array_handlesNestedArrays),
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user