Skip to content

Commit 84c648e

Browse files
committed
Implementing (initial) of Stream and InputStream.
Add TestNSStream file to Xcode project.
1 parent ac33719 commit 84c648e

File tree

5 files changed

+198
-10
lines changed

5 files changed

+198
-10
lines changed

CoreFoundation/Stream.subproj/CFStream.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ const CFStringRef kCFStreamPropertyDataWritten;
7878
CF_EXPORT
7979
CFReadStreamRef CFReadStreamCreateWithBytesNoCopy(CFAllocatorRef alloc, const UInt8 *bytes, CFIndex length, CFAllocatorRef bytesDeallocator);
8080

81+
CF_EXPORT CFReadStreamRef CFReadStreamCreateWithData(CFAllocatorRef alloc, CFDataRef data);
82+
8183
/* The stream writes into the buffer given; when bufferCapacity is exhausted, the stream is exhausted (status becomes kCFStreamStatusAtEnd) */
8284
CF_EXPORT
8385
CFWriteStreamRef CFWriteStreamCreateWithBuffer(CFAllocatorRef alloc, UInt8 *buffer, CFIndex bufferCapacity);

Foundation.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
0383A1751D2E558A0052E5D1 /* TestNSStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0383A1741D2E558A0052E5D1 /* TestNSStream.swift */; };
1011
294E3C1D1CC5E19300E4F44C /* TestNSAttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294E3C1C1CC5E19300E4F44C /* TestNSAttributedString.swift */; };
1112
2EBE67A51C77BF0E006583D5 /* TestNSDateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBE67A31C77BF05006583D5 /* TestNSDateFormatter.swift */; };
1213
528776141BF2629700CB0090 /* FoundationErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522C253A1BF16E1600804FC6 /* FoundationErrors.swift */; };
@@ -418,6 +419,7 @@
418419
/* End PBXCopyFilesBuildPhase section */
419420

420421
/* Begin PBXFileReference section */
422+
0383A1741D2E558A0052E5D1 /* TestNSStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSStream.swift; sourceTree = "<group>"; };
421423
22B9C1E01C165D7A00DECFF9 /* TestNSDate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSDate.swift; sourceTree = "<group>"; };
422424
294E3C1C1CC5E19300E4F44C /* TestNSAttributedString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSAttributedString.swift; sourceTree = "<group>"; };
423425
2EBE67A31C77BF05006583D5 /* TestNSDateFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSDateFormatter.swift; sourceTree = "<group>"; };
@@ -1273,6 +1275,7 @@
12731275
5B6F17951C48631C00935030 /* TestNSXMLDocument.swift */,
12741276
5B40F9F11C125187000E72E3 /* TestNSXMLParser.swift */,
12751277
5B6F17961C48631C00935030 /* TestUtils.swift */,
1278+
0383A1741D2E558A0052E5D1 /* TestNSStream.swift */,
12761279
);
12771280
name = Tests;
12781281
sourceTree = "<group>";
@@ -2082,6 +2085,7 @@
20822085
5B13B34E1C582D4C00651CE2 /* TestNSXMLDocument.swift in Sources */,
20832086
5B13B32B1C582D4C00651CE2 /* TestNSData.swift in Sources */,
20842087
5B13B34C1C582D4C00651CE2 /* TestNSURLResponse.swift in Sources */,
2088+
0383A1751D2E558A0052E5D1 /* TestNSStream.swift in Sources */,
20852089
5B13B3481C582D4C00651CE2 /* TestNSTimer.swift in Sources */,
20862090
5B13B32D1C582D4C00651CE2 /* TestNSDictionary.swift in Sources */,
20872091
5B13B3261C582D4C00651CE2 /* TestNSAffineTransform.swift in Sources */,

Foundation/NSStream.swift

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
88
//
99

10+
#if os(Linux)
11+
import CoreFoundation
12+
#endif
13+
1014
extension Stream {
1115
public struct PropertyKey : RawRepresentable, Equatable, Hashable, Comparable {
1216
public private(set) var rawValue: String
@@ -60,17 +64,17 @@ public func <(lhs: Stream.PropertyKey, rhs: Stream.PropertyKey) -> Bool {
6064
// NSStream is an abstract class encapsulating the common API to NSInputStream and NSOutputStream.
6165
// Subclassers of NSInputStream and NSOutputStream must also implement these methods.
6266
public class Stream: NSObject {
63-
67+
6468
public override init() {
65-
69+
6670
}
6771

6872
public func open() {
69-
NSUnimplemented()
73+
streamOpen()
7074
}
7175

7276
public func close() {
73-
NSUnimplemented()
77+
streamClose()
7478
}
7579

7680
public weak var delegate: StreamDelegate?
@@ -95,20 +99,37 @@ public class Stream: NSObject {
9599
}
96100

97101
public var streamStatus: Status {
98-
NSUnimplemented()
102+
return getStreamStatus()
99103
}
100104

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

106124
// NSInputStream is an abstract class representing the base functionality of a read stream.
107125
// Subclassers are required to implement these methods.
108126
public class InputStream: Stream {
127+
128+
private var _stream: CFReadStream!
129+
109130
// reads up to length bytes into the supplied buffer, which must be at least of size len. Returns the actual number of bytes read.
110131
public func read(_ buffer: UnsafeMutablePointer<UInt8>, maxLength len: Int) -> Int {
111-
NSUnimplemented()
132+
return CFReadStreamRead(_stream, buffer, CFIndex(len._bridgeToObject()))
112133
}
113134

114135
// returns in O(1) a pointer to the buffer in 'buffer' and by reference in 'len' how many bytes are available. This buffer is only valid until the next stream operation. Subclassers may return NO for this if it is not appropriate for the stream type. This may return NO if the buffer is not available.
@@ -118,19 +139,34 @@ public class InputStream: Stream {
118139

119140
// returns YES if the stream has bytes available or if it impossible to tell without actually doing the read.
120141
public var hasBytesAvailable: Bool {
121-
NSUnimplemented()
142+
return CFReadStreamHasBytesAvailable(_stream)
122143
}
123144

124145
public init(data: Data) {
125-
NSUnimplemented()
146+
let nsData = data._bridgeToObjectiveC()
147+
let _data: CFData = CFDataCreate(kCFAllocatorDefault,
148+
UnsafePointer<UInt8>(nsData.bytes), nsData.length)
149+
_stream = CFReadStreamCreateWithData(kCFAllocatorSystemDefault, _data)
126150
}
127151

128152
public init?(url: URL) {
129-
NSUnimplemented()
153+
_stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url._cfObject)
130154
}
131155

132156
public convenience init?(fileAtPath path: String) {
133-
NSUnimplemented()
157+
self.init(url: URL(fileURLWithPath: path))
158+
}
159+
160+
internal override func streamOpen() {
161+
CFReadStreamOpen(_stream)
162+
}
163+
164+
internal override func streamClose() {
165+
CFReadStreamClose(_stream)
166+
}
167+
168+
internal override func getStreamStatus() -> Stream.Status {
169+
return Stream.Status(rawValue: UInt(CFReadStreamGetStatus(_stream)))!
134170
}
135171
}
136172

TestFoundation/TestNSStream.swift

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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_InputStreamWithData", test_InputStreamWithData),
22+
("test_InputStreamWithUrl", test_InputStreamWithUrl),
23+
("test_InputStreamWithFile", test_InputStreamWithFile),
24+
("test_InputStreamHasBytesAvailable", test_InputStreamHasBytesAvailable),
25+
("test_InputStreamInvalidPath", test_InputStreamInvalidPath),
26+
]
27+
}
28+
29+
func test_InputStreamWithData(){
30+
let message: NSString = "Hello, playground"
31+
let messageData: Data = message.data(using: String.Encoding.utf8.rawValue)!
32+
let dataStream: InputStream = InputStream(data: messageData)
33+
XCTAssertEqual(Stream.Status.notOpen, dataStream.streamStatus)
34+
dataStream.open()
35+
XCTAssertEqual(Stream.Status.open, dataStream.streamStatus)
36+
var buffer = [UInt8](repeating: 0, count: 20)
37+
if dataStream.hasBytesAvailable {
38+
let result: Int = dataStream.read(&buffer, maxLength: buffer.count)
39+
dataStream.close()
40+
XCTAssertEqual(Stream.Status.closed, dataStream.streamStatus)
41+
if(result > 0){
42+
let output = NSString(bytes: &buffer, length: buffer.count, encoding: String.Encoding.utf8.rawValue)
43+
XCTAssertEqual(message, output!)
44+
}
45+
}
46+
}
47+
48+
func test_InputStreamWithUrl() {
49+
let message: NSString = "Hello, playground"
50+
let messageData: Data = message.data(using: String.Encoding.utf8.rawValue)!
51+
//Initialiser with url
52+
let testFile = createTestFile("testFile_in.txt", _contents: messageData)
53+
if testFile != nil {
54+
let url = URL(fileURLWithPath: testFile!)
55+
let urlStream: InputStream = InputStream(url: url)!
56+
XCTAssertEqual(Stream.Status.notOpen, urlStream.streamStatus)
57+
urlStream.open()
58+
XCTAssertEqual(Stream.Status.open, urlStream.streamStatus)
59+
var buffer = [UInt8](repeating: 0, count: 20)
60+
if urlStream.hasBytesAvailable {
61+
let result :Int = urlStream.read(&buffer, maxLength: buffer.count)
62+
urlStream.close()
63+
XCTAssertEqual(Stream.Status.closed, urlStream.streamStatus)
64+
XCTAssertEqual(messageData.count, result)
65+
if(result > 0) {
66+
let output = NSString(bytes: &buffer, length: buffer.count, encoding: String.Encoding.utf8.rawValue)
67+
XCTAssertEqual(message, output!)
68+
}
69+
}
70+
removeTestFile(testFile!)
71+
} else {
72+
XCTFail("Unable to create temp file")
73+
}
74+
}
75+
76+
func test_InputStreamWithFile() {
77+
let message: NSString = "Hello, playground"
78+
let messageData: Data = message.data(using: String.Encoding.utf8.rawValue)!
79+
//Initialiser with file
80+
let testFile = createTestFile("testFile_in.txt", _contents: messageData)
81+
if testFile != nil {
82+
let fileStream: InputStream = InputStream(fileAtPath: testFile!)!
83+
XCTAssertEqual(Stream.Status.notOpen, fileStream.streamStatus)
84+
fileStream.open()
85+
XCTAssertEqual(Stream.Status.open, fileStream.streamStatus)
86+
var buffer = [UInt8](repeating: 0, count: 20)
87+
if fileStream.hasBytesAvailable {
88+
let result: Int = fileStream.read(&buffer, maxLength: buffer.count)
89+
fileStream.close()
90+
XCTAssertEqual(Stream.Status.closed, fileStream.streamStatus)
91+
XCTAssertEqual(messageData.count, result)
92+
if(result > 0){
93+
let output = NSString(bytes: &buffer, length: buffer.count, encoding: String.Encoding.utf8.rawValue)
94+
XCTAssertEqual(message, output!)
95+
}
96+
}
97+
removeTestFile(testFile!)
98+
} else {
99+
XCTFail("Unable to create temp file")
100+
}
101+
}
102+
103+
func test_InputStreamHasBytesAvailable() {
104+
let message: NSString = "Hello, playground"
105+
let messageData: Data = message.data(using: String.Encoding.utf8.rawValue)!
106+
let stream: InputStream = InputStream(data: messageData)
107+
var buffer = [UInt8](repeating: 0, count: 20)
108+
stream.open()
109+
XCTAssertTrue(stream.hasBytesAvailable)
110+
_ = stream.read(&buffer, maxLength: buffer.count)
111+
XCTAssertFalse(stream.hasBytesAvailable)
112+
}
113+
114+
func test_InputStreamInvalidPath() {
115+
let fileStream: InputStream = InputStream(fileAtPath: "/tmp/file.txt")!
116+
XCTAssertEqual(Stream.Status.notOpen, fileStream.streamStatus)
117+
fileStream.open()
118+
XCTAssertEqual(Stream.Status.error, fileStream.streamStatus)
119+
}
120+
121+
private func createTestFile(_ path: String,_contents: Data) -> String? {
122+
let tempDir = "/tmp/TestFoundation_Playground_" + NSUUID().UUIDString + "/"
123+
do {
124+
try FileManager.default().createDirectory(atPath: tempDir, withIntermediateDirectories: false, attributes: nil)
125+
if FileManager.default().createFile(atPath: tempDir + "/" + path, contents: _contents, attributes: nil) {
126+
return tempDir + path
127+
} else {
128+
return nil
129+
}
130+
} catch _ {
131+
return nil
132+
}
133+
134+
}
135+
136+
private func removeTestFile(_ location: String) {
137+
do {
138+
try FileManager.default().removeItem(atPath: location)
139+
} catch _ {
140+
141+
}
142+
}
143+
}
144+
145+

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)