Skip to content

Commit fd2afbe

Browse files
committed
Intial Implementation of Stream and NSOutputStream
1 parent ac33719 commit fd2afbe

File tree

3 files changed

+169
-9
lines changed

3 files changed

+169
-9
lines changed

Foundation/NSStream.swift

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
// See http://swift.org/LICENSE.txt for license information
77
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
88
//
9+
#if os(Linux)
10+
import CoreFoundation
11+
#endif
912

1013
extension Stream {
1114
public struct PropertyKey : RawRepresentable, Equatable, Hashable, Comparable {
@@ -66,11 +69,11 @@ public class Stream: NSObject {
6669
}
6770

6871
public func open() {
69-
NSUnimplemented()
72+
streamOpen()
7073
}
7174

7275
public func close() {
73-
NSUnimplemented()
76+
streamClose()
7477
}
7578

7679
public weak var delegate: StreamDelegate?
@@ -95,12 +98,26 @@ public class Stream: NSObject {
9598
}
9699

97100
public var streamStatus: Status {
98-
NSUnimplemented()
101+
return getStreamStatus()
99102
}
100103

101104
/*@NSCopying */public var streamError: NSError? {
102105
NSUnimplemented()
103106
}
107+
108+
internal func streamOpen(){
109+
preconditionFailure("This method must be overriden.")
110+
}
111+
112+
internal func streamClose(){
113+
preconditionFailure("This method must be overriden.")
114+
}
115+
116+
internal func getStreamStatus() -> Status {
117+
// Initial status of stream is 'notOpen'.
118+
// Subsequent status is set in the subclass function.
119+
return Status.notOpen
120+
}
104121
}
105122

106123
// NSInputStream is an abstract class representing the base functionality of a read stream.
@@ -138,35 +155,54 @@ public class InputStream: Stream {
138155
// Subclassers are required to implement these methods.
139156
// Currently this is left as named NSOutputStream due to conflicts with the standard library's text streaming target protocol named OutputStream (which ideally should be renamed)
140157
public class NSOutputStream : Stream {
158+
159+
private var _stream: CFWriteStream!
160+
141161
// writes the bytes from the specified buffer to the stream up to len bytes. Returns the number of bytes actually written.
142162
public func write(_ buffer: UnsafePointer<UInt8>, maxLength len: Int) -> Int {
143-
NSUnimplemented()
163+
if let outputStream = _stream {
164+
return CFWriteStreamWrite(outputStream, buffer, len)
165+
} else {
166+
return -1
167+
}
144168
}
145169

146170
// returns YES if the stream can be written to or if it is impossible to tell without actually doing the write.
147171
public var hasSpaceAvailable: Bool {
148-
NSUnimplemented()
172+
return CFWriteStreamCanAcceptBytes(_stream)
149173
}
150174

151175
public init(toMemory: ()) {
152176
NSUnimplemented()
153177
}
154178

155179
public init(toBuffer buffer: UnsafeMutablePointer<UInt8>, capacity: Int) {
156-
NSUnimplemented()
180+
_stream = CFWriteStreamCreateWithBuffer(kCFAllocatorSystemDefault, buffer, capacity)
157181
}
158-
182+
159183
public init?(url: URL, append shouldAppend: Bool) {
160-
NSUnimplemented()
184+
_stream = CFWriteStreamCreateWithFile(kCFAllocatorSystemDefault, url._cfObject)
161185
}
162186

163187
public convenience init?(toFileAtPath path: String, append shouldAppend: Bool) {
164-
NSUnimplemented()
188+
self.init(url: URL(fileURLWithPath: path), append: true)
165189
}
166190

167191
public class func outputStreamToMemory() -> Self {
168192
NSUnimplemented()
169193
}
194+
195+
internal override func streamOpen() {
196+
CFWriteStreamOpen(_stream)
197+
}
198+
199+
internal override func streamClose() {
200+
CFWriteStreamClose(_stream)
201+
}
202+
203+
internal override func getStreamStatus() -> Stream.Status {
204+
return Stream.Status(rawValue: UInt(CFWriteStreamGetStatus(_stream)))!
205+
}
170206
}
171207

172208
// Discussion of this API is ongoing for its usage of AutoreleasingUnsafeMutablePointer

TestFoundation/TestNSStream.swift

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// This source file is part of the Swift.org open source project
2+
//
3+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
4+
// Licensed under Apache License v2.0 with Runtime Library Exception
5+
//
6+
// See http://swift.org/LICENSE.txt for license information
7+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
8+
//
9+
10+
#if DEPLOYMENT_RUNTIME_OBJC || os(Linux)
11+
import Foundation
12+
import XCTest
13+
#else
14+
import SwiftFoundation
15+
import SwiftXCTest
16+
#endif
17+
18+
class TestNSStream : XCTestCase {
19+
static var allTests: [(String, (TestNSStream) -> () throws -> Void)] {
20+
return [
21+
("test_outputStreamCreationToFile", test_outputStreamCreationToFile),
22+
("test_outputStreamCreationToBuffer", test_outputStreamCreationToBuffer),
23+
("test_outputStreamCreationWithUrl", test_outputStreamCreationWithUrl),
24+
("test_outputStreamHasSpaceAvailable", test_outputStreamHasSpaceAvailable),
25+
("test_ouputStreamWithInvalidPath", test_ouputStreamWithInvalidPath),
26+
]
27+
}
28+
29+
func test_outputStreamCreationToFile() {
30+
let filePath = createTestFile("TestFileOut.txt", _contents: Data(capacity: 256)!)
31+
if filePath != nil {
32+
let outputStream = NSOutputStream(toFileAtPath: filePath!, append: true)
33+
XCTAssertEqual(Stream.Status.notOpen, outputStream!.streamStatus)
34+
var myString = "Hello world!"
35+
let encodedData = [UInt8](myString.utf8)
36+
outputStream?.open()
37+
XCTAssertEqual(Stream.Status.open, outputStream!.streamStatus)
38+
let result: Int? = outputStream?.write(encodedData, maxLength: encodedData.count)
39+
outputStream?.close()
40+
XCTAssertEqual(myString.characters.count, result)
41+
XCTAssertEqual(Stream.Status.closed, outputStream!.streamStatus)
42+
removeTestFile(filePath!)
43+
} else {
44+
XCTFail("Unable to create temp file");
45+
}
46+
}
47+
48+
func test_outputStreamCreationToBuffer() {
49+
var buffer = Array<UInt8>(repeating: 0, count: 12)
50+
var myString = "Hello world!"
51+
let encodedData = [UInt8](myString.utf8)
52+
let outputStream = NSOutputStream(toBuffer: UnsafeMutablePointer<UInt8>(buffer), capacity: 12)
53+
XCTAssertEqual(Stream.Status.notOpen, outputStream.streamStatus)
54+
outputStream.open()
55+
XCTAssertEqual(Stream.Status.open, outputStream.streamStatus)
56+
let result: Int? = outputStream.write(encodedData, maxLength: encodedData.count)
57+
outputStream.close()
58+
XCTAssertEqual(Stream.Status.closed, outputStream.streamStatus)
59+
XCTAssertEqual(myString.characters.count, result)
60+
XCTAssertEqual(NSString(bytes: &buffer, length: buffer.count, encoding: String.Encoding.utf8.rawValue),myString._bridgeToObject())
61+
}
62+
63+
func test_outputStreamCreationWithUrl() {
64+
let filePath = createTestFile("TestFileOut.txt", _contents: Data(capacity: 256)!)
65+
if filePath != nil {
66+
let outputStream = NSOutputStream(url: URL(fileURLWithPath: filePath!), append: true)
67+
XCTAssertEqual(Stream.Status.notOpen, outputStream!.streamStatus)
68+
var myString = "Hello world!"
69+
let encodedData = [UInt8](myString.utf8)
70+
outputStream!.open()
71+
XCTAssertEqual(Stream.Status.open, outputStream!.streamStatus)
72+
let result: Int? = outputStream?.write(encodedData, maxLength: encodedData.count)
73+
outputStream?.close()
74+
XCTAssertEqual(myString.characters.count, result)
75+
XCTAssertEqual(Stream.Status.closed, outputStream!.streamStatus)
76+
removeTestFile(filePath!)
77+
} else {
78+
XCTFail("Unable to create temp file");
79+
}
80+
}
81+
82+
func test_outputStreamHasSpaceAvailable() {
83+
let buffer = Array<UInt8>(repeating: 0, count: 12)
84+
var myString = "Welcome To Hello world !"
85+
let encodedData = [UInt8](myString.utf8)
86+
let outputStream = NSOutputStream(toBuffer: UnsafeMutablePointer<UInt8>(buffer), capacity: 12)
87+
outputStream.open()
88+
XCTAssertTrue(outputStream.hasSpaceAvailable)
89+
_ = outputStream.write(encodedData, maxLength: encodedData.count)
90+
XCTAssertFalse(outputStream.hasSpaceAvailable)
91+
}
92+
93+
func test_ouputStreamWithInvalidPath(){
94+
let outputStream = NSOutputStream(toFileAtPath: "http:///home/sdsfsdfd", append: true)
95+
XCTAssertEqual(Stream.Status.notOpen, outputStream!.streamStatus)
96+
outputStream?.open()
97+
XCTAssertEqual(Stream.Status.error, outputStream!.streamStatus)
98+
}
99+
100+
private func createTestFile(_ path: String, _contents: Data) -> String? {
101+
let tempDir = "/tmp/TestFoundation_Playground_" + NSUUID().UUIDString + "/"
102+
do {
103+
try FileManager.default().createDirectory(atPath: tempDir, withIntermediateDirectories: false, attributes: nil)
104+
if FileManager.default().createFile(atPath: tempDir + "/" + path, contents: _contents,
105+
attributes: nil) {
106+
return tempDir + path
107+
} else {
108+
return nil
109+
}
110+
} catch _ {
111+
return nil
112+
}
113+
}
114+
115+
private func removeTestFile(_ location: String) {
116+
do {
117+
try FileManager.default().removeItem(atPath: location)
118+
} catch _ {
119+
120+
}
121+
}
122+
}
123+

TestFoundation/main.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ XCTMain([
5757
testCase(TestNSRunLoop.allTests),
5858
testCase(TestNSScanner.allTests),
5959
testCase(TestNSSet.allTests),
60+
testCase(TestNSStream.allTests),
6061
testCase(TestNSString.allTests),
6162
// testCase(TestNSThread.allTests),
6263
testCase(TestNSTask.allTests),

0 commit comments

Comments
 (0)