commit
03c2d8bce3
|
@ -1 +1 @@
|
|||
3.0
|
||||
3.1
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
language: objective-c
|
||||
osx_image: xcode8
|
||||
osx_image: xcode8.3
|
||||
env:
|
||||
- LC_CTYPE=en_US.UTF-8
|
||||
git:
|
||||
|
|
|
@ -15,6 +15,13 @@
|
|||
0E47EEC21DBCDB1800EBF783 /* CSV+iterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E47EEC01DBCDB1800EBF783 /* CSV+iterator.swift */; };
|
||||
0E47EEC31DBCDB1800EBF783 /* CSV+iterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E47EEC01DBCDB1800EBF783 /* CSV+iterator.swift */; };
|
||||
0E47EEC41DBCDB1800EBF783 /* CSV+iterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E47EEC01DBCDB1800EBF783 /* CSV+iterator.swift */; };
|
||||
0E54021B1ED9DDF40019C3ED /* CSVWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E54021A1ED9DDF40019C3ED /* CSVWriterTests.swift */; };
|
||||
0E54021C1ED9DDF40019C3ED /* CSVWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E54021A1ED9DDF40019C3ED /* CSVWriterTests.swift */; };
|
||||
0E54021D1ED9DDF40019C3ED /* CSVWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E54021A1ED9DDF40019C3ED /* CSVWriterTests.swift */; };
|
||||
0E5402221EDA82220019C3ED /* CSVWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E54021E1EDA81E80019C3ED /* CSVWriter.swift */; };
|
||||
0E5402231EDA82220019C3ED /* CSVWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E54021E1EDA81E80019C3ED /* CSVWriter.swift */; };
|
||||
0E5402241EDA82220019C3ED /* CSVWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E54021E1EDA81E80019C3ED /* CSVWriter.swift */; };
|
||||
0E5402251EDA82230019C3ED /* CSVWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E54021E1EDA81E80019C3ED /* CSVWriter.swift */; };
|
||||
0E7E8C8C1D0BC7BB0057A1C1 /* CSV.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E7E8C811D0BC7BB0057A1C1 /* CSV.framework */; };
|
||||
0E7E8CA11D0BC7F10057A1C1 /* CSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */; };
|
||||
0E7E8CA21D0BC7F10057A1C1 /* CSVError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */; };
|
||||
|
@ -90,6 +97,8 @@
|
|||
/* Begin PBXFileReference section */
|
||||
0E0F160D1D197DB800C92580 /* Endian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Endian.swift; sourceTree = "<group>"; };
|
||||
0E47EEC01DBCDB1800EBF783 /* CSV+iterator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CSV+iterator.swift"; sourceTree = "<group>"; };
|
||||
0E54021A1ED9DDF40019C3ED /* CSVWriterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSVWriterTests.swift; sourceTree = "<group>"; };
|
||||
0E54021E1EDA81E80019C3ED /* CSVWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSVWriter.swift; sourceTree = "<group>"; };
|
||||
0E7E8C811D0BC7BB0057A1C1 /* CSV.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CSV.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0E7E8C8B1D0BC7BB0057A1C1 /* CSVTests-iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "CSVTests-iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSV.swift; sourceTree = "<group>"; };
|
||||
|
@ -203,6 +212,7 @@
|
|||
0EDF8EAE1DDB6D620068056A /* CSVConfiguration.swift */,
|
||||
0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */,
|
||||
0E7E8C9F1D0BC7F10057A1C1 /* CSVVersion.h */,
|
||||
0E54021E1EDA81E80019C3ED /* CSVWriter.swift */,
|
||||
0E0F160D1D197DB800C92580 /* Endian.swift */,
|
||||
0E7E8CAC1D0BC8610057A1C1 /* Info.plist */,
|
||||
0EA2AB801D183BA9003EC967 /* UnicodeIterator.swift */,
|
||||
|
@ -223,6 +233,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
0EDF8ECD1DDB73370068056A /* CSVTests.swift */,
|
||||
0E54021A1ED9DDF40019C3ED /* CSVWriterTests.swift */,
|
||||
0EDF8ECE1DDB73370068056A /* LineBreakTests.swift */,
|
||||
0EDF8ECF1DDB73370068056A /* ReadmeTests.swift */,
|
||||
0EDF8ED01DDB73370068056A /* TrimFieldsTests.swift */,
|
||||
|
@ -536,6 +547,7 @@
|
|||
0E9317D51D0DB2F200AC20A0 /* CSV+init.swift in Sources */,
|
||||
0EA2AB821D183BA9003EC967 /* UnicodeIterator.swift in Sources */,
|
||||
0E47EEC21DBCDB1800EBF783 /* CSV+iterator.swift in Sources */,
|
||||
0E5402241EDA82220019C3ED /* CSVWriter.swift in Sources */,
|
||||
0E7E8CA11D0BC7F10057A1C1 /* CSV.swift in Sources */,
|
||||
0E0F160F1D197DB800C92580 /* Endian.swift in Sources */,
|
||||
0EDF8EB01DDB6DAC0068056A /* CSVConfiguration.swift in Sources */,
|
||||
|
@ -553,6 +565,7 @@
|
|||
0EDF8EDF1DDB73520068056A /* TrimFieldsTests.swift in Sources */,
|
||||
0EDF8EE01DDB73520068056A /* UnicodeTests.swift in Sources */,
|
||||
0EDF8EDD1DDB73520068056A /* LineBreakTests.swift in Sources */,
|
||||
0E54021C1ED9DDF40019C3ED /* CSVWriterTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -563,6 +576,7 @@
|
|||
0E9317D71D0DB2F200AC20A0 /* CSV+init.swift in Sources */,
|
||||
0EA2AB841D183BA9003EC967 /* UnicodeIterator.swift in Sources */,
|
||||
0E47EEC41DBCDB1800EBF783 /* CSV+iterator.swift in Sources */,
|
||||
0E5402221EDA82220019C3ED /* CSVWriter.swift in Sources */,
|
||||
0E7E8CBE1D0BC9D70057A1C1 /* CSV.swift in Sources */,
|
||||
0E0F16111D197DB800C92580 /* Endian.swift in Sources */,
|
||||
0EDF8EB21DDB6DAD0068056A /* CSVConfiguration.swift in Sources */,
|
||||
|
@ -578,6 +592,7 @@
|
|||
0E9317D41D0DB2F200AC20A0 /* CSV+init.swift in Sources */,
|
||||
0EA2AB811D183BA9003EC967 /* UnicodeIterator.swift in Sources */,
|
||||
0E47EEC11DBCDB1800EBF783 /* CSV+iterator.swift in Sources */,
|
||||
0E5402251EDA82230019C3ED /* CSVWriter.swift in Sources */,
|
||||
0E7E8CE01D0BCA8E0057A1C1 /* CSV.swift in Sources */,
|
||||
0E0F160E1D197DB800C92580 /* Endian.swift in Sources */,
|
||||
0EDF8EAF1DDB6D620068056A /* CSVConfiguration.swift in Sources */,
|
||||
|
@ -595,6 +610,7 @@
|
|||
0EDF8EDA1DDB73520068056A /* TrimFieldsTests.swift in Sources */,
|
||||
0EDF8EDB1DDB73520068056A /* UnicodeTests.swift in Sources */,
|
||||
0EDF8ED81DDB73520068056A /* LineBreakTests.swift in Sources */,
|
||||
0E54021B1ED9DDF40019C3ED /* CSVWriterTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -605,6 +621,7 @@
|
|||
0E9317D61D0DB2F200AC20A0 /* CSV+init.swift in Sources */,
|
||||
0EA2AB831D183BA9003EC967 /* UnicodeIterator.swift in Sources */,
|
||||
0E47EEC31DBCDB1800EBF783 /* CSV+iterator.swift in Sources */,
|
||||
0E5402231EDA82220019C3ED /* CSVWriter.swift in Sources */,
|
||||
0E7E8D001D0BCDCF0057A1C1 /* CSV.swift in Sources */,
|
||||
0E0F16101D197DB800C92580 /* Endian.swift in Sources */,
|
||||
0EDF8EB11DDB6DAC0068056A /* CSVConfiguration.swift in Sources */,
|
||||
|
@ -622,6 +639,7 @@
|
|||
0EDF8EE41DDB73530068056A /* TrimFieldsTests.swift in Sources */,
|
||||
0EDF8EE51DDB73530068056A /* UnicodeTests.swift in Sources */,
|
||||
0EDF8EE21DDB73530068056A /* LineBreakTests.swift in Sources */,
|
||||
0E54021D1ED9DDF40019C3ED /* CSVWriterTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -62,7 +62,7 @@ internal class BinaryReader {
|
|||
stream.open()
|
||||
}
|
||||
if stream.streamStatus != .open {
|
||||
throw CSVError.cannotOpenFile
|
||||
throw CSVError.cannotOpenStream
|
||||
}
|
||||
|
||||
let readCount = stream.read(tempBuffer, maxLength: tempBufferSize)
|
||||
|
@ -93,7 +93,7 @@ internal class BinaryReader {
|
|||
|
||||
private func readStream(_ buffer: UnsafeMutablePointer<UInt8>, maxLength: Int) throws -> Int {
|
||||
if stream.streamStatus != .open {
|
||||
throw CSVError.cannotReadFile
|
||||
throw CSVError.cannotReadStream
|
||||
}
|
||||
|
||||
var i = 0
|
||||
|
@ -115,7 +115,7 @@ internal class BinaryReader {
|
|||
throw CSVError.streamErrorHasOccurred(error: stream.streamError!)
|
||||
}
|
||||
if length != bufferSize {
|
||||
throw CSVError.cannotReadFile
|
||||
throw CSVError.cannotReadStream
|
||||
}
|
||||
return buffer[0]
|
||||
}
|
||||
|
|
|
@ -8,9 +8,12 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
private let LF: UnicodeScalar = "\n"
|
||||
private let CR: UnicodeScalar = "\r"
|
||||
private let DQUOTE: UnicodeScalar = "\""
|
||||
internal let LF: UnicodeScalar = "\n"
|
||||
internal let CR: UnicodeScalar = "\r"
|
||||
internal let DQUOTE: UnicodeScalar = "\""
|
||||
|
||||
internal let DQUOTE_STR: String = "\""
|
||||
internal let DQUOTE2_STR: String = "\"\""
|
||||
|
||||
/// No overview available.
|
||||
public class CSV {
|
||||
|
|
|
@ -10,9 +10,11 @@
|
|||
public enum CSVError: Error {
|
||||
|
||||
/// No overview available.
|
||||
case cannotOpenFile
|
||||
case cannotOpenStream
|
||||
/// No overview available.
|
||||
case cannotReadFile
|
||||
case cannotReadStream
|
||||
/// No overview available.
|
||||
case cannotWriteStream
|
||||
/// No overview available.
|
||||
case streamErrorHasOccurred(error: Error)
|
||||
/// No overview available.
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
//
|
||||
// CSVWriter.swift
|
||||
// CSV
|
||||
//
|
||||
// Created by Yasuhiro Hatta on 2017/05/28.
|
||||
// Copyright © 2017 yaslab. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class CSVWriter {
|
||||
|
||||
public struct Configuration {
|
||||
|
||||
public var delimiter: String
|
||||
public var newline: String
|
||||
|
||||
public init(delimiter: String = String(defaultDelimiter), newline: String = String(LF)) {
|
||||
self.delimiter = delimiter
|
||||
self.newline = newline
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public let stream: OutputStream
|
||||
public let configuration: Configuration
|
||||
fileprivate let writeScalar: ((UnicodeScalar) throws -> Void)
|
||||
|
||||
fileprivate var isFirstRecord: Bool = true
|
||||
fileprivate var isFirstField: Bool = true
|
||||
|
||||
fileprivate init(
|
||||
stream: OutputStream,
|
||||
configuration: Configuration,
|
||||
writeScalar: @escaping ((UnicodeScalar) throws -> Void)) throws {
|
||||
|
||||
self.stream = stream
|
||||
self.configuration = configuration
|
||||
self.writeScalar = writeScalar
|
||||
|
||||
if stream.streamStatus == .notOpen {
|
||||
stream.open()
|
||||
}
|
||||
if stream.streamStatus != .open {
|
||||
throw CSVError.cannotOpenStream
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension CSVWriter {
|
||||
|
||||
public convenience init(
|
||||
stream: OutputStream,
|
||||
configuration: Configuration = Configuration()) throws {
|
||||
|
||||
try self.init(stream: stream, codecType: UTF8.self, configuration: configuration)
|
||||
}
|
||||
|
||||
public convenience init<T: UnicodeCodec>(
|
||||
stream: OutputStream,
|
||||
codecType: T.Type,
|
||||
configuration: Configuration = Configuration()
|
||||
) throws where T.CodeUnit == UInt8 {
|
||||
|
||||
try self.init(stream: stream, configuration: configuration) { (scalar: UnicodeScalar) throws in
|
||||
var error: CSVError? = nil
|
||||
codecType.encode(scalar) { (code: UInt8) in
|
||||
var code = code
|
||||
let count = stream.write(&code, maxLength: 1)
|
||||
if count != 1 {
|
||||
error = CSVError.cannotWriteStream
|
||||
}
|
||||
}
|
||||
if let error = error {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public convenience init<T: UnicodeCodec>(
|
||||
stream: OutputStream,
|
||||
codecType: T.Type,
|
||||
endian: Endian = .big,
|
||||
configuration: Configuration = Configuration()
|
||||
) throws where T.CodeUnit == UInt16 {
|
||||
|
||||
try self.init(stream: stream, configuration: configuration) { (scalar: UnicodeScalar) throws in
|
||||
var error: CSVError? = nil
|
||||
codecType.encode(scalar) { (code: UInt16) in
|
||||
var code = (endian == .big) ? code.bigEndian : code.littleEndian
|
||||
withUnsafeBytes(of: &code) { (buffer) -> Void in
|
||||
let count = stream.write(buffer.baseAddress!.assumingMemoryBound(to: UInt8.self), maxLength: buffer.count)
|
||||
if count != buffer.count {
|
||||
error = CSVError.cannotWriteStream
|
||||
}
|
||||
}
|
||||
}
|
||||
if let error = error {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public convenience init<T: UnicodeCodec>(
|
||||
stream: OutputStream,
|
||||
codecType: T.Type,
|
||||
endian: Endian = .big,
|
||||
configuration: Configuration = Configuration()
|
||||
) throws where T.CodeUnit == UInt32 {
|
||||
|
||||
try self.init(stream: stream, configuration: configuration) { (scalar: UnicodeScalar) throws in
|
||||
var error: CSVError? = nil
|
||||
codecType.encode(scalar) { (code: UInt32) in
|
||||
var code = (endian == .big) ? code.bigEndian : code.littleEndian
|
||||
withUnsafeBytes(of: &code) { (buffer) -> Void in
|
||||
let count = stream.write(buffer.baseAddress!.assumingMemoryBound(to: UInt8.self), maxLength: buffer.count)
|
||||
if count != buffer.count {
|
||||
error = CSVError.cannotWriteStream
|
||||
}
|
||||
}
|
||||
}
|
||||
if let error = error {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension CSVWriter {
|
||||
|
||||
public func beginNewRecord() {
|
||||
isFirstField = true
|
||||
}
|
||||
|
||||
public func write(field value: String, quoted: Bool = false) throws {
|
||||
if isFirstRecord {
|
||||
isFirstRecord = false
|
||||
} else {
|
||||
if isFirstField {
|
||||
try configuration.newline.unicodeScalars.forEach(writeScalar)
|
||||
}
|
||||
}
|
||||
|
||||
if isFirstField {
|
||||
isFirstField = false
|
||||
} else {
|
||||
try configuration.delimiter.unicodeScalars.forEach(writeScalar)
|
||||
}
|
||||
|
||||
var value = value
|
||||
|
||||
if quoted {
|
||||
value = value.replacingOccurrences(of: DQUOTE_STR, with: DQUOTE2_STR)
|
||||
try writeScalar(DQUOTE)
|
||||
}
|
||||
|
||||
try value.unicodeScalars.forEach(writeScalar)
|
||||
|
||||
if quoted {
|
||||
try writeScalar(DQUOTE)
|
||||
}
|
||||
}
|
||||
|
||||
public func write(record values: [String], quotedAtIndex: ((Int) -> Bool) = { _ in false }) throws {
|
||||
beginNewRecord()
|
||||
for (i, value) in values.enumerated() {
|
||||
try write(field: value, quoted: quotedAtIndex(i))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
//
|
||||
// CSVWriterTests.swift
|
||||
// CSV
|
||||
//
|
||||
// Created by Yasuhiro Hatta on 2017/05/28.
|
||||
// Copyright © 2017年 yaslab. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
import CSV
|
||||
|
||||
extension OutputStream {
|
||||
|
||||
var data: Data? {
|
||||
guard let nsData = property(forKey: .dataWrittenToMemoryStreamKey) as? NSData else {
|
||||
return nil
|
||||
}
|
||||
return Data(referencing: nsData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CSVWriterTests: XCTestCase {
|
||||
|
||||
static let allTests = [
|
||||
("testSingleFieldSingleRecord", testSingleFieldSingleRecord),
|
||||
("testSingleFieldMultipleRecord", testSingleFieldMultipleRecord),
|
||||
("testMultipleFieldSingleRecord", testMultipleFieldSingleRecord),
|
||||
("testMultipleFieldMultipleRecord", testMultipleFieldMultipleRecord),
|
||||
("testQuoted", testQuoted),
|
||||
("testQuotedNewline", testQuotedNewline),
|
||||
("testEscapeQuote", testEscapeQuote),
|
||||
("testDelimiter", testDelimiter),
|
||||
("testNewline", testNewline),
|
||||
("testUTF16BE", testUTF16BE),
|
||||
("testUTF16LE", testUTF16LE),
|
||||
("testUTF32BE", testUTF32BE),
|
||||
("testUTF32LE", testUTF32LE)
|
||||
]
|
||||
|
||||
let str = "TEST-test-1234-😄😆👨👩👧👦"
|
||||
|
||||
/// xxxx
|
||||
func testSingleFieldSingleRecord() {
|
||||
let stream = OutputStream(toMemory: ())
|
||||
stream.open()
|
||||
|
||||
let csv = try! CSVWriter(stream: stream)
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str)
|
||||
|
||||
stream.close()
|
||||
let data = stream.data!
|
||||
let csvStr = String(data: data, encoding: .utf8)!
|
||||
|
||||
XCTAssertEqual(csvStr, str)
|
||||
}
|
||||
|
||||
/// xxxx
|
||||
/// xxxx
|
||||
func testSingleFieldMultipleRecord() {
|
||||
let stream = OutputStream(toMemory: ())
|
||||
stream.open()
|
||||
|
||||
let csv = try! CSVWriter(stream: stream)
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str + "-1")
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str + "-2")
|
||||
|
||||
stream.close()
|
||||
let data = stream.data!
|
||||
let csvStr = String(data: data, encoding: .utf8)!
|
||||
|
||||
XCTAssertEqual(csvStr, "\(str)-1\n\(str)-2")
|
||||
}
|
||||
|
||||
/// xxxx,xxxx
|
||||
func testMultipleFieldSingleRecord() {
|
||||
let stream = OutputStream(toMemory: ())
|
||||
stream.open()
|
||||
|
||||
let csv = try! CSVWriter(stream: stream)
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str + "-1")
|
||||
try! csv.write(field: str + "-2")
|
||||
|
||||
stream.close()
|
||||
let data = stream.data!
|
||||
let csvStr = String(data: data, encoding: .utf8)!
|
||||
|
||||
XCTAssertEqual(csvStr, "\(str)-1,\(str)-2")
|
||||
}
|
||||
|
||||
/// xxxx,xxxx
|
||||
/// xxxx,xxxx
|
||||
func testMultipleFieldMultipleRecord() {
|
||||
let stream = OutputStream(toMemory: ())
|
||||
stream.open()
|
||||
|
||||
let csv = try! CSVWriter(stream: stream)
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str + "-1-1")
|
||||
try! csv.write(field: str + "-1-2")
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str + "-2-1")
|
||||
try! csv.write(field: str + "-2-2")
|
||||
|
||||
stream.close()
|
||||
let data = stream.data!
|
||||
let csvStr = String(data: data, encoding: .utf8)!
|
||||
|
||||
XCTAssertEqual(csvStr, "\(str)-1-1,\(str)-1-2\n\(str)-2-1,\(str)-2-2")
|
||||
}
|
||||
|
||||
/// "xxxx",xxxx
|
||||
func testQuoted() {
|
||||
let stream = OutputStream(toMemory: ())
|
||||
stream.open()
|
||||
|
||||
let csv = try! CSVWriter(stream: stream)
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str + "-1", quoted: true)
|
||||
try! csv.write(field: str + "-2") // quoted: false
|
||||
|
||||
stream.close()
|
||||
let data = stream.data!
|
||||
let csvStr = String(data: data, encoding: .utf8)!
|
||||
|
||||
XCTAssertEqual(csvStr, "\"\(str)-1\",\(str)-2")
|
||||
}
|
||||
|
||||
/// xxxx,"xx\nxx"
|
||||
func testQuotedNewline() {
|
||||
let stream = OutputStream(toMemory: ())
|
||||
stream.open()
|
||||
|
||||
let csv = try! CSVWriter(stream: stream)
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str + "-1") // quoted: false
|
||||
try! csv.write(field: str + "-\n-2", quoted: true)
|
||||
|
||||
stream.close()
|
||||
let data = stream.data!
|
||||
let csvStr = String(data: data, encoding: .utf8)!
|
||||
|
||||
XCTAssertEqual(csvStr, "\(str)-1,\"\(str)-\n-2\"")
|
||||
}
|
||||
|
||||
/// xxxx,"xx""xx"
|
||||
func testEscapeQuote() {
|
||||
let stream = OutputStream(toMemory: ())
|
||||
stream.open()
|
||||
|
||||
let csv = try! CSVWriter(stream: stream)
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str + "-1") // quoted: false
|
||||
try! csv.write(field: str + "-\"-2", quoted: true)
|
||||
|
||||
stream.close()
|
||||
let data = stream.data!
|
||||
let csvStr = String(data: data, encoding: .utf8)!
|
||||
|
||||
XCTAssertEqual(csvStr, "\(str)-1,\"\(str)-\"\"-2\"")
|
||||
}
|
||||
|
||||
/// Test delimiter: "\t"
|
||||
func testDelimiter() {
|
||||
let stream = OutputStream(toMemory: ())
|
||||
stream.open()
|
||||
|
||||
let config = CSVWriter.Configuration(delimiter: "\t")
|
||||
let csv = try! CSVWriter.init(stream: stream, configuration: config)
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str + "-1")
|
||||
try! csv.write(field: str + "-2")
|
||||
|
||||
stream.close()
|
||||
let data = stream.data!
|
||||
let csvStr = String(data: data, encoding: .utf8)!
|
||||
|
||||
XCTAssertEqual(csvStr, "\(str)-1\t\(str)-2")
|
||||
}
|
||||
|
||||
/// Test newline: "\r\n"
|
||||
func testNewline() {
|
||||
let stream = OutputStream(toMemory: ())
|
||||
stream.open()
|
||||
|
||||
let config = CSVWriter.Configuration(newline: "\r\n")
|
||||
let csv = try! CSVWriter.init(stream: stream, configuration: config)
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str + "-1")
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str + "-2")
|
||||
|
||||
stream.close()
|
||||
let data = stream.data!
|
||||
let csvStr = String(data: data, encoding: .utf8)!
|
||||
|
||||
XCTAssertEqual(csvStr, "\(str)-1\r\n\(str)-2")
|
||||
}
|
||||
|
||||
/// UTF16 Big Endian
|
||||
func testUTF16BE() {
|
||||
let stream = OutputStream(toMemory: ())
|
||||
stream.open()
|
||||
|
||||
let csv = try! CSVWriter(stream: stream, codecType: UTF16.self, endian: .big)
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str)
|
||||
|
||||
stream.close()
|
||||
let data = stream.data!
|
||||
let csvStr = String(data: data, encoding: .utf16BigEndian)!
|
||||
|
||||
XCTAssertEqual(csvStr, str)
|
||||
}
|
||||
|
||||
/// UTF16 Little Endian
|
||||
func testUTF16LE() {
|
||||
let stream = OutputStream(toMemory: ())
|
||||
stream.open()
|
||||
|
||||
let csv = try! CSVWriter(stream: stream, codecType: UTF16.self, endian: .little)
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str)
|
||||
|
||||
stream.close()
|
||||
let data = stream.data!
|
||||
let csvStr = String(data: data, encoding: .utf16LittleEndian)!
|
||||
|
||||
XCTAssertEqual(csvStr, str)
|
||||
}
|
||||
|
||||
/// UTF32 Big Endian
|
||||
func testUTF32BE() {
|
||||
let stream = OutputStream(toMemory: ())
|
||||
stream.open()
|
||||
|
||||
let csv = try! CSVWriter(stream: stream, codecType: UTF32.self, endian: .big)
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str)
|
||||
|
||||
stream.close()
|
||||
let data = stream.data!
|
||||
let csvStr = String(data: data, encoding: .utf32BigEndian)!
|
||||
|
||||
XCTAssertEqual(csvStr, str)
|
||||
}
|
||||
|
||||
/// UTF32 Little Endian
|
||||
func testUTF32LE() {
|
||||
let stream = OutputStream(toMemory: ())
|
||||
stream.open()
|
||||
|
||||
let csv = try! CSVWriter(stream: stream, codecType: UTF32.self, endian: .little)
|
||||
csv.beginNewRecord()
|
||||
try! csv.write(field: str)
|
||||
|
||||
stream.close()
|
||||
let data = stream.data!
|
||||
let csvStr = String(data: data, encoding: .utf32LittleEndian)!
|
||||
|
||||
XCTAssertEqual(csvStr, str)
|
||||
}
|
||||
|
||||
}
|
|
@ -11,6 +11,7 @@ import XCTest
|
|||
|
||||
XCTMain([
|
||||
testCase(CSVTests.allTests),
|
||||
testCase(CSVWriterTests.allTests),
|
||||
testCase(LineBreakTests.allTests),
|
||||
testCase(ReadmeTests.allTests),
|
||||
testCase(TrimFieldsTests.allTests),
|
||||
|
|
Loading…
Reference in New Issue