Commit dc0b7e8b authored by Nathan Harris's avatar Nathan Harris

Merge branch 'resp-translator-refactor' into '47-proposal-feedback'

Refactor `RESPTranslator` to mutate the passed `ByteBuffer` directly.

See merge request Mordil/swift-redis-nio-client!63
parents 44c29169 b8c19488
......@@ -21,18 +21,19 @@ import NIO
public final class RedisByteDecoder: ByteToMessageDecoder {
/// `ByteToMessageDecoder.InboundOut`
public typealias InboundOut = RESPValue
private let parser: RESPTranslator
public init() {
self.parser = RESPTranslator()
}
/// See `ByteToMessageDecoder.decode(context:buffer:)`
public func decode(context: ChannelHandlerContext, buffer: inout ByteBuffer) throws -> DecodingState {
var position = 0
switch try RESPTranslator.parseBytes(&buffer, fromIndex: &position) {
case .incomplete: return .needMoreData
case let .parsed(value):
context.fireChannelRead(wrapInboundOut(value))
buffer.moveReaderIndex(forwardBy: position)
return .continue
}
guard let value = try self.parser.parseBytes(from: &buffer) else { return .needMoreData }
context.fireChannelRead(wrapInboundOut(value))
return .continue
}
/// See `ByteToMessageDecoder.decodeLast(context:buffer:seenEOF)`
......
......@@ -33,7 +33,7 @@ public final class RedisMessageEncoder: MessageToByteEncoder {
///
/// See [https://redis.io/topics/protocol](https://redis.io/topics/protocol) and `RESPEncoder.encode(data:out:)`
public func encode(data: RESPValue, out: inout ByteBuffer) throws {
RESPTranslator.writeValue(data, into: &out)
out.writeRESPValue(data)
logger.debug("Encoded \(data) to \(getPrintableString(for: &out))")
}
......
This diff is collapsed.
......@@ -253,10 +253,7 @@ extension RedisByteDecoderTests {
}
func test_badMessage_throws() {
do {
_ = try decodeTest("&3\r\n").0
XCTFail("Failed to properly throw error")
} catch { XCTAssertTrue(error is RESPTranslator.ParsingError) }
XCTAssertThrowsError(try decodeTest("&3\r\n").0)
}
private static let completeMessages = [
......
//===----------------------------------------------------------------------===//
//
// This source file is part of the RedisNIO open source project
//
// Copyright (c) 2019 RedisNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of RedisNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import Foundation
import NIO
@testable import RedisNIO
import XCTest
final class RESPTranslatorWritingTests: XCTestCase {
private let encoder = RESPTranslator.self
private let allocator = ByteBufferAllocator()
func testSimpleStrings() {
XCTAssertTrue(testPass(input: .simpleString("Test1".byteBuffer), expected: "+Test1\r\n"))
XCTAssertTrue(testPass(input: .simpleString("®in§³¾".byteBuffer), expected: "+®in§³¾\r\n"))
}
func testBulkStrings() {
let bytes: [UInt8] = [0x01, 0x02, 0x0a, 0x1b, 0xaa]
var buffer = allocator.buffer(capacity: 5)
buffer.writeBytes(bytes)
XCTAssertTrue(testPass(input: .bulkString(buffer), expected: "$5\r\n".bytes + bytes + "\r\n".bytes))
XCTAssertTrue(testPass(input: .init(bulk: "®in§³¾"), expected: "$10\r\n®in§³¾\r\n"))
XCTAssertTrue(testPass(input: .init(bulk: ""), expected: "$0\r\n\r\n"))
}
func testIntegers() {
XCTAssertTrue(testPass(input: .integer(Int.min), expected: ":\(Int.min)\r\n"))
XCTAssertTrue(testPass(input: .integer(0), expected: ":0\r\n"))
}
func testArrays() {
XCTAssertTrue(testPass(input: .array([]), expected: "*0\r\n"))
XCTAssertTrue(testPass(
input: .array([ .integer(3), .simpleString("foo".byteBuffer) ]),
expected: "*2\r\n:3\r\n+foo\r\n"
))
let bytes: [UInt8] = [ 0x0a, 0x1a, 0x1b, 0xff ]
var buffer = allocator.buffer(capacity: 4)
buffer.writeBytes(bytes)
XCTAssertTrue(testPass(
input: .array([ .array([ .integer(10), .bulkString(buffer) ]) ]),
expected: "*1\r\n*2\r\n:10\r\n$4\r\n".bytes + bytes + "\r\n".bytes
))
}
func testError() {
let error = RedisError(reason: "Manual error")
XCTAssertTrue(testPass(input: .error(error), expected: "-\(error.message)\r\n"))
}
func testNull() {
XCTAssertTrue(testPass(input: .null, expected: "$-1\r\n"))
}
func testDataEncoding() throws {
let name = #function
let data = Data(name.bytes).convertedToRESPValue()
XCTAssertTrue(testPass(input: data, expected: "$\(name.count)\r\n\(name)\r\n"))
}
private func testPass(input: RESPValue, expected: [UInt8]) -> Bool {
let allocator = ByteBufferAllocator()
var comparisonBuffer = allocator.buffer(capacity: expected.count)
comparisonBuffer.writeBytes(expected)
var buffer = allocator.buffer(capacity: expected.count)
encoder.writeValue(input.convertedToRESPValue(), into: &buffer)
return buffer == comparisonBuffer
}
private func testPass(input: RESPValue, expected: String) -> Bool {
let allocator = ByteBufferAllocator()
var comparisonBuffer = allocator.buffer(capacity: expected.count)
comparisonBuffer.writeString(expected)
var buffer = allocator.buffer(capacity: expected.count)
encoder.writeValue(input.convertedToRESPValue(), into: &buffer)
return buffer == comparisonBuffer
}
}
extension RESPTranslatorWritingTests {
static var allTests = [
("testSimpleStrings", testSimpleStrings),
("testBulkStrings", testBulkStrings),
("testIntegers", testIntegers),
("testArrays", testArrays),
("testError", testError),
("testNull", testNull),
("testDataEncoding", testDataEncoding),
]
}
This diff is collapsed.
......@@ -19,8 +19,7 @@ public func allTests() -> [XCTestCaseEntry] {
return [
testCase(RedisByteDecoderTests.allTests),
testCase(RedisMessageEncoderTests.allTests),
testCase(RESPTranslatorParsingTests.allTests),
testCase(RESPTranslatorWritingTests.allTests),
testCase(RESPTranslatorTests.allTests),
testCase(BasicCommandsTests.allTests),
testCase(SetCommandsTests.allTests),
testCase(HashCommandsTests.allTests),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment