Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Reorganized and elaborated tests
  • Loading branch information
yoiang committed Sep 11, 2018
commit 68a7e0469ac82caa73fb4caa608c26640b7e7103
8 changes: 8 additions & 0 deletions CSV.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
0EDF8EE31DDB73530068056A /* ReadmeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ECF1DDB73370068056A /* ReadmeTests.swift */; };
0EDF8EE41DDB73530068056A /* TrimFieldsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ED01DDB73370068056A /* TrimFieldsTests.swift */; };
0EDF8EE51DDB73530068056A /* UnicodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ED11DDB73370068056A /* UnicodeTests.swift */; };
3C89219E21484154004AA78A /* CSVReader+DecodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C89219D21484153004AA78A /* CSVReader+DecodableTests.swift */; };
3C89219F21484154004AA78A /* CSVReader+DecodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C89219D21484153004AA78A /* CSVReader+DecodableTests.swift */; };
3C8921A021484154004AA78A /* CSVReader+DecodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C89219D21484153004AA78A /* CSVReader+DecodableTests.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -114,6 +117,7 @@
0EDF8ECF1DDB73370068056A /* ReadmeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadmeTests.swift; sourceTree = "<group>"; };
0EDF8ED01DDB73370068056A /* TrimFieldsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrimFieldsTests.swift; sourceTree = "<group>"; };
0EDF8ED11DDB73370068056A /* UnicodeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnicodeTests.swift; sourceTree = "<group>"; };
3C89219D21484153004AA78A /* CSVReader+DecodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CSVReader+DecodableTests.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -233,6 +237,7 @@
isa = PBXGroup;
children = (
0EDF8ECD1DDB73370068056A /* CSVTests.swift */,
3C89219D21484153004AA78A /* CSVReader+DecodableTests.swift */,
0E54021A1ED9DDF40019C3ED /* CSVWriterTests.swift */,
0EDF8ECE1DDB73370068056A /* LineBreakTests.swift */,
0EDF8ECF1DDB73370068056A /* ReadmeTests.swift */,
Expand Down Expand Up @@ -560,6 +565,7 @@
buildActionMask = 2147483647;
files = (
0EDF8EDE1DDB73520068056A /* ReadmeTests.swift in Sources */,
3C89219F21484154004AA78A /* CSVReader+DecodableTests.swift in Sources */,
0EDF8EDC1DDB73520068056A /* CSVTests.swift in Sources */,
0EDF8EDF1DDB73520068056A /* TrimFieldsTests.swift in Sources */,
0E7F657C1EF6437E00E1E1A0 /* Version1Tests.swift in Sources */,
Expand Down Expand Up @@ -602,6 +608,7 @@
buildActionMask = 2147483647;
files = (
0EDF8ED91DDB73520068056A /* ReadmeTests.swift in Sources */,
3C89219E21484154004AA78A /* CSVReader+DecodableTests.swift in Sources */,
0EDF8ED71DDB73520068056A /* CSVTests.swift in Sources */,
0EDF8EDA1DDB73520068056A /* TrimFieldsTests.swift in Sources */,
0E7F657B1EF6437E00E1E1A0 /* Version1Tests.swift in Sources */,
Expand Down Expand Up @@ -630,6 +637,7 @@
buildActionMask = 2147483647;
files = (
0EDF8EE31DDB73530068056A /* ReadmeTests.swift in Sources */,
3C8921A021484154004AA78A /* CSVReader+DecodableTests.swift in Sources */,
0EDF8EE11DDB73530068056A /* CSVTests.swift in Sources */,
0EDF8EE41DDB73530068056A /* TrimFieldsTests.swift in Sources */,
0E7F657D1EF6437E00E1E1A0 /* Version1Tests.swift in Sources */,
Expand Down
1 change: 1 addition & 0 deletions CSV.xcodeproj/xcshareddata/xcschemes/CSV-iOS.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
codeCoverageEnabled = "YES"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
Expand Down
205 changes: 205 additions & 0 deletions Tests/CSVTests/CSVReader+DecodableTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
//
// CSVReader+DecodableTests.swift
// CSV
//
// Created by Ian Grossberg on 9/11/18.
// Copyright © 2018 yaslab. All rights reserved.
//

import XCTest
@testable import CSV

class CSVReader_DecodableTests: XCTestCase {
static let allTests = [
("testNoHeader", testNoHeader),
("testBasic", testBasic),
("testTypeMismatch", testTypeMismatch),
]

struct SupportedDecodableExample: Decodable, Equatable {
let intKey: Int
let stringKey: String
let optionalStringKey: String?
let dateKey: Date

static func ==(left: SupportedDecodableExample, right: SupportedDecodableExample) -> Bool {
let formatter = CSVReader.dateFormatter
return left.intKey == right.intKey && left.stringKey == right.stringKey && left.optionalStringKey == right.optionalStringKey
//&& left.dateKey.compare(right.dateKey) == ComparisonResult.orderedSame // TODO: find more accurate conversion method, cannot compare directly likely because we are losing precision when in csv
&& formatter.string(from: left.dateKey) == formatter.string(from: right.dateKey)
}

static var examples: [SupportedDecodableExample] {
return [
SupportedDecodableExample(intKey: 12345, stringKey: "stringValue", optionalStringKey: nil, dateKey: Date()),
SupportedDecodableExample(intKey: 54321, stringKey: "stringValue2", optionalStringKey: "withValue", dateKey: Date(timeInterval: 100, since: Date()))
]
}
}

func testNoHeader() {
let noHeaderConfig = CSVReader.Configuration(hasHeaderRow: false,
trimFields: false,
delimiter: ",",
whitespaces: .whitespaces)
let noHeaderIt = "あ,い1,\"う\",えお\n,,x,".unicodeScalars.makeIterator()
let noHeaderCSV = try! CSVReader(iterator: noHeaderIt, configuration: noHeaderConfig)

do {
let _: SupportedDecodableExample? = try noHeaderCSV.readRow()
XCTFail("Expect DecodingError.typeMismatch Error thrown")
} catch {
}
}

func testBasic() {
let headerConfig = CSVReader.Configuration(hasHeaderRow: true,
trimFields: false,
delimiter: ",",
whitespaces: .whitespaces)
let exampleRecords = SupportedDecodableExample.examples
let dateFormatter = CSVReader.dateFormatter

let headerIt = """
stringKey,optionalStringKey,intKey,ignored,dateKey
\(exampleRecords[0].stringKey),,\(exampleRecords[0].intKey),,\"\(dateFormatter.string(from: exampleRecords[0].dateKey))\"
\(exampleRecords[1].stringKey),\(exampleRecords[1].optionalStringKey!),\(exampleRecords[1].intKey),,\"\(dateFormatter.string(from: exampleRecords[1].dateKey))\"
""".unicodeScalars.makeIterator()
let headerCSV = try! CSVReader(iterator: headerIt, configuration: headerConfig)

var records = [SupportedDecodableExample]()
do {
while let record: SupportedDecodableExample = try headerCSV.readRow() {
records.append(record)
}
} catch {
XCTFail("readRow<T>() threw error: \(error)")
}
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], exampleRecords[0])
XCTAssertEqual(records[1], exampleRecords[1])
}

func testTypeMismatch() {
let headerConfig = CSVReader.Configuration(hasHeaderRow: true,
trimFields: false,
delimiter: ",",
whitespaces: .whitespaces)
let exampleRecords = SupportedDecodableExample.examples

let invalidFieldTypeIt = """
stringKey,optionalStringKey,intKey,ignored
\(exampleRecords[0].stringKey),,this is a string where we expect an Int,
\(exampleRecords[1].stringKey),\(exampleRecords[1].optionalStringKey!),\(exampleRecords[1].intKey),
""".unicodeScalars.makeIterator()
let invalidFieldTypeCSV = try! CSVReader(iterator: invalidFieldTypeIt, configuration: headerConfig)

do {
while let _: SupportedDecodableExample = try invalidFieldTypeCSV.readRow() {
}
XCTFail("Expect DecodingError.typeMismatch Error thrown")
} catch {
guard let error = error as? DecodingError else {
XCTFail("Expect DecodingError Error thrown")
return
}
switch error {
case let .typeMismatch(_, context):
XCTAssertEqual(context.codingPath[0].stringValue, "intKey", "Type Mismatch Error on unexpected field")
break
default:
XCTFail("Expect Type Mismatch Error thrown")
return
}
}
}

func testTypeInvalidDateFormat() {
let headerConfig = CSVReader.Configuration(hasHeaderRow: true,
trimFields: false,
delimiter: ",",
whitespaces: .whitespaces)
let invalidFieldTypeIt = """
dateKey,stringKey,optionalStringKey,intKey,ignored
al;ksdjf;akjsdf,asldkj,,1234,
""".unicodeScalars.makeIterator()
let invalidFieldTypeCSV = try! CSVReader(iterator: invalidFieldTypeIt, configuration: headerConfig)

do {
while let _: SupportedDecodableExample = try invalidFieldTypeCSV.readRow() {
}
XCTFail("Expect DecodingError.dataCorrupted Error thrown")
} catch {
guard let error = error as? DecodingError else {
XCTFail("Expect DecodingError Error thrown")
return
}
switch error {
case let .dataCorrupted(context):
XCTAssertEqual(context.codingPath[0].stringValue, "dateKey", "Type Mismatch Error on unexpected field")
break
default:
XCTFail("Expect DecodingError.dataCorrupted Error thrown, got \(error)")
return
}
}
}

struct UnsupportedDecodableExample: Decodable, Equatable {
enum UndecodableEnum: Int, Decodable {
case first
case second
}
let enumKey: UndecodableEnum

static func ==(left: UnsupportedDecodableExample, right: UnsupportedDecodableExample) -> Bool {
return left.enumKey == right.enumKey
}

static var examples: [UnsupportedDecodableExample] {
return [
UnsupportedDecodableExample(enumKey: .first),
UnsupportedDecodableExample(enumKey: .second)
]
}
}

func testUnsupportedDecodableField() {
let headerConfig = CSVReader.Configuration(hasHeaderRow: true,
trimFields: false,
delimiter: ",",
whitespaces: .whitespaces)
let exampleRecords = UnsupportedDecodableExample.examples

let headerIt = """
enumKey,optionalStringKey,intKey,ignored,dateKey
\(exampleRecords[0].enumKey),"hiiiii",123445,,
\(exampleRecords[1].enumKey),,54231,,
""".unicodeScalars.makeIterator()
let headerCSV = try! CSVReader(iterator: headerIt, configuration: headerConfig)

var records = [UnsupportedDecodableExample]()
do {
while let record: UnsupportedDecodableExample = try headerCSV.readRow() {
records.append(record)
}
XCTFail("Expect Data Corrupted Error thrown")
} catch {
guard let error = error as? DecodingError else {
XCTFail("Expect DecodingError Error thrown")
return
}
switch error {
case let .dataCorrupted(context):
guard context.codingPath[0].stringValue == "enumKey" else {
XCTFail("Data Corrupted Error on unexpected field")
return
}
break
default:
XCTFail("Expect Data Corrupted Error thrown")
return
}
}
}
}
61 changes: 0 additions & 61 deletions Tests/CSVTests/CSVTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -232,65 +232,4 @@ class CSVTests: XCTestCase {
// XCTAssertNil(rows[1]["yyy"])
// }

struct DecodableExample: Decodable, Equatable {
let intKey: Int
let stringKey: String
let optionalStringKey: String?
let dateKey: Date

static func ==(left: DecodableExample, right: DecodableExample) -> Bool {
let formatter = CSVReader.dateFormatter
return left.intKey == right.intKey && left.stringKey == right.stringKey && left.optionalStringKey == right.optionalStringKey
//&& left.dateKey.compare(right.dateKey) == ComparisonResult.orderedSame // TODO: find more accurate conversion method, cannot compare directly likely because we are losing precision when in csv
&& formatter.string(from: left.dateKey) == formatter.string(from: right.dateKey)
}
}

func testDecodable() {
let noHeaderConfig = CSVReader.Configuration(hasHeaderRow: false,
trimFields: false,
delimiter: ",",
whitespaces: .whitespaces)
let noHeaderIt = "あ,い1,\"う\",えお\n,,x,".unicodeScalars.makeIterator()
let noHeaderCSV = try! CSVReader(iterator: noHeaderIt, configuration: noHeaderConfig)

do {
let _: DecodableExample? = try noHeaderCSV.readRow()
XCTFail("Expect DecodingError.typeMismatch Error thrown")
} catch {
}

let headerConfig = CSVReader.Configuration(hasHeaderRow: true,
trimFields: false,
delimiter: ",",
whitespaces: .whitespaces)
let record0Example = DecodableExample(intKey: 12345, stringKey: "stringValue", optionalStringKey: nil, dateKey: Date())
let record1Example = DecodableExample(intKey: 54321, stringKey: "stringValue2", optionalStringKey: "withValue", dateKey: Date(timeInterval: 100, since: Date()))
let dateFormatter = CSVReader.dateFormatter

let headerIt = "stringKey,optionalStringKey,intKey,ignored,dateKey\n\(record0Example.stringKey),,\(record0Example.intKey),,\"\(dateFormatter.string(from: record0Example.dateKey))\"\n\(record1Example.stringKey),\(record1Example.optionalStringKey!),\(record1Example.intKey),,\"\(dateFormatter.string(from: record1Example.dateKey))\"".unicodeScalars.makeIterator()
let headerCSV = try! CSVReader(iterator: headerIt, configuration: headerConfig)

var records = [DecodableExample]()
do {
while let record: DecodableExample = try headerCSV.readRow() {
records.append(record)
}
} catch {
XCTFail("readRow<T>() threw error: \(error)")
}
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], record0Example)
XCTAssertEqual(records[1], record1Example)

let invalidFieldTypeIt = "stringKey,optionalStringKey,intKey,ignored\n\(record0Example.stringKey),,this is a string where we expect an Int,\n\(record1Example.stringKey),\(record1Example.optionalStringKey!),\(record1Example.intKey),".unicodeScalars.makeIterator()
let invalidFieldTypeCSV = try! CSVReader(iterator: invalidFieldTypeIt, configuration: headerConfig)

do {
while let _: DecodableExample = try invalidFieldTypeCSV.readRow() {
}
XCTFail("Expect DecodingError.typeMismatch Error thrown")
} catch {
}
}
}