mirror of
https://github.com/apple/swift-nio.git
synced 2026-05-20 20:30:36 +00:00
Motivation: We accidentally removed the 'NIOFileSystem' module from the '_NIOFileSystem' product in the last release. Modifications: - Rename 'NIOFileSystem' and 'NIOFileSystemFoundationCompat' to 'NIOFS' and 'NIOFSFoundationCompat' - Add back 'NIOFileSystem' which re-exports '_NIOFileSystem' (there was no publicly available 'NIOFileSystemFoundationCompat' module to remove, only '_NIOFileSystemFoundationCompat'). Result: Fewer breaks
282 lines
10 KiB
Swift
282 lines
10 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the SwiftNIO open source project
|
|
//
|
|
// Copyright (c) 2023 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 NIOCore
|
|
import NIOFS
|
|
import XCTest
|
|
|
|
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
|
|
final class BufferedReaderTests: XCTestCase {
|
|
func testBufferedReaderSizeAndCapacity() async throws {
|
|
let fs = FileSystem.shared
|
|
try await fs.withFileHandle(forReadingAt: #filePath) { handle in
|
|
var reader = handle.bufferedReader(capacity: .bytes(128 * 1024))
|
|
XCTAssertEqual(reader.count, 0)
|
|
XCTAssertEqual(reader.capacity, 128 * 1024)
|
|
|
|
let byte = try await reader.read(.bytes(1))
|
|
XCTAssertEqual(byte.readableBytes, 1)
|
|
|
|
// Buffer should be non-empty; there's more than one byte in this file.
|
|
XCTAssertGreaterThan(reader.count, 0)
|
|
// It should be no greater than the buffer capacity, however.
|
|
XCTAssertLessThanOrEqual(reader.count, reader.capacity)
|
|
}
|
|
}
|
|
|
|
func testBufferedReaderReadFixedSize() async throws {
|
|
let fs = FileSystem.shared
|
|
let path = try await fs.temporaryFilePath()
|
|
|
|
try await fs.withFileHandle(
|
|
forWritingAt: path,
|
|
options: .newFile(replaceExisting: false)
|
|
) { handle in
|
|
var writer = handle.bufferedWriter()
|
|
try await writer.write(contentsOf: repeatElement(0, count: 1024 * 1024))
|
|
try await writer.flush()
|
|
}
|
|
|
|
try await fs.withFileHandle(forReadingAt: path) { handle in
|
|
var reader = handle.bufferedReader()
|
|
let allTheBytes = try await reader.read(.bytes(1024 * 1024))
|
|
XCTAssertEqual(allTheBytes.readableBytes, 1024 * 1024)
|
|
|
|
let noBytes = try await reader.read(.bytes(1024))
|
|
XCTAssertEqual(noBytes.readableBytes, 0)
|
|
}
|
|
}
|
|
|
|
func testBufferedReaderMultipleReads() async throws {
|
|
let fs = FileSystem.shared
|
|
let path = try await fs.temporaryFilePath()
|
|
|
|
try await fs.withFileHandle(
|
|
forWritingAt: path,
|
|
options: .newFile(replaceExisting: false)
|
|
) { handle in
|
|
var writer = handle.bufferedWriter()
|
|
try await writer.write(contentsOf: repeatElement(0, count: 1024 * 1024))
|
|
try await writer.flush()
|
|
}
|
|
|
|
try await fs.withFileHandle(forReadingAt: path) { handle in
|
|
var reader = handle.bufferedReader()
|
|
var allTheBytes = [UInt8]()
|
|
|
|
while true {
|
|
let byte = try await reader.read(.bytes(100))
|
|
if byte.readableBytes == 0 { break }
|
|
allTheBytes.append(contentsOf: byte.readableBytesView)
|
|
}
|
|
|
|
XCTAssertEqual(allTheBytes.count, 1024 * 1024)
|
|
}
|
|
}
|
|
|
|
func testBufferedReaderReadingShort() async throws {
|
|
let fs = FileSystem.shared
|
|
try await fs.withFileHandle(forReadingAt: #filePath) { handle in
|
|
var reader = handle.bufferedReader(capacity: .bytes(128))
|
|
var buffer = ByteBuffer()
|
|
while true {
|
|
let chunk = try await reader.read(.bytes(128))
|
|
buffer.writeImmutableBuffer(chunk)
|
|
if chunk.readableBytes < 128 { break }
|
|
}
|
|
|
|
let info = try await handle.info()
|
|
XCTAssertEqual(Int64(buffer.readableBytes), info.size)
|
|
}
|
|
}
|
|
|
|
func testBufferedReaderReadWhile() async throws {
|
|
let fs = FileSystem.shared
|
|
let path = try await fs.temporaryFilePath()
|
|
|
|
try await fs.withFileHandle(
|
|
forWritingAt: path,
|
|
options: .newFile(replaceExisting: false)
|
|
) { handle in
|
|
var writer = handle.bufferedWriter()
|
|
for byte in UInt8.min...UInt8.max {
|
|
try await writer.write(contentsOf: repeatElement(byte, count: 1024))
|
|
}
|
|
try await writer.flush()
|
|
}
|
|
|
|
try await fs.withFileHandle(forReadingAt: path) { handle in
|
|
var reader = handle.bufferedReader()
|
|
let (zeros, isEOFZeros) = try await reader.read { $0 == 0 }
|
|
XCTAssertEqual(zeros, ByteBuffer(bytes: Array(repeating: 0, count: 1024)))
|
|
XCTAssertFalse(isEOFZeros)
|
|
|
|
let (onesAndTwos, isEOFOnesAndTwos) = try await reader.read { $0 < 3 }
|
|
var expectedOnesAndTwos = ByteBuffer()
|
|
expectedOnesAndTwos.writeRepeatingByte(1, count: 1024)
|
|
expectedOnesAndTwos.writeRepeatingByte(2, count: 1024)
|
|
|
|
XCTAssertEqual(onesAndTwos, expectedOnesAndTwos)
|
|
XCTAssertFalse(isEOFOnesAndTwos)
|
|
|
|
let (threesThroughNines, isEOFThreesThroughNines) = try await reader.read { $0 < 10 }
|
|
var expectedThreesThroughNines = ByteBuffer()
|
|
for byte in UInt8(3)...9 {
|
|
expectedThreesThroughNines.writeRepeatingByte(byte, count: 1024)
|
|
}
|
|
XCTAssertEqual(threesThroughNines, expectedThreesThroughNines)
|
|
XCTAssertFalse(isEOFThreesThroughNines)
|
|
|
|
let (theRest, isEOFTheRest) = try await reader.read { _ in true }
|
|
XCTAssertEqual(theRest.readableBytes, 246 * 1024)
|
|
XCTAssertTrue(isEOFTheRest)
|
|
}
|
|
}
|
|
|
|
func testBufferedReaderDropFixedSize() async throws {
|
|
let fs = FileSystem.shared
|
|
let path = try await fs.temporaryFilePath()
|
|
|
|
try await fs.withFileHandle(
|
|
forWritingAt: path,
|
|
options: .newFile(replaceExisting: false)
|
|
) { handle in
|
|
var writer = handle.bufferedWriter()
|
|
for byte in UInt8.min...UInt8.max {
|
|
try await writer.write(contentsOf: repeatElement(byte, count: 1000))
|
|
}
|
|
try await writer.flush()
|
|
}
|
|
|
|
try await fs.withFileHandle(forReadingAt: path) { handle in
|
|
var reader = handle.bufferedReader()
|
|
try await reader.drop(1000)
|
|
let ones = try await reader.read(.bytes(1000))
|
|
XCTAssertEqual(ones, ByteBuffer(repeating: 1, count: 1000))
|
|
|
|
try await reader.drop(1500)
|
|
let threes = try await reader.read(.bytes(500))
|
|
XCTAssertEqual(threes, ByteBuffer(repeating: 3, count: 500))
|
|
|
|
// More than remains in the file.
|
|
try await reader.drop(1_000_000)
|
|
let empty = try await reader.read(.bytes(1000))
|
|
XCTAssertEqual(empty.readableBytes, 0)
|
|
}
|
|
}
|
|
|
|
func testBufferedReaderDropWhile() async throws {
|
|
let fs = FileSystem.shared
|
|
let path = try await fs.temporaryFilePath()
|
|
|
|
try await fs.withFileHandle(
|
|
forWritingAt: path,
|
|
options: .newFile(replaceExisting: false)
|
|
) { handle in
|
|
var writer = handle.bufferedWriter()
|
|
for byte in UInt8.min...UInt8.max {
|
|
try await writer.write(contentsOf: repeatElement(byte, count: 1024))
|
|
}
|
|
try await writer.flush()
|
|
}
|
|
|
|
try await fs.withFileHandle(forReadingAt: path) { handle in
|
|
var reader = handle.bufferedReader()
|
|
try await reader.drop(while: { $0 < 255 })
|
|
let bytes = try await reader.read(.bytes(1024))
|
|
XCTAssertEqual(bytes, ByteBuffer(repeating: 255, count: 1024))
|
|
|
|
let empty = try await reader.read(.bytes(1))
|
|
XCTAssertEqual(empty.readableBytes, 0)
|
|
}
|
|
}
|
|
|
|
func testBufferedReaderReadingText() async throws {
|
|
let fs = FileSystem.shared
|
|
let path = try await fs.temporaryFilePath()
|
|
|
|
try await fs.withFileHandle(
|
|
forWritingAt: path,
|
|
options: .newFile(replaceExisting: false)
|
|
) { handle in
|
|
let text = """
|
|
Here's to the crazy ones, the misfits, the rebels, the troublemakers, \
|
|
the round pegs in the square holes, the ones who see things differently.
|
|
"""
|
|
|
|
var writer = handle.bufferedWriter()
|
|
try await writer.write(contentsOf: text.utf8)
|
|
try await writer.flush()
|
|
}
|
|
|
|
try await fs.withFileHandle(forReadingAt: path) { file in
|
|
var reader = file.bufferedReader()
|
|
var words = [String]()
|
|
|
|
func isWordIsh(_ byte: UInt8) -> Bool {
|
|
switch byte {
|
|
case UInt8(ascii: "a")...UInt8(ascii: "z"),
|
|
UInt8(ascii: "A")...UInt8(ascii: "Z"),
|
|
UInt8(ascii: "'"):
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
repeat {
|
|
// Gobble up whitespace etc..
|
|
try await reader.drop(while: { !isWordIsh($0) })
|
|
// Read the next word.
|
|
var (characters, _) = try await reader.read(while: isWordIsh(_:))
|
|
|
|
if characters.readableBytes == 0 {
|
|
break // Done.
|
|
} else {
|
|
words.append(characters.readString(length: characters.readableBytes)!)
|
|
}
|
|
} while true
|
|
|
|
let expected: [String] = [
|
|
"Here's",
|
|
"to",
|
|
"the",
|
|
"crazy",
|
|
"ones",
|
|
"the",
|
|
"misfits",
|
|
"the",
|
|
"rebels",
|
|
"the",
|
|
"troublemakers",
|
|
"the",
|
|
"round",
|
|
"pegs",
|
|
"in",
|
|
"the",
|
|
"square",
|
|
"holes",
|
|
"the",
|
|
"ones",
|
|
"who",
|
|
"see",
|
|
"things",
|
|
"differently",
|
|
]
|
|
|
|
XCTAssertEqual(words, expected)
|
|
}
|
|
}
|
|
}
|