Use errors in parsing method

This commit is contained in:
Erik Little 2017-08-18 11:04:06 -04:00
parent 079c8e4e4c
commit afbf2cfc40
No known key found for this signature in database
GPG Key ID: 4930B7C5FBC1A69D
3 changed files with 96 additions and 98 deletions

View File

@ -12,7 +12,7 @@ import XCTest
class SocketBasicPacketTest: XCTestCase { class SocketBasicPacketTest: XCTestCase {
let data = "test".data(using: String.Encoding.utf8)! let data = "test".data(using: String.Encoding.utf8)!
let data2 = "test2".data(using: String.Encoding.utf8)! let data2 = "test2".data(using: String.Encoding.utf8)!
func testEmpyEmit() { func testEmpyEmit() {
let expectedSendString = "2[\"test\"]" let expectedSendString = "2[\"test\"]"
let sendData = ["test"] let sendData = ["test"]
@ -20,75 +20,75 @@ class SocketBasicPacketTest: XCTestCase {
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
} }
func testNullEmit() { func testNullEmit() {
let expectedSendString = "2[\"test\",null]" let expectedSendString = "2[\"test\",null]"
let sendData: [Any] = ["test", NSNull()] let sendData: [Any] = ["test", NSNull()]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
} }
func testStringEmit() { func testStringEmit() {
let expectedSendString = "2[\"test\",\"foo bar\"]" let expectedSendString = "2[\"test\",\"foo bar\"]"
let sendData = ["test", "foo bar"] let sendData = ["test", "foo bar"]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
} }
func testStringEmitWithQuotes() { func testStringEmitWithQuotes() {
let expectedSendString = "2[\"test\",\"\\\"he\\\"llo world\\\"\"]" let expectedSendString = "2[\"test\",\"\\\"he\\\"llo world\\\"\"]"
let sendData = ["test", "\"he\"llo world\""] let sendData = ["test", "\"he\"llo world\""]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
} }
func testJSONEmit() { func testJSONEmit() {
let expectedSendString = "2[\"test\",{\"null\":null,\"hello\":1,\"test\":\"hello\",\"foobar\":true}]" let expectedSendString = "2[\"test\",{\"null\":null,\"hello\":1,\"test\":\"hello\",\"foobar\":true}]"
let sendData: [Any] = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]] let sendData: [Any] = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
} }
func testArrayEmit() { func testArrayEmit() {
let expectedSendString = "2[\"test\",[\"hello\",1,{\"test\":\"test\"}]]" let expectedSendString = "2[\"test\",[\"hello\",1,{\"test\":\"test\"}]]"
let sendData: [Any] = ["test", ["hello", 1, ["test": "test"]]] let sendData: [Any] = ["test", ["hello", 1, ["test": "test"]]]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
} }
func testBinaryEmit() { func testBinaryEmit() {
let expectedSendString = "51-[\"test\",{\"_placeholder\":true,\"num\":0}]" let expectedSendString = "51-[\"test\",{\"_placeholder\":true,\"num\":0}]"
let sendData: [Any] = ["test", data] let sendData: [Any] = ["test", data]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data]) XCTAssertEqual(packet.binary, [data])
} }
func testMultipleBinaryEmit() { func testMultipleBinaryEmit() {
let expectedSendString = "52-[\"test\",{\"data2\":{\"_placeholder\":true,\"num\":0},\"data1\":{\"_placeholder\":true,\"num\":1}}]" let expectedSendString = "52-[\"test\",{\"data2\":{\"_placeholder\":true,\"num\":0},\"data1\":{\"_placeholder\":true,\"num\":1}}]"
let sendData: [Any] = ["test", ["data1": data, "data2": data2] as NSDictionary] let sendData: [Any] = ["test", ["data1": data, "data2": data2] as NSDictionary]
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data2, data]) XCTAssertEqual(packet.binary, [data2, data])
} }
func testEmitWithAck() { func testEmitWithAck() {
let expectedSendString = "20[\"test\"]" let expectedSendString = "20[\"test\"]"
let sendData = ["test"] let sendData = ["test"]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: false) let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: false)
XCTAssertEqual(packet.packetString, XCTAssertEqual(packet.packetString,
expectedSendString) expectedSendString)
} }
func testEmitDataWithAck() { func testEmitDataWithAck() {
let expectedSendString = "51-0[\"test\",{\"_placeholder\":true,\"num\":0}]" let expectedSendString = "51-0[\"test\",{\"_placeholder\":true,\"num\":0}]"
let sendData: [Any] = ["test", data] let sendData: [Any] = ["test", data]
@ -97,70 +97,67 @@ class SocketBasicPacketTest: XCTestCase {
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data]) XCTAssertEqual(packet.binary, [data])
} }
// Acks // Acks
func testEmptyAck() { func testEmptyAck() {
let expectedSendString = "30[]" let expectedSendString = "30[]"
let packet = SocketPacket.packetFromEmit([], id: 0, nsp: "/", ack: true) let packet = SocketPacket.packetFromEmit([], id: 0, nsp: "/", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
} }
func testNullAck() { func testNullAck() {
let expectedSendString = "30[null]" let expectedSendString = "30[null]"
let sendData = [NSNull()] let sendData = [NSNull()]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
} }
func testStringAck() { func testStringAck() {
let expectedSendString = "30[\"test\"]" let expectedSendString = "30[\"test\"]"
let sendData = ["test"] let sendData = ["test"]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
} }
func testJSONAck() { func testJSONAck() {
let expectedSendString = "30[{\"null\":null,\"hello\":1,\"test\":\"hello\",\"foobar\":true}]" let expectedSendString = "30[{\"null\":null,\"hello\":1,\"test\":\"hello\",\"foobar\":true}]"
let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]] let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
} }
func testBinaryAck() { func testBinaryAck() {
let expectedSendString = "61-0[{\"_placeholder\":true,\"num\":0}]" let expectedSendString = "61-0[{\"_placeholder\":true,\"num\":0}]"
let sendData = [data] let sendData = [data]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data]) XCTAssertEqual(packet.binary, [data])
} }
func testMultipleBinaryAck() { func testMultipleBinaryAck() {
let expectedSendString = "62-0[{\"data2\":{\"_placeholder\":true,\"num\":0},\"data1\":{\"_placeholder\":true,\"num\":1}}]" let expectedSendString = "62-0[{\"data2\":{\"_placeholder\":true,\"num\":0},\"data1\":{\"_placeholder\":true,\"num\":1}}]"
let sendData = [["data1": data, "data2": data2]] let sendData = [["data1": data, "data2": data2]]
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.packetString, expectedSendString)
XCTAssertEqual(packet.binary, [data2, data]) XCTAssertEqual(packet.binary, [data2, data])
} }
func testBinaryStringPlaceholderInMessage() { func testBinaryStringPlaceholderInMessage() {
let engineString = "52-[\"test\",\"~~0\",{\"num\":0,\"_placeholder\":true},{\"_placeholder\":true,\"num\":1}]" let engineString = "52-[\"test\",\"~~0\",{\"num\":0,\"_placeholder\":true},{\"_placeholder\":true,\"num\":1}]"
let socket = SocketIOClient(socketURL: URL(string: "http://localhost/")!) let socket = SocketIOClient(socketURL: URL(string: "http://localhost/")!)
socket.setTestable() socket.setTestable()
if case let .right(packet) = socket.parseString(engineString) { var packet = try! socket.parseString(engineString)
var packet = packet
XCTAssertEqual(packet.event, "test") XCTAssertEqual(packet.event, "test")
_ = packet.addData(data) _ = packet.addData(data)
_ = packet.addData(data2) _ = packet.addData(data2)
XCTAssertEqual(packet.args[0] as? String, "~~0") XCTAssertEqual(packet.args[0] as? String, "~~0")
} else {
XCTFail()
}
} }
} }

View File

@ -11,7 +11,7 @@ import XCTest
class SocketParserTest: XCTestCase { class SocketParserTest: XCTestCase {
let testSocket = SocketIOClient(socketURL: URL(string: "http://localhost/")!) let testSocket = SocketIOClient(socketURL: URL(string: "http://localhost/")!)
//Format key: message; namespace-data-binary-id //Format key: message; namespace-data-binary-id
static let packetTypes: [String: (String, [Any], [Data], Int)] = [ static let packetTypes: [String: (String, [Any], [Data], Int)] = [
"0": ("/", [], [], -1), "1": ("/", [], [], -1), "0": ("/", [], [], -1), "1": ("/", [], [], -1),
@ -29,7 +29,7 @@ class SocketParserTest: XCTestCase {
"4{\"test\":2}": ("/", [["test": 2]], [], -1), "4{\"test\":2}": ("/", [["test": 2]], [], -1),
"41": ("/", [1], [], -1), "41": ("/", [1], [], -1),
"4[1, \"hello\"]": ("/", [1, "hello"], [], -1)] "4[1, \"hello\"]": ("/", [1, "hello"], [], -1)]
func testDisconnect() { func testDisconnect() {
let message = "1" let message = "1"
validateParseResult(message) validateParseResult(message)
@ -39,82 +39,82 @@ class SocketParserTest: XCTestCase {
let message = "0" let message = "0"
validateParseResult(message) validateParseResult(message)
} }
func testDisconnectNameSpace() { func testDisconnectNameSpace() {
let message = "1/swift" let message = "1/swift"
validateParseResult(message) validateParseResult(message)
} }
func testConnecttNameSpace() { func testConnecttNameSpace() {
let message = "0/swift" let message = "0/swift"
validateParseResult(message) validateParseResult(message)
} }
func testIdEvent() { func testIdEvent() {
let message = "25[\"test\"]" let message = "25[\"test\"]"
validateParseResult(message) validateParseResult(message)
} }
func testBinaryPlaceholderAsString() { func testBinaryPlaceholderAsString() {
let message = "2[\"test\",\"~~0\"]" let message = "2[\"test\",\"~~0\"]"
validateParseResult(message) validateParseResult(message)
} }
func testNameSpaceArrayParse() { func testNameSpaceArrayParse() {
let message = "2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]" let message = "2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]"
validateParseResult(message) validateParseResult(message)
} }
func testNameSpaceArrayAckParse() { func testNameSpaceArrayAckParse() {
let message = "3/swift,0[[\"test3\",\"test4\"]]" let message = "3/swift,0[[\"test3\",\"test4\"]]"
validateParseResult(message) validateParseResult(message)
} }
func testNameSpaceBinaryEventParse() { func testNameSpaceBinaryEventParse() {
let message = "51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]" let message = "51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]"
validateParseResult(message) validateParseResult(message)
} }
func testNameSpaceBinaryAckParse() { func testNameSpaceBinaryAckParse() {
let message = "61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]" let message = "61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]"
validateParseResult(message) validateParseResult(message)
} }
func testNamespaceErrorParse() { func testNamespaceErrorParse() {
let message = "4/swift," let message = "4/swift,"
validateParseResult(message) validateParseResult(message)
} }
func testErrorTypeString() { func testErrorTypeString() {
let message = "4\"ERROR\"" let message = "4\"ERROR\""
validateParseResult(message) validateParseResult(message)
} }
func testErrorTypeDictionary() { func testErrorTypeDictionary() {
let message = "4{\"test\":2}" let message = "4{\"test\":2}"
validateParseResult(message) validateParseResult(message)
} }
func testErrorTypeInt() { func testErrorTypeInt() {
let message = "41" let message = "41"
validateParseResult(message) validateParseResult(message)
} }
func testErrorTypeArray() { func testErrorTypeArray() {
let message = "4[1, \"hello\"]" let message = "4[1, \"hello\"]"
validateParseResult(message) validateParseResult(message)
} }
func testInvalidInput() { func testInvalidInput() {
let message = "8" let message = "8"
switch testSocket.parseString(message) { do {
case .left(_): let _ = try testSocket.parseString(message)
return XCTFail()
case .right(_): } catch {
XCTFail("Created packet when shouldn't have")
} }
} }
func testGenericParser() { func testGenericParser() {
var parser = SocketStringReader(message: "61-/swift,") var parser = SocketStringReader(message: "61-/swift,")
XCTAssertEqual(parser.read(count: 1), "6") XCTAssertEqual(parser.read(count: 1), "6")
@ -122,27 +122,24 @@ class SocketParserTest: XCTestCase {
XCTAssertEqual(parser.readUntilOccurence(of: "-"), "1") XCTAssertEqual(parser.readUntilOccurence(of: "-"), "1")
XCTAssertEqual(parser.currentCharacter, "/") XCTAssertEqual(parser.currentCharacter, "/")
} }
func validateParseResult(_ message: String) { func validateParseResult(_ message: String) {
let validValues = SocketParserTest.packetTypes[message]! let validValues = SocketParserTest.packetTypes[message]!
let packet = testSocket.parseString(message) let packet = try! testSocket.parseString(message)
let type = String(message.characters.prefix(1)) let type = String(message.characters.prefix(1))
if case let .right(packet) = packet {
XCTAssertEqual(packet.type, SocketPacket.PacketType(rawValue: Int(type) ?? -1)!) XCTAssertEqual(packet.type, SocketPacket.PacketType(rawValue: Int(type) ?? -1)!)
XCTAssertEqual(packet.nsp, validValues.0) XCTAssertEqual(packet.nsp, validValues.0)
XCTAssertTrue((packet.data as NSArray).isEqual(to: validValues.1), "\(packet.data)") XCTAssertTrue((packet.data as NSArray).isEqual(to: validValues.1), "\(packet.data)")
XCTAssertTrue((packet.binary as NSArray).isEqual(to: validValues.2), "\(packet.binary)") XCTAssertTrue((packet.binary as NSArray).isEqual(to: validValues.2), "\(packet.binary)")
XCTAssertEqual(packet.id, validValues.3) XCTAssertEqual(packet.id, validValues.3)
} else {
XCTFail()
}
} }
func testParsePerformance() { func testParsePerformance() {
let keys = Array(SocketParserTest.packetTypes.keys) let keys = Array(SocketParserTest.packetTypes.keys)
measure { measure {
for item in keys.enumerated() { for item in keys.enumerated() {
_ = self.testSocket.parseString(item.element) _ = try! self.testSocket.parseString(item.element)
} }
} }
} }

View File

@ -27,6 +27,12 @@ protocol SocketParsable {
func parseSocketMessage(_ message: String) func parseSocketMessage(_ message: String)
} }
enum SocketParsableError : Error {
case invalidDataArray
case invalidPacket
case invalidPacketType
}
extension SocketParsable where Self: SocketIOClientSpec { extension SocketParsable where Self: SocketIOClientSpec {
private func isCorrectNamespace(_ nsp: String) -> Bool { private func isCorrectNamespace(_ nsp: String) -> Bool {
return nsp == self.nsp return nsp == self.nsp
@ -62,15 +68,15 @@ extension SocketParsable where Self: SocketIOClientSpec {
} }
/// Parses a messsage from the engine. Returning either a string error or a complete SocketPacket /// Parses a messsage from the engine. Returning either a string error or a complete SocketPacket
func parseString(_ message: String) -> Either<String, SocketPacket> { func parseString(_ message: String) throws -> SocketPacket {
var reader = SocketStringReader(message: message) var reader = SocketStringReader(message: message)
guard let type = Int(reader.read(count: 1)).flatMap({ SocketPacket.PacketType(rawValue: $0) }) else { guard let type = Int(reader.read(count: 1)).flatMap({ SocketPacket.PacketType(rawValue: $0) }) else {
return .left("Invalid packet type") throw SocketParsableError.invalidPacketType
} }
if !reader.hasNext { if !reader.hasNext {
return .right(SocketPacket(type: type, nsp: "/")) return SocketPacket(type: type, nsp: "/")
} }
var namespace = "/" var namespace = "/"
@ -80,7 +86,7 @@ extension SocketParsable where Self: SocketIOClientSpec {
if let holders = Int(reader.readUntilOccurence(of: "-")) { if let holders = Int(reader.readUntilOccurence(of: "-")) {
placeholders = holders placeholders = holders
} else { } else {
return .left("Invalid packet") throw SocketParsableError.invalidPacket
} }
} }
@ -89,7 +95,7 @@ extension SocketParsable where Self: SocketIOClientSpec {
} }
if !reader.hasNext { if !reader.hasNext {
return .right(SocketPacket(type: type, nsp: namespace, placeholders: placeholders)) return SocketPacket(type: type, nsp: namespace, placeholders: placeholders)
} }
var idString = "" var idString = ""
@ -113,21 +119,17 @@ extension SocketParsable where Self: SocketIOClientSpec {
dataArray = "[" + dataArray + "]" dataArray = "[" + dataArray + "]"
} }
switch parseData(dataArray) { let data = try parseData(dataArray)
case let .left(err):
return .left(err) return SocketPacket(type: type, data: data, id: Int(idString) ?? -1, nsp: namespace, placeholders: placeholders)
case let .right(data):
return .right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1,
nsp: namespace, placeholders: placeholders))
}
} }
// Parses data for events // Parses data for events
private func parseData(_ data: String) -> Either<String, [Any]> { private func parseData(_ data: String) throws -> [Any] {
do { do {
return .right(try data.toArray()) return try data.toArray()
} catch { } catch {
return .left("Error parsing data for packet") throw SocketParsableError.invalidDataArray
} }
} }
@ -137,12 +139,14 @@ extension SocketParsable where Self: SocketIOClientSpec {
DefaultSocketLogger.Logger.log("Parsing %@", type: "SocketParser", args: message) DefaultSocketLogger.Logger.log("Parsing %@", type: "SocketParser", args: message)
switch parseString(message) { do {
case let .left(err): let packet = try parseString(message)
DefaultSocketLogger.Logger.error("\(err): %@", type: "SocketParser", args: message)
case let .right(pack): DefaultSocketLogger.Logger.log("Decoded packet as: %@", type: "SocketParser", args: packet.description)
DefaultSocketLogger.Logger.log("Decoded packet as: %@", type: "SocketParser", args: pack.description)
handlePacket(pack) handlePacket(packet)
} catch {
DefaultSocketLogger.Logger.error("\(error): %@", type: "SocketParser", args: message)
} }
} }