import XCTest import CodableCSV /// Check support for handling bad input final class DecodingBadInputTests: XCTestCase { /// Representation of a CSV row containing a couple of strings. private struct _Row: Codable, Equatable { var x: String var y: String } } extension DecodingBadInputTests { /// Tests bad quoting resulting in too many fields in a particular row func testBadQuoting() throws { let correctAnswer = [ _Row(x: "A", y: "A A"), _Row(x: "B", y: "B, B"), _Row(x: "C", y: "C, C"), _Row(x: "D", y: "D D"), ] let stringAB = """ x,y A,A A B,"B, B" """.appending("\n") let stringC_GOOD = """ C,"C, C" """.appending("\n") // stringC_BAD fails to quote the second field which contains a comma thus making it appear to be two fields let stringC_BAD = """ C,C, C """.appending("\n") let stringD = """ D,D D """.appending("\n") let decoder = CSVDecoder { $0.headerStrategy = .firstLine $0.boolStrategy = .numeric } // using quotes properly causes a successful decode of all 4 rows let result_GOOD = try decoder.decode([_Row].self, from: stringAB + stringC_GOOD + stringD) XCTAssertEqual(correctAnswer, result_GOOD) // when the last field is lacking the quotes, that line and all the lines after it fail to parse. let result_BAD = try decoder.decode([_Row].self, from: stringAB + stringC_BAD + stringD) XCTAssertEqual(correctAnswer, result_BAD) } /// Tests having an ill-formed header func testIllFormedHeader() throws { let correctAnswer = [ _Row(x: "A", y: "A A"), _Row(x: "B", y: "B, B"), ] let stringA_GOOD = """ x,y """.appending("\n") // stringA_BAD has an additional, incorrect, comma after the y in the header line let stringA_BAD = """ x,y, """.appending("\n") let stringB = """ A,A A B,"B, B" """.appending("\n") let decoder = CSVDecoder { $0.headerStrategy = .firstLine } // with the correct header, everything is tickety-boo let result_GOOD = try decoder.decode([_Row].self, from: stringA_GOOD + stringB) XCTAssertEqual(correctAnswer, result_GOOD) // having a stray comma at the end of the header line causes no error, but no rows are processed. let result_BAD = try decoder.decode([_Row].self, from: stringA_BAD + stringB) XCTAssertEqual(correctAnswer, result_BAD) } }