From afbf2cfc40cab98de73f3ea528ae8cd57879fc5c Mon Sep 17 00:00:00 2001 From: Erik Little Date: Fri, 18 Aug 2017 11:04:06 -0400 Subject: [PATCH] Use errors in parsing method --- SocketIO-MacTests/SocketBasicPacketTest.swift | 81 +++++++++---------- SocketIO-MacTests/SocketParserTest.swift | 67 ++++++++------- Source/SocketIO/Parse/SocketParsable.swift | 46 ++++++----- 3 files changed, 96 insertions(+), 98 deletions(-) diff --git a/SocketIO-MacTests/SocketBasicPacketTest.swift b/SocketIO-MacTests/SocketBasicPacketTest.swift index d2614fb..fb947a0 100644 --- a/SocketIO-MacTests/SocketBasicPacketTest.swift +++ b/SocketIO-MacTests/SocketBasicPacketTest.swift @@ -12,7 +12,7 @@ import XCTest class SocketBasicPacketTest: XCTestCase { let data = "test".data(using: String.Encoding.utf8)! let data2 = "test2".data(using: String.Encoding.utf8)! - + func testEmpyEmit() { let expectedSendString = "2[\"test\"]" let sendData = ["test"] @@ -20,75 +20,75 @@ class SocketBasicPacketTest: XCTestCase { XCTAssertEqual(packet.packetString, expectedSendString) } - + func testNullEmit() { let expectedSendString = "2[\"test\",null]" let sendData: [Any] = ["test", NSNull()] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) - + XCTAssertEqual(packet.packetString, expectedSendString) } - + func testStringEmit() { let expectedSendString = "2[\"test\",\"foo bar\"]" let sendData = ["test", "foo bar"] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) - + XCTAssertEqual(packet.packetString, expectedSendString) } - + func testStringEmitWithQuotes() { let expectedSendString = "2[\"test\",\"\\\"he\\\"llo world\\\"\"]" let sendData = ["test", "\"he\"llo world\""] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) - + XCTAssertEqual(packet.packetString, expectedSendString) } - + func testJSONEmit() { 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 packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) - + XCTAssertEqual(packet.packetString, expectedSendString) } - + func testArrayEmit() { let expectedSendString = "2[\"test\",[\"hello\",1,{\"test\":\"test\"}]]" let sendData: [Any] = ["test", ["hello", 1, ["test": "test"]]] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) - + XCTAssertEqual(packet.packetString, expectedSendString) } - + func testBinaryEmit() { let expectedSendString = "51-[\"test\",{\"_placeholder\":true,\"num\":0}]" let sendData: [Any] = ["test", data] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) - + XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data]) } - + func testMultipleBinaryEmit() { 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 packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) - + XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data2, data]) } - + func testEmitWithAck() { let expectedSendString = "20[\"test\"]" let sendData = ["test"] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: false) - + XCTAssertEqual(packet.packetString, - + expectedSendString) } - + func testEmitDataWithAck() { let expectedSendString = "51-0[\"test\",{\"_placeholder\":true,\"num\":0}]" let sendData: [Any] = ["test", data] @@ -97,70 +97,67 @@ class SocketBasicPacketTest: XCTestCase { XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data]) } - + // Acks func testEmptyAck() { let expectedSendString = "30[]" let packet = SocketPacket.packetFromEmit([], id: 0, nsp: "/", ack: true) - + XCTAssertEqual(packet.packetString, expectedSendString) } - + func testNullAck() { let expectedSendString = "30[null]" let sendData = [NSNull()] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) - + XCTAssertEqual(packet.packetString, expectedSendString) } - + func testStringAck() { let expectedSendString = "30[\"test\"]" let sendData = ["test"] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) - + XCTAssertEqual(packet.packetString, expectedSendString) } - + func testJSONAck() { let expectedSendString = "30[{\"null\":null,\"hello\":1,\"test\":\"hello\",\"foobar\":true}]" let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) - + XCTAssertEqual(packet.packetString, expectedSendString) } - + func testBinaryAck() { let expectedSendString = "61-0[{\"_placeholder\":true,\"num\":0}]" let sendData = [data] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) - + XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data]) } - + func testMultipleBinaryAck() { let expectedSendString = "62-0[{\"data2\":{\"_placeholder\":true,\"num\":0},\"data1\":{\"_placeholder\":true,\"num\":1}}]" let sendData = [["data1": data, "data2": data2]] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) - + XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data2, data]) } - + func testBinaryStringPlaceholderInMessage() { let engineString = "52-[\"test\",\"~~0\",{\"num\":0,\"_placeholder\":true},{\"_placeholder\":true,\"num\":1}]" let socket = SocketIOClient(socketURL: URL(string: "http://localhost/")!) socket.setTestable() - - if case let .right(packet) = socket.parseString(engineString) { - var packet = packet - XCTAssertEqual(packet.event, "test") - _ = packet.addData(data) - _ = packet.addData(data2) - XCTAssertEqual(packet.args[0] as? String, "~~0") - } else { - XCTFail() - } + + var packet = try! socket.parseString(engineString) + + XCTAssertEqual(packet.event, "test") + _ = packet.addData(data) + _ = packet.addData(data2) + XCTAssertEqual(packet.args[0] as? String, "~~0") } } diff --git a/SocketIO-MacTests/SocketParserTest.swift b/SocketIO-MacTests/SocketParserTest.swift index 559ca33..e22de7c 100644 --- a/SocketIO-MacTests/SocketParserTest.swift +++ b/SocketIO-MacTests/SocketParserTest.swift @@ -11,7 +11,7 @@ import XCTest class SocketParserTest: XCTestCase { let testSocket = SocketIOClient(socketURL: URL(string: "http://localhost/")!) - + //Format key: message; namespace-data-binary-id static let packetTypes: [String: (String, [Any], [Data], Int)] = [ "0": ("/", [], [], -1), "1": ("/", [], [], -1), @@ -29,7 +29,7 @@ class SocketParserTest: XCTestCase { "4{\"test\":2}": ("/", [["test": 2]], [], -1), "41": ("/", [1], [], -1), "4[1, \"hello\"]": ("/", [1, "hello"], [], -1)] - + func testDisconnect() { let message = "1" validateParseResult(message) @@ -39,82 +39,82 @@ class SocketParserTest: XCTestCase { let message = "0" validateParseResult(message) } - + func testDisconnectNameSpace() { let message = "1/swift" validateParseResult(message) } - + func testConnecttNameSpace() { let message = "0/swift" validateParseResult(message) } - + func testIdEvent() { let message = "25[\"test\"]" validateParseResult(message) } - + func testBinaryPlaceholderAsString() { let message = "2[\"test\",\"~~0\"]" validateParseResult(message) } - + func testNameSpaceArrayParse() { let message = "2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]" validateParseResult(message) } - + func testNameSpaceArrayAckParse() { let message = "3/swift,0[[\"test3\",\"test4\"]]" validateParseResult(message) } - + func testNameSpaceBinaryEventParse() { let message = "51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]" validateParseResult(message) } - + func testNameSpaceBinaryAckParse() { let message = "61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]" validateParseResult(message) } - + func testNamespaceErrorParse() { let message = "4/swift," validateParseResult(message) } - + func testErrorTypeString() { let message = "4\"ERROR\"" validateParseResult(message) } - + func testErrorTypeDictionary() { let message = "4{\"test\":2}" validateParseResult(message) } - + func testErrorTypeInt() { let message = "41" validateParseResult(message) } - + func testErrorTypeArray() { let message = "4[1, \"hello\"]" validateParseResult(message) } - + func testInvalidInput() { let message = "8" - switch testSocket.parseString(message) { - case .left(_): - return - case .right(_): - XCTFail("Created packet when shouldn't have") + do { + let _ = try testSocket.parseString(message) + XCTFail() + } catch { + } } - + func testGenericParser() { var parser = SocketStringReader(message: "61-/swift,") XCTAssertEqual(parser.read(count: 1), "6") @@ -122,27 +122,24 @@ class SocketParserTest: XCTestCase { XCTAssertEqual(parser.readUntilOccurence(of: "-"), "1") XCTAssertEqual(parser.currentCharacter, "/") } - + func validateParseResult(_ message: String) { let validValues = SocketParserTest.packetTypes[message]! - let packet = testSocket.parseString(message) + let packet = try! testSocket.parseString(message) let type = String(message.characters.prefix(1)) - if case let .right(packet) = packet { - XCTAssertEqual(packet.type, SocketPacket.PacketType(rawValue: Int(type) ?? -1)!) - XCTAssertEqual(packet.nsp, validValues.0) - XCTAssertTrue((packet.data as NSArray).isEqual(to: validValues.1), "\(packet.data)") - XCTAssertTrue((packet.binary as NSArray).isEqual(to: validValues.2), "\(packet.binary)") - XCTAssertEqual(packet.id, validValues.3) - } else { - XCTFail() - } + + XCTAssertEqual(packet.type, SocketPacket.PacketType(rawValue: Int(type) ?? -1)!) + XCTAssertEqual(packet.nsp, validValues.0) + XCTAssertTrue((packet.data as NSArray).isEqual(to: validValues.1), "\(packet.data)") + XCTAssertTrue((packet.binary as NSArray).isEqual(to: validValues.2), "\(packet.binary)") + XCTAssertEqual(packet.id, validValues.3) } - + func testParsePerformance() { let keys = Array(SocketParserTest.packetTypes.keys) measure { for item in keys.enumerated() { - _ = self.testSocket.parseString(item.element) + _ = try! self.testSocket.parseString(item.element) } } } diff --git a/Source/SocketIO/Parse/SocketParsable.swift b/Source/SocketIO/Parse/SocketParsable.swift index 6b31cc8..7f5ec74 100644 --- a/Source/SocketIO/Parse/SocketParsable.swift +++ b/Source/SocketIO/Parse/SocketParsable.swift @@ -27,6 +27,12 @@ protocol SocketParsable { func parseSocketMessage(_ message: String) } +enum SocketParsableError : Error { + case invalidDataArray + case invalidPacket + case invalidPacketType +} + extension SocketParsable where Self: SocketIOClientSpec { private func isCorrectNamespace(_ nsp: String) -> Bool { 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 - func parseString(_ message: String) -> Either { + func parseString(_ message: String) throws -> SocketPacket { var reader = SocketStringReader(message: message) 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 { - return .right(SocketPacket(type: type, nsp: "/")) + return SocketPacket(type: type, nsp: "/") } var namespace = "/" @@ -80,7 +86,7 @@ extension SocketParsable where Self: SocketIOClientSpec { if let holders = Int(reader.readUntilOccurence(of: "-")) { placeholders = holders } else { - return .left("Invalid packet") + throw SocketParsableError.invalidPacket } } @@ -89,7 +95,7 @@ extension SocketParsable where Self: SocketIOClientSpec { } if !reader.hasNext { - return .right(SocketPacket(type: type, nsp: namespace, placeholders: placeholders)) + return SocketPacket(type: type, nsp: namespace, placeholders: placeholders) } var idString = "" @@ -113,21 +119,17 @@ extension SocketParsable where Self: SocketIOClientSpec { dataArray = "[" + dataArray + "]" } - switch parseData(dataArray) { - case let .left(err): - return .left(err) - case let .right(data): - return .right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1, - nsp: namespace, placeholders: placeholders)) - } + let data = try parseData(dataArray) + + return SocketPacket(type: type, data: data, id: Int(idString) ?? -1, nsp: namespace, placeholders: placeholders) } // Parses data for events - private func parseData(_ data: String) -> Either { + private func parseData(_ data: String) throws -> [Any] { do { - return .right(try data.toArray()) + return try data.toArray() } 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) - switch parseString(message) { - case let .left(err): - DefaultSocketLogger.Logger.error("\(err): %@", type: "SocketParser", args: message) - case let .right(pack): - DefaultSocketLogger.Logger.log("Decoded packet as: %@", type: "SocketParser", args: pack.description) - handlePacket(pack) + do { + let packet = try parseString(message) + + DefaultSocketLogger.Logger.log("Decoded packet as: %@", type: "SocketParser", args: packet.description) + + handlePacket(packet) + } catch { + DefaultSocketLogger.Logger.error("\(error): %@", type: "SocketParser", args: message) } }