Fixed Serializer crash when columns have different lengths

This commit is contained in:
Caleb Kleveter 2021-10-19 07:52:01 -05:00
parent 05d10cb79f
commit 12a49c1e4c
No known key found for this signature in database
GPG Key ID: B38DBD5CF2C98D69
2 changed files with 23 additions and 6 deletions

View File

@ -85,9 +85,6 @@ public struct Serializer {
/// You can pass multiple dictionaries of the same structure into this method. The headers will only be serialized the
/// first time it is called.
///
/// - Note: When you pass a dictionary into this method, each value collection is expect to contain the same
/// number of elements, and will crash with `index out of bounds` if that assumption is broken.
///
/// - Parameter data: The dictionary (or other object) to parse.
/// - Returns: A `Result` instance with a `.failure` case with all the errors from the the `.onRow` callback calls.
/// If there are no errors, the result will be a `.success` case.
@ -111,6 +108,7 @@ public struct Serializer {
guard let first = data.first?.value else { return errors.result }
(first.startIndex..<first.endIndex).forEach { index in
let cells = data.values.map { column -> [UInt8] in
guard column.indices.contains(index) else { return [] }
return column[index].bytes.escaping(self.configuration.cellDelimiter)
}
do { try onRow(Array(cells.joined(separator: [configuration.cellSeparator]))) }
@ -137,9 +135,6 @@ public struct SyncSerializer {
/// Serializes a dictionary to CSV document data. Usually this will be a dictionary of type
/// `[BytesRepresentable: [BytesRepresentable]], but it can be any type you conform to the proper protocols.
///
/// - Note: When you pass a dictionary into this method, each value collection is expect to contain the same
/// number of elements, and will crash with `index out of bounds` if that assumption is broken.
///
/// - Parameter data: The dictionary (or other object) to parse.
/// - Returns: The serialized CSV data.
public func serialize<Data>(_ data: Data) -> [UInt8] where

View File

@ -64,6 +64,28 @@ final class SerializerTests: XCTestCase {
XCTAssertEqual(quoteSerializer.serialize(quoteData), Array(quoteResult.utf8))
XCTAssertEqual(hashSerializer.serialize(hashData), Array(hashResult.utf8))
}
func testMismatchColumnLength() throws {
let data: OrderedKeyedCollection = [
"names": ["Ralph", "Caleb", "Gwynne", "Tim", "Tanner", "Logan", "Joannis"],
"specialties": ["Manager", "Grunt", "Know-it-All", "Vapor", "Rockets"]
]
let serializer = SyncSerializer()
let result = String(decoding: serializer.serialize(data), as: UTF8.self)
let match = """
"names","specialties"
"Ralph","Manager"
"Caleb","Grunt"
"Gwynne","Know-it-All"
"Tim","Vapor"
"Tanner","Rockets"
"Logan",
"Joannis",
"""
XCTAssertEqual(result, match)
}
}
internal struct OrderedKeyedCollection<K, V>: KeyedCollection, ExpressibleByDictionaryLiteral where K: Hashable {