THRIFT-5128 Swift TFramedTransport does not work using present code
Client: Swift
Patch: Jano Svitok

This closes #2047
diff --git a/compiler/cpp/src/thrift/generate/t_swift_generator.cc b/compiler/cpp/src/thrift/generate/t_swift_generator.cc
index ac63ea0..f291ee4 100644
--- a/compiler/cpp/src/thrift/generate/t_swift_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_swift_generator.cc
@@ -2423,7 +2423,8 @@
         if (!tfunction->is_oneway()) {
           out << indent() << "try outProtocol.writeMessageBegin(name: \"" << tfunction->get_name() << "\", type: .reply, sequenceID: sequenceID)" << endl
               << indent() << "try result.write(to: outProtocol)" << endl
-              << indent() << "try outProtocol.writeMessageEnd()" << endl;
+              << indent() << "try outProtocol.writeMessageEnd()" << endl
+              << indent() << "try outProtocol.transport.flush()" << endl;
         }
       } else {
         for (x_iter = xfields.begin(); x_iter != xfields.end(); ++x_iter) {
@@ -2476,7 +2477,8 @@
   if (!gen_cocoa_) {
     out << indent() << "catch let error as TApplicationError";
     block_open(out);
-    out << indent() << "try outProtocol.writeException(messageName: messageName, sequenceID: sequenceID, ex: error)" << endl;
+    out << indent() << "try outProtocol.writeException(messageName: messageName, sequenceID: sequenceID, ex: error)" << endl
+        << indent() << "try outProtocol.transport.flush()" << endl;
     block_close(out);
     block_close(out);
     out << indent() << "else";
@@ -2484,8 +2486,8 @@
     out << indent() << "try inProtocol.skip(type: .struct)" << endl
         << indent() << "try inProtocol.readMessageEnd()" << endl
         << indent() << "let ex = TApplicationError(error: .unknownMethod(methodName: messageName))" << endl
-        << indent() << "try outProtocol.writeException(messageName: messageName, "
-        << "sequenceID: sequenceID, ex: ex)" << endl;
+        << indent() << "try outProtocol.writeException(messageName: messageName, sequenceID: sequenceID, ex: ex)" << endl
+        << indent() << "try outProtocol.transport.flush()" << endl;
   } else {
     out << indent() << "catch let error as NSError";
     block_open(out);
diff --git a/lib/swift/Sources/TFramedTransport.swift b/lib/swift/Sources/TFramedTransport.swift
index 59855eb..9f75b5e 100644
--- a/lib/swift/Sources/TFramedTransport.swift
+++ b/lib/swift/Sources/TFramedTransport.swift
@@ -65,7 +65,9 @@
         throw TTransportError(error: .sizeLimit(limit: maxSize, got: toRead))
     }
 
-    return try transport.readAll(size: toRead)
+    let data = try transport.readAll(size: toRead)
+    remainingBytes -= data.count
+    return data
   }
 
   public func flush() throws {
@@ -73,10 +75,6 @@
     let buff = writeBuffer
     writeBuffer = Data()
 
-    if buff.count - TFramedTransport.headerSize < 0 {
-      throw TTransportError(error: .unknown)
-    }
-
     let frameSize = encodeFrameSize(size: UInt32(buff.count))
 
     try transport.write(data: frameSize)
diff --git a/lib/swift/Tests/ThriftTests/TBinaryProtocolTests.swift b/lib/swift/Tests/ThriftTests/TBinaryProtocolTests.swift
index 56a5572..a50db4e 100644
--- a/lib/swift/Tests/ThriftTests/TBinaryProtocolTests.swift
+++ b/lib/swift/Tests/ThriftTests/TBinaryProtocolTests.swift
@@ -116,7 +116,6 @@
     do {
       try writeVal.write(to: proto)
       try? transport.flush()
-
     } catch let error {
       XCTAssertFalse(true, "Caught Error attempting to write \(error)")
     }
@@ -129,6 +128,7 @@
       XCTAssertFalse(true, "Caught Error attempting to read \(error)")
     }
   }
+
   func testUnsafeBitcastUpdate() {
     let value: Double = 3.14159
     let val: Int64 = 31415926
@@ -162,7 +162,8 @@
       ("testBoolWriteRead", testBoolWriteRead),
       ("testStringWriteRead", testStringWriteRead),
       ("testDataWriteRead", testDataWriteRead),
-      ("testStructWriteRead", testStructWriteRead)
+      ("testStructWriteRead", testStructWriteRead),
+      ("testUnsafeBitcastUpdate", testUnsafeBitcastUpdate)
     ]
   }
 }
diff --git a/lib/swift/Tests/ThriftTests/TFramedTransportTests.swift b/lib/swift/Tests/ThriftTests/TFramedTransportTests.swift
new file mode 100644
index 0000000..d830cee
--- /dev/null
+++ b/lib/swift/Tests/ThriftTests/TFramedTransportTests.swift
@@ -0,0 +1,179 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import XCTest
+import Foundation
+@testable import Thrift
+
+/// Testig TFramedTransport
+/// 
+class TFramedTransportTests: XCTestCase {
+  var underlyingTransport: TMemoryBufferTransport = TMemoryBufferTransport(flushHandler: {
+    $0.reset(readBuffer: $1)
+  })
+
+  var proto: TBinaryProtocol!
+  var transport: TFramedTransport!
+
+  override func setUp() {
+    super.setUp()
+    transport = TFramedTransport(transport:underlyingTransport)
+    proto = TBinaryProtocol(on: transport)
+    underlyingTransport.reset()
+  }
+
+  override func tearDown() {
+    super.tearDown()
+    underlyingTransport.reset()
+  }
+  func testInt8WriteRead() {
+    let writeVal: UInt8 = 250
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: UInt8 = (try? proto.read()) ?? 0
+    XCTAssertEqual(writeVal, readVal, "Error with UInt8, wrote \(writeVal) but read \(readVal)")
+  }
+
+  func testInt16WriteRead() {
+
+    let writeVal: Int16 = 12312
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Int16 = (try? proto.read()) ?? 0
+    XCTAssertEqual(writeVal, readVal, "Error with Int16, wrote \(writeVal) but read \(readVal)")
+  }
+
+  func testInt32WriteRead() {
+    let writeVal: Int32 = 2029234
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Int32 = (try? proto.read()) ?? 0
+    XCTAssertEqual(writeVal, readVal, "Error with Int32, wrote \(writeVal) but read \(readVal)")
+  }
+
+  func testInt64WriteRead() {
+    let writeVal: Int64 = 234234981374134
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Int64 = (try? proto.read()) ?? 0
+    XCTAssertEqual(writeVal, readVal, "Error with Int64, wrote \(writeVal) but read \(readVal)")
+  }
+
+  func testDoubleWriteRead() {
+    let writeVal: Double = 3.1415926
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Double = (try? proto.read()) ?? 0.0
+    XCTAssertEqual(writeVal, readVal, "Error with Double, wrote \(writeVal) but read \(readVal)")
+  }
+
+  func testBoolWriteRead() {
+    let writeVal: Bool = true
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Bool = (try? proto.read()) ?? false
+    XCTAssertEqual(writeVal, readVal, "Error with Bool, wrote \(writeVal) but read \(readVal)")
+  }
+
+  func testStringWriteRead() {
+    let writeVal: String = "Hello World"
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: String!
+    do {
+      readVal = try proto.read()
+    } catch let error {
+      XCTAssertFalse(true, "Error reading \(error)")
+      return
+    }
+
+    XCTAssertEqual(writeVal, readVal, "Error with String, wrote \(writeVal) but read \(readVal)")
+  }
+
+  func testDataWriteRead() {
+    let writeVal: Data = "Data World".data(using: .utf8)!
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Data = (try? proto.read()) ?? "Goodbye World".data(using: .utf8)!
+    XCTAssertEqual(writeVal, readVal, "Error with Data, wrote \(writeVal) but read \(readVal)")
+  }
+
+  func testStructWriteRead() {
+    let msg = "Test Protocol Error"
+    let writeVal = TApplicationError(error: .protocolError, message: msg)
+    do {
+      try writeVal.write(to: proto)
+      try? transport.flush()
+    } catch let error {
+      XCTAssertFalse(true, "Caught Error attempting to write \(error)")
+    }
+
+    do {
+      let readVal = try TApplicationError.read(from: proto)
+      XCTAssertEqual(readVal.error.thriftErrorCode, writeVal.error.thriftErrorCode, "Error case mismatch, expected \(readVal.error) got \(writeVal.error)")
+      XCTAssertEqual(readVal.message, writeVal.message, "Error message mismatch, expected \(readVal.message) got \(writeVal.message)")
+    } catch let error {
+      XCTAssertFalse(true, "Caught Error attempting to read \(error)")
+    }
+  }
+
+  func testUnsafeBitcastUpdate() {
+    let value: Double = 3.14159
+    let val: Int64 = 31415926
+    let uval: UInt64 = 31415926
+
+    let i64 = Int64(bitPattern: value.bitPattern)
+    let ubc = unsafeBitCast(value, to: Int64.self)
+
+    XCTAssertEqual(i64, ubc, "Bitcast Double-> i64 Values don't match")
+
+    let dbl = Double(bitPattern: UInt64(val))
+    let ubdb = unsafeBitCast(val, to: Double.self)
+
+    XCTAssertEqual(dbl, ubdb, "Bitcast i64 -> Double Values don't match")
+
+    let db2 = Double(bitPattern: uval)
+    let usbc2 = unsafeBitCast(uval, to: Double.self)
+
+    XCTAssertEqual(db2, usbc2, "Bitcast u64 -> Double Values don't match")
+  }
+
+  static var allTests : [(String, (TFramedTransportTests) -> () throws -> Void)] {
+    return [
+      ("testInt8WriteRead", testInt8WriteRead),
+      ("testInt16WriteRead", testInt16WriteRead),
+      ("testInt32WriteRead", testInt32WriteRead),
+      ("testInt64WriteRead", testInt64WriteRead),
+      ("testDoubleWriteRead", testDoubleWriteRead),
+      ("testBoolWriteRead", testBoolWriteRead),
+      ("testStringWriteRead", testStringWriteRead),
+      ("testDataWriteRead", testDataWriteRead),
+      ("testStructWriteRead", testStructWriteRead),
+      ("testUnsafeBitcastUpdate", testUnsafeBitcastUpdate)
+    ]
+  }
+}
diff --git a/lib/swift/Tests/ThriftTests/TMultiplexedProcessorTests.swift b/lib/swift/Tests/ThriftTests/TMultiplexedProcessorTests.swift
index 559ff0b..a68c081 100644
--- a/lib/swift/Tests/ThriftTests/TMultiplexedProcessorTests.swift
+++ b/lib/swift/Tests/ThriftTests/TMultiplexedProcessorTests.swift
@@ -138,4 +138,17 @@
     try transport.flush()
     try sut.process(on: proto, outProtocol: proto)
   }
+
+  static var allTests : [(String, (TMultiplexedProcessorTests) -> () throws -> Void)] {
+    return [
+      ("testExceptionMessageThrowsError", testExceptionMessageThrowsError),
+      ("testReplyMessageThrowsError", testReplyMessageThrowsError),
+      ("testMissingDefaultProcessorThrowsError", testMissingDefaultProcessorThrowsError),
+      ("testUsesDefaultProcessorForNonMultiplexedMessage", testUsesDefaultProcessorForNonMultiplexedMessage),
+      ("testUsesProcessorForMultiplexedMessage", testUsesProcessorForMultiplexedMessage),
+      ("testMissingProcessorForMultiplexedMessageThrowsError", testMissingProcessorForMultiplexedMessageThrowsError),
+      ("testCallMessageDoesNotThrowError", testCallMessageDoesNotThrowError),
+      ("testOneWayMessageDoesNotThrowError", testOneWayMessageDoesNotThrowError)
+    ]
+  }
 }
diff --git a/lib/swift/Tests/ThriftTests/ThriftTests.swift b/lib/swift/Tests/ThriftTests/ThriftTests.swift
index 37f3cf6..226862e 100644
--- a/lib/swift/Tests/ThriftTests/ThriftTests.swift
+++ b/lib/swift/Tests/ThriftTests/ThriftTests.swift
@@ -6,10 +6,6 @@
     XCTAssertEqual(Thrift().version, "0.14.0")
   }
 
-  func test_in_addr_extension() {
-
-  }
-
   static var allTests : [(String, (ThriftTests) -> () throws -> Void)] {
     return [
       ("testVersion", testVersion),