Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -330,5 +330,9 @@ let package = Package(
name: "SmithyHTTPAPITests",
dependencies: ["SmithyHTTPAPI"]
),
.testTarget(
name: "SmithyStreamsTests",
dependencies: ["SmithyStreams", "Smithy"]
),
].compactMap { $0 }
)
1 change: 1 addition & 0 deletions Sources/Smithy/Stream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public enum StreamError: Error, Sendable {
case invalidOffset(String)
case notSupported(String)
case connectionReleased(String)
case writeToClosedStream(String)
}

extension Stream {
Expand Down
10 changes: 9 additions & 1 deletion Sources/SmithyStreams/BufferedStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import struct Foundation.Data
import class Foundation.NSRecursiveLock
import protocol Smithy.Stream
import enum Smithy.StreamError

/// A `Stream` implementation that buffers data in memory.
/// The buffer size depends on the amount of data written and read.
Expand Down Expand Up @@ -207,8 +208,15 @@ public class BufferedStream: Stream, @unchecked Sendable {
/// Writes the specified data to the stream.
/// Then, continues a suspended reader (if any) to read the data.
/// - Parameter data: The data to write.
/// - Throws: `StreamError.writeToClosedStream` if a write is attempted after the stream is closed.
public func write(contentsOf data: Data) throws {
lock.withLockingClosure {
try lock.withLockingClosure {
// Do not allow writing to stream once it closes.
// This ensures length of stream does not change once it reports a length.
// Throw `StreamError.writeToClosedStream` to alert the caller.
guard !isClosed else {
throw StreamError.writeToClosedStream("Attempt to write to closed stream")
}
// append the data to the buffer
// this will increase the in-memory size of the buffer
_buffer.append(data)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//

import XCTest
import ClientRuntime
import enum Smithy.StreamError
import class SmithyStreams.BufferedStream

final class BufferedStreamTests: XCTestCase {
Expand Down Expand Up @@ -208,6 +208,29 @@ final class BufferedStreamTests: XCTestCase {
XCTAssertEqual(testData + additionalData, readData1)
}

func test_write_throwsWriteToClosedStreamErrorWhenStreamIsClosed() throws {
let subject = BufferedStream(data: testData, isClosed: true)
XCTAssertThrowsError(
try subject.write(contentsOf: additionalData),
"No error was thrown when writing to a closed stream",
{ error in
switch error {
case StreamError.writeToClosedStream:
break // expected error, test passes
default:
XCTFail("Error was thrown, but not of expected error type")
}
}
)
}

func test_write_rejectsAdditionalDataWhenStreamIsClosed() throws {
let subject = BufferedStream(data: testData, isClosed: true)
XCTAssertThrowsError(try subject.write(contentsOf: additionalData))
let readData = try subject.read(upToCount: Int.max)
XCTAssertEqual(testData, readData)
}

// MARK: - length

func test_length_returnsNilLengthBeforeStreamCloses() throws {
Expand Down
Loading