Files
swift-nio/Tests/NIOCoreTests/ByteBufferQUICBinaryEncodingStrategyTests.swift
hamzahrmalik 752abd759c Make ByteBufferQUICBinaryEncodingStrategyTests compatible with 32-bit systems (#2904)
This is a followup to #2867

Some of the literals used in the test cases were too big to fit in an
Int32
This is fine on 64-bit systems, because the literals are considered as
`Int`, which is Int64 on those systems
However, on 32-bit systems, those literals are considered as Int64

Change: Add `as Int64` where needed, to tell the compiler we want these
literals to be treated as Int64, which should allow these tests to run
on 32 bit systems too
2024-10-07 07:18:20 +00:00

139 lines
6.4 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2024 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
@testable import NIOCore
final class ByteBufferQUICBinaryEncodingStrategyTests: XCTestCase {
// MARK: - writeEncodedInteger tests
func testWriteOneByteQUICVariableLengthInteger() {
// One byte, ie less than 63, just write out as-is
for number in 0..<63 {
var buffer = ByteBuffer()
let strategy = ByteBuffer.QUICBinaryEncodingStrategy.quic
let bytesWritten = strategy.writeInteger(number, to: &buffer)
XCTAssertEqual(bytesWritten, 1)
// The number is written exactly as is
XCTAssertEqual(buffer.readInteger(as: UInt8.self), UInt8(number))
XCTAssertEqual(buffer.readableBytes, 0)
}
}
func testWriteBigUInt8() {
// This test case specifically tests the scenario where 2 bytes are needed, but the number being written is UInt8.
// A naive implementation of the quic variable length integer encoder might check whether the number is in
// the range of 64..<16383, to determine that it should be written with 2 bytes.
// However, constructing such a range on a UInt8 would actually construct 64..<0, because 16383 can't be represented as UInt8.
// So this test makes sure we didn't make that mistake
let number: UInt8 = .max
var buffer = ByteBuffer()
let strategy = ByteBuffer.QUICBinaryEncodingStrategy.quic
let bytesWritten = strategy.writeInteger(number, to: &buffer)
XCTAssertEqual(bytesWritten, 2)
XCTAssertEqual(buffer.readInteger(as: UInt16.self), 0b01000000_11111111)
XCTAssertEqual(buffer.readableBytes, 0)
}
func testWriteTwoByteQUICVariableLengthInteger() {
var buffer = ByteBuffer()
let strategy = ByteBuffer.QUICBinaryEncodingStrategy.quic
let bytesWritten = strategy.writeInteger(0b00111011_10111101, to: &buffer)
XCTAssertEqual(bytesWritten, 2)
// We need to mask the first 2 bits with 01 to indicate this is a 2 byte integer
// Final result 0b01111011_10111101
XCTAssertEqual(buffer.readInteger(as: UInt16.self), 0b01111011_10111101)
XCTAssertEqual(buffer.readableBytes, 0)
}
func testWriteFourByteQUICVariableLengthInteger() {
var buffer = ByteBuffer()
let strategy = ByteBuffer.QUICBinaryEncodingStrategy.quic
let bytesWritten = strategy.writeInteger(0b00011101_01111111_00111110_01111101 as Int64, to: &buffer)
XCTAssertEqual(bytesWritten, 4)
// 2 bit mask is 10 for 4 bytes so this becomes 0b10011101_01111111_00111110_01111101
XCTAssertEqual(buffer.readInteger(as: UInt32.self), 0b10011101_01111111_00111110_01111101)
XCTAssertEqual(buffer.readableBytes, 0)
}
func testWriteEightByteQUICVariableLengthInteger() {
var buffer = ByteBuffer()
let strategy = ByteBuffer.QUICBinaryEncodingStrategy.quic
let bytesWritten = strategy.writeInteger(
0b00000010_00011001_01111100_01011110_11111111_00010100_11101000_10001100 as Int64,
to: &buffer
)
XCTAssertEqual(bytesWritten, 8)
// 2 bit mask is 11 for 8 bytes so this becomes 0b11000010_00011001_01111100_01011110_11111111_00010100_11101000_10001100
XCTAssertEqual(
buffer.readInteger(as: UInt64.self),
0b11000010_00011001_01111100_01011110_11111111_00010100_11101000_10001100
)
XCTAssertEqual(buffer.readableBytes, 0)
}
// MARK: - writeEncodedIntegerWithReservedCapacity tests
func testWriteOneByteQUICVariableLengthIntegerWithTwoBytesReserved() {
// We only need one byte but the encoder will use 2 because we reserved 2
var buffer = ByteBuffer()
let strategy = ByteBuffer.QUICBinaryEncodingStrategy.quic
let bytesWritten = strategy.writeInteger(0b00000001, reservedCapacity: 2, to: &buffer)
XCTAssertEqual(bytesWritten, 2)
XCTAssertEqual(buffer.readInteger(as: UInt16.self), UInt16(0b01000000_00000001))
XCTAssertEqual(buffer.readableBytes, 0)
}
func testRoundtripWithReservedCapacity() {
// This test makes sure that a number encoded with more space than necessary can still be decoded as normal
for reservedCapacity in [0, 1, 2, 4, 8] {
let testNumbers: [Int64] = [0, 63, 15293, 494_878_333, 151_288_809_941_952_652]
for testNumber in testNumbers {
var buffer = ByteBuffer()
let strategy = ByteBuffer.QUICBinaryEncodingStrategy.quic
let bytesWritten = strategy.writeInteger(
testNumber,
reservedCapacity: reservedCapacity,
to: &buffer
)
let minRequiredBytes = ByteBuffer.QUICBinaryEncodingStrategy.bytesNeededForInteger(testNumber)
// If the reserved capacity is higher than the min required, use the reserved number
let expectedUsedBytes = max(minRequiredBytes, reservedCapacity)
XCTAssertEqual(bytesWritten, expectedUsedBytes)
XCTAssertEqual(strategy.readInteger(as: UInt64.self, from: &buffer), UInt64(testNumber))
XCTAssertEqual(buffer.readableBytes, 0)
}
}
}
// MARK: - readEncodedInteger tests
func testReadEmptyQUICVariableLengthInteger() {
var buffer = ByteBuffer()
let strategy = ByteBuffer.QUICBinaryEncodingStrategy.quic
XCTAssertNil(strategy.readInteger(as: Int.self, from: &buffer))
}
func testWriteReadQUICVariableLengthInteger() {
let strategy = ByteBuffer.QUICBinaryEncodingStrategy.quic
let testNumbers: [Int64] = [37, 15293, 494_878_333, 151_288_809_941_952_652]
for integer in testNumbers {
var buffer = ByteBuffer()
_ = strategy.writeInteger(integer, to: &buffer)
XCTAssertEqual(strategy.readInteger(as: Int64.self, from: &buffer), integer)
}
}
}