mirror of
https://github.com/apple/swift-nio-extras.git
synced 2025-05-14 17:02:43 +08:00
Motivation: To simplify the enum from the calling perspective. Modifications: Removed integer backing. Removed a string addition from a test that wasn’t actually adding anything. Result: The integer for the enum can not be seen publicly.
297 lines
13 KiB
Swift
297 lines
13 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the SwiftNIO open source project
|
|
//
|
|
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
|
|
// Licensed under Apache License v2.0
|
|
//
|
|
// See LICENSE.txt for license information
|
|
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import XCTest
|
|
import NIO
|
|
import NIOExtras
|
|
|
|
private let standardDataString = "abcde"
|
|
|
|
class LengthFieldBasedFrameDecoderTest: XCTestCase {
|
|
|
|
private var channel: EmbeddedChannel!
|
|
private var decoderUnderTest: LengthFieldBasedFrameDecoder!
|
|
|
|
override func setUp() {
|
|
self.channel = EmbeddedChannel()
|
|
}
|
|
|
|
func testDecodeWithUInt8HeaderWithData() throws {
|
|
|
|
self.decoderUnderTest = LengthFieldBasedFrameDecoder(lengthFieldLength: .one, lengthFieldEndianness: .little)
|
|
try? self.channel.pipeline.add(handler: self.decoderUnderTest).wait()
|
|
|
|
let dataBytes: [UInt8] = [10, 20, 30, 40]
|
|
let dataBytesLengthHeader = UInt8(dataBytes.count)
|
|
|
|
var buffer = self.channel.allocator.buffer(capacity: 5)
|
|
buffer.write(bytes: [dataBytesLengthHeader])
|
|
buffer.write(bytes: dataBytes)
|
|
|
|
XCTAssertTrue(try self.channel.writeInbound(buffer))
|
|
|
|
var outputBuffer: ByteBuffer? = self.channel.readInbound()
|
|
let outputData = outputBuffer?.readBytes(length: dataBytes.count)
|
|
|
|
XCTAssertEqual(dataBytes, outputData)
|
|
XCTAssertFalse(try self.channel.finish())
|
|
}
|
|
|
|
func testDecodeWithUInt16HeaderWithString() throws {
|
|
|
|
self.decoderUnderTest = LengthFieldBasedFrameDecoder(lengthFieldLength: .two, lengthFieldEndianness: .little)
|
|
try? self.channel.pipeline.add(handler: self.decoderUnderTest).wait()
|
|
|
|
let dataLength: UInt16 = 5
|
|
|
|
var buffer = self.channel.allocator.buffer(capacity: 7) // 2 byte header + 5 character string
|
|
buffer.write(integer: dataLength, endianness: .little, as: UInt16.self)
|
|
buffer.write(string: standardDataString)
|
|
|
|
XCTAssertTrue(try self.channel.writeInbound(buffer))
|
|
|
|
var outputBuffer: ByteBuffer? = self.channel.readInbound()
|
|
let outputData = outputBuffer?.readString(length: standardDataString.count)
|
|
|
|
XCTAssertEqual(standardDataString, outputData)
|
|
XCTAssertFalse(try self.channel.finish())
|
|
}
|
|
|
|
func testDecodeWithUInt32HeaderWithString() throws {
|
|
|
|
self.decoderUnderTest = LengthFieldBasedFrameDecoder(lengthFieldLength: .four, lengthFieldEndianness: .little)
|
|
try? self.channel.pipeline.add(handler: self.decoderUnderTest).wait()
|
|
|
|
let dataLength: UInt32 = 5
|
|
|
|
var buffer = self.channel.allocator.buffer(capacity: 9) // 4 byte header + 5 character string
|
|
buffer.write(integer: dataLength, endianness: .little, as: UInt32.self)
|
|
buffer.write(string: standardDataString)
|
|
|
|
XCTAssertTrue(try self.channel.writeInbound(buffer))
|
|
|
|
var outputBuffer: ByteBuffer? = self.channel.readInbound()
|
|
let outputData = outputBuffer?.readString(length: standardDataString.count)
|
|
|
|
XCTAssertEqual(standardDataString, outputData)
|
|
XCTAssertFalse(try self.channel.finish())
|
|
}
|
|
|
|
func testDecodeWithUInt64HeaderWithString() throws {
|
|
|
|
self.decoderUnderTest = LengthFieldBasedFrameDecoder(lengthFieldLength: .eight, lengthFieldEndianness: .little)
|
|
try? self.channel.pipeline.add(handler: self.decoderUnderTest).wait()
|
|
|
|
let dataLength: UInt64 = 5
|
|
|
|
var buffer = self.channel.allocator.buffer(capacity: 13) // 8 byte header + 5 character string
|
|
buffer.write(integer: dataLength, endianness: .little, as: UInt64.self)
|
|
buffer.write(string: standardDataString)
|
|
|
|
XCTAssertTrue(try self.channel.writeInbound(buffer))
|
|
|
|
var outputBuffer: ByteBuffer? = self.channel.readInbound()
|
|
let outputData = outputBuffer?.readString(length: standardDataString.count)
|
|
|
|
XCTAssertEqual(standardDataString, outputData)
|
|
XCTAssertFalse(try self.channel.finish())
|
|
}
|
|
|
|
func testDecodeWithInt64HeaderWithString() throws {
|
|
|
|
self.decoderUnderTest = LengthFieldBasedFrameDecoder(lengthFieldLength: .eight, lengthFieldEndianness: .little)
|
|
try? self.channel.pipeline.add(handler: self.decoderUnderTest).wait()
|
|
|
|
let dataLength: Int64 = 5
|
|
|
|
var buffer = self.channel.allocator.buffer(capacity: 13) // 8 byte header + 5 character string
|
|
buffer.write(integer: dataLength, endianness: .little, as: Int64.self)
|
|
buffer.write(string: standardDataString)
|
|
|
|
XCTAssertTrue(try self.channel.writeInbound(buffer))
|
|
|
|
var outputBuffer: ByteBuffer? = self.channel.readInbound()
|
|
let outputData = outputBuffer?.readString(length: standardDataString.count)
|
|
|
|
XCTAssertEqual(standardDataString, outputData)
|
|
XCTAssertFalse(try self.channel.finish())
|
|
}
|
|
|
|
func testDecodeWithInt64HeaderStringBigEndian() throws {
|
|
|
|
self.decoderUnderTest = LengthFieldBasedFrameDecoder(lengthFieldLength: .eight, lengthFieldEndianness: .big)
|
|
try? self.channel.pipeline.add(handler: self.decoderUnderTest).wait()
|
|
|
|
let dataLength: Int64 = 5
|
|
|
|
var buffer = self.channel.allocator.buffer(capacity: 13) // 8 byte header + 5 character string
|
|
buffer.write(integer: dataLength, endianness: .big, as: Int64.self)
|
|
buffer.write(string: standardDataString)
|
|
|
|
XCTAssertTrue(try self.channel.writeInbound(buffer))
|
|
|
|
var outputBuffer: ByteBuffer? = self.channel.readInbound()
|
|
let outputData = outputBuffer?.readString(length: standardDataString.count)
|
|
|
|
XCTAssertEqual(standardDataString, outputData)
|
|
XCTAssertFalse(try self.channel.finish())
|
|
}
|
|
|
|
func testDecodeWithInt64HeaderStringDefaultingToBigEndian() throws {
|
|
|
|
self.decoderUnderTest = LengthFieldBasedFrameDecoder(lengthFieldLength: .eight)
|
|
try? self.channel.pipeline.add(handler: self.decoderUnderTest).wait()
|
|
|
|
let dataLength: Int64 = 5
|
|
|
|
var buffer = self.channel.allocator.buffer(capacity: 13) // 8 byte header + 5 character string
|
|
buffer.write(integer: dataLength, endianness: .big, as: Int64.self)
|
|
buffer.write(string: standardDataString)
|
|
|
|
XCTAssertTrue(try self.channel.writeInbound(buffer))
|
|
|
|
var outputBuffer: ByteBuffer? = self.channel.readInbound()
|
|
let outputData = outputBuffer?.readString(length: standardDataString.count)
|
|
|
|
XCTAssertEqual(standardDataString, outputData)
|
|
XCTAssertFalse(try self.channel.finish())
|
|
}
|
|
|
|
func testDecodeWithUInt8HeaderTwoFrames() throws {
|
|
|
|
self.decoderUnderTest = LengthFieldBasedFrameDecoder(lengthFieldLength: .one, lengthFieldEndianness: .little)
|
|
try? self.channel.pipeline.add(handler: self.decoderUnderTest).wait()
|
|
|
|
let firstFrameDataLength: UInt8 = 5
|
|
let secondFrameDataLength: UInt8 = 3
|
|
let secondFrameString = "123"
|
|
|
|
var buffer = self.channel.allocator.buffer(capacity: 10) // 1 byte header + 5 character string + 1 byte header + 3 character string
|
|
buffer.write(integer: firstFrameDataLength, endianness: .little, as: UInt8.self)
|
|
buffer.write(string: standardDataString)
|
|
buffer.write(integer: secondFrameDataLength, endianness: .little, as: UInt8.self)
|
|
buffer.write(string: secondFrameString)
|
|
|
|
XCTAssertTrue(try self.channel.writeInbound(buffer))
|
|
var outputFirstFrameBuffer: ByteBuffer? = self.channel.readInbound()
|
|
|
|
let outputFirstFrameData = outputFirstFrameBuffer?.readString(length: standardDataString.count)
|
|
XCTAssertEqual(standardDataString, outputFirstFrameData)
|
|
|
|
var outputSecondFrameBuffer: ByteBuffer? = self.channel.readInbound()
|
|
|
|
let outputSecondFrameData = outputSecondFrameBuffer?.readString(length: secondFrameString.count)
|
|
XCTAssertEqual(secondFrameString, outputSecondFrameData)
|
|
|
|
XCTAssertFalse(try self.channel.finish())
|
|
}
|
|
|
|
func testEmptyBuffer() throws {
|
|
|
|
self.decoderUnderTest = LengthFieldBasedFrameDecoder(lengthFieldLength: .one, lengthFieldEndianness: .little)
|
|
try? self.channel.pipeline.add(handler: self.decoderUnderTest).wait()
|
|
|
|
var buffer = self.channel.allocator.buffer(capacity: 1)
|
|
XCTAssertFalse(try self.channel.writeInbound(buffer))
|
|
XCTAssertFalse(try self.channel.finish())
|
|
}
|
|
|
|
func testDecodeWithUInt16HeaderWithPartialHeader() throws {
|
|
|
|
self.decoderUnderTest = LengthFieldBasedFrameDecoder(lengthFieldLength: .two, lengthFieldEndianness: .little)
|
|
try? self.channel.pipeline.add(handler: self.decoderUnderTest).wait()
|
|
|
|
let dataLength: UInt8 = 5 // 8 byte is only half the length required
|
|
|
|
var buffer = self.channel.allocator.buffer(capacity: 7) // 2 byte header + 5 character string
|
|
buffer.write(integer: dataLength, endianness: .little, as: UInt8.self)
|
|
|
|
XCTAssertFalse(try self.channel.writeInbound(buffer))
|
|
XCTAssertFalse(try self.channel.finish())
|
|
}
|
|
|
|
func testDecodeWithUInt16HeaderWithPartialBody() throws {
|
|
|
|
self.decoderUnderTest = LengthFieldBasedFrameDecoder(lengthFieldLength: .two, lengthFieldEndianness: .little)
|
|
try? self.channel.pipeline.add(handler: self.decoderUnderTest).wait()
|
|
|
|
let dataLength: UInt16 = 7
|
|
|
|
var buffer = self.channel.allocator.buffer(capacity: 9) // 2 byte header + 7 character string
|
|
buffer.write(integer: dataLength, endianness: .little, as: UInt16.self)
|
|
buffer.write(string: standardDataString) // 2 bytes short of the 7 required.
|
|
|
|
XCTAssertFalse(try self.channel.writeInbound(buffer))
|
|
XCTAssertFalse(try self.channel.finish())
|
|
}
|
|
|
|
func testRemoveHandlerWhenBufferIsEmpty() throws {
|
|
|
|
self.decoderUnderTest = LengthFieldBasedFrameDecoder(lengthFieldLength: .eight, lengthFieldEndianness: .little)
|
|
try? self.channel.pipeline.add(handler: self.decoderUnderTest).wait()
|
|
|
|
let dataLength: Int64 = 5
|
|
|
|
var buffer = self.channel.allocator.buffer(capacity: 13) // 8 byte header + 5 character string
|
|
buffer.write(integer: dataLength, endianness: .little, as: Int64.self)
|
|
buffer.write(string: standardDataString)
|
|
|
|
XCTAssertTrue(try self.channel.writeInbound(buffer))
|
|
|
|
var outputBuffer: ByteBuffer? = self.channel.readInbound()
|
|
let outputData = outputBuffer?.readString(length: standardDataString.count)
|
|
|
|
_ = try self.channel.pipeline.remove(handler: self.decoderUnderTest).wait()
|
|
|
|
XCTAssertEqual(standardDataString, outputData)
|
|
XCTAssertNoThrow(try self.channel.throwIfErrorCaught())
|
|
XCTAssertFalse(try self.channel.finish())
|
|
}
|
|
|
|
func testRemoveHandlerWhenBufferIsNotEmpty() throws {
|
|
|
|
self.decoderUnderTest = LengthFieldBasedFrameDecoder(lengthFieldLength: .eight, lengthFieldEndianness: .little)
|
|
try? self.channel.pipeline.add(handler: self.decoderUnderTest).wait()
|
|
|
|
let extraUnusedDataString = "fghi"
|
|
let dataLength: Int64 = 5
|
|
|
|
var buffer = self.channel.allocator.buffer(capacity: 17) // 8 byte header + 5 character string + 4 unused
|
|
buffer.write(integer: dataLength, endianness: .little, as: Int64.self)
|
|
buffer.write(string: standardDataString + extraUnusedDataString)
|
|
|
|
XCTAssertTrue(try channel.writeInbound(buffer))
|
|
|
|
var outputBuffer: ByteBuffer? = self.channel.readInbound()
|
|
let outputData = outputBuffer?.readString(length: standardDataString.count)
|
|
|
|
_ = try self.channel.pipeline.remove(handler: self.decoderUnderTest).wait()
|
|
|
|
XCTAssertThrowsError(try self.channel.throwIfErrorCaught()) { error in
|
|
|
|
guard let error = error as? NIOExtrasErrors.LeftOverBytesError else {
|
|
XCTFail()
|
|
return
|
|
}
|
|
|
|
var expectedBuffer = self.channel.allocator.buffer(capacity: 7)
|
|
expectedBuffer.write(string: extraUnusedDataString)
|
|
XCTAssertEqual(error.leftOverBytes, expectedBuffer)
|
|
}
|
|
|
|
XCTAssertEqual(standardDataString, outputData)
|
|
XCTAssertFalse(try self.channel.finish())
|
|
}
|
|
}
|