From 978e4ffd402010500967cc5ab202a584872a6884 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Wed, 14 Sep 2022 12:21:30 +0200
Subject: [PATCH] Implement MessageListenerHandler

---
 .../MessageListenerHandler.swift              |  50 ++++++++
 .../MessageListenerHandlerTests.swift         | 110 ++++++++++++++++++
 2 files changed, 160 insertions(+)
 create mode 100644 Examples/xx-messenger/Sources/AppCore/MessageListenerHandler/MessageListenerHandler.swift
 create mode 100644 Examples/xx-messenger/Tests/AppCoreTests/MessageListenerHandler/MessageListenerHandlerTests.swift

diff --git a/Examples/xx-messenger/Sources/AppCore/MessageListenerHandler/MessageListenerHandler.swift b/Examples/xx-messenger/Sources/AppCore/MessageListenerHandler/MessageListenerHandler.swift
new file mode 100644
index 00000000..70fbace7
--- /dev/null
+++ b/Examples/xx-messenger/Sources/AppCore/MessageListenerHandler/MessageListenerHandler.swift
@@ -0,0 +1,50 @@
+import Foundation
+import XCTestDynamicOverlay
+import XXClient
+import XXMessengerClient
+import XXModels
+
+public struct MessageListenerHandler {
+  public typealias OnError = (Error) -> Void
+
+  public var run: (@escaping OnError) -> Cancellable
+
+  public func callAsFunction(onError: @escaping OnError) -> Cancellable {
+    run(onError)
+  }
+}
+
+extension MessageListenerHandler {
+  public static func live(
+    messenger: Messenger,
+    db: DBManagerGetDB
+  ) -> MessageListenerHandler {
+    MessageListenerHandler { onError in
+      let listener = Listener { message in
+        do {
+          let payload = try MessagePayload.decode(message.payload)
+          try db().saveMessage(.init(
+            networkId: message.id,
+            senderId: message.sender,
+            recipientId: message.recipientId,
+            groupId: nil,
+            date: Date(timeIntervalSince1970: TimeInterval(message.timestamp) / 1_000_000_000),
+            status: .received,
+            isUnread: true,
+            text: payload.text,
+            roundURL: message.roundURL
+          ))
+        } catch {
+          onError(error)
+        }
+      }
+      return messenger.registerMessageListener(listener)
+    }
+  }
+}
+
+extension MessageListenerHandler {
+  public static let unimplemented = MessageListenerHandler(
+    run: XCTUnimplemented("\(Self.self)", placeholder: Cancellable {})
+  )
+}
diff --git a/Examples/xx-messenger/Tests/AppCoreTests/MessageListenerHandler/MessageListenerHandlerTests.swift b/Examples/xx-messenger/Tests/AppCoreTests/MessageListenerHandler/MessageListenerHandlerTests.swift
new file mode 100644
index 00000000..4038cb0d
--- /dev/null
+++ b/Examples/xx-messenger/Tests/AppCoreTests/MessageListenerHandler/MessageListenerHandlerTests.swift
@@ -0,0 +1,110 @@
+import CustomDump
+import XCTest
+import XXClient
+import XXMessengerClient
+import XXModels
+@testable import AppCore
+
+final class MessageListenerHandlerTests: XCTestCase {
+  func testHandleIncomingMessage() throws {
+    var didRegisterListener: [Listener] = []
+    var didCancelListener = 0
+    var didSaveMessage: [XXModels.Message] = []
+
+    var messenger: Messenger = .unimplemented
+    messenger.registerMessageListener.run = { listener in
+      didRegisterListener.append(listener)
+      return Cancellable { didCancelListener += 1 }
+    }
+    var db: DBManagerGetDB = .unimplemented
+    db.run = {
+      var db: Database = .failing
+      db.saveMessage.run = { message in
+        didSaveMessage.append(message)
+        return message
+      }
+      return db
+    }
+    let handler: MessageListenerHandler = .live(
+      messenger: messenger,
+      db: db
+    )
+
+    var cancellable: Cancellable? = handler(onError: { _ in XCTFail() })
+
+    XCTAssertNoDifference(didRegisterListener.count, 1)
+
+    let payload = MessagePayload(text: "Hello")
+    let xxMessage = XXClient.Message(
+      messageType: 111,
+      id: "message-id".data(using: .utf8)!,
+      payload: try! payload.encode(),
+      sender: "sender-id".data(using: .utf8)!,
+      recipientId: "recipient-id".data(using: .utf8)!,
+      ephemeralId: 222,
+      timestamp: 1_653_580_439_357_351_000,
+      encrypted: true,
+      roundId: 333,
+      roundURL: "round-url"
+    )
+    didRegisterListener.first?.handle(xxMessage)
+
+    XCTAssertNoDifference(didSaveMessage, [
+      .init(
+        networkId: xxMessage.id,
+        senderId: xxMessage.sender,
+        recipientId: xxMessage.recipientId,
+        groupId: nil,
+        date: Date(timeIntervalSince1970: TimeInterval(xxMessage.timestamp) / 1_000_000_000),
+        status: .received,
+        isUnread: true,
+        text: payload.text,
+        roundURL: xxMessage.roundURL
+      )
+    ])
+
+    cancellable = nil
+    _ = cancellable
+
+    XCTAssertNoDifference(didCancelListener, 1)
+  }
+
+  func testDatabaseFailure() {
+    struct Failure: Error, Equatable {}
+    let error = Failure()
+    var registeredListeners: [Listener] = []
+    var didReceiveError: [Error] = []
+
+    var messenger: Messenger = .unimplemented
+    messenger.registerMessageListener.run = { listener in
+      registeredListeners.append(listener)
+      return Cancellable {}
+    }
+    var db: DBManagerGetDB = .unimplemented
+    db.run = { throw error }
+    let handler: MessageListenerHandler = .live(
+      messenger: messenger,
+      db: db
+    )
+
+    _ = handler(onError: { error in didReceiveError.append(error) })
+
+    let payload = MessagePayload(text: "Hello")
+    let xxMessage = XXClient.Message(
+      messageType: 111,
+      id: "message-id".data(using: .utf8)!,
+      payload: try! payload.encode(),
+      sender: "sender-id".data(using: .utf8)!,
+      recipientId: "recipient-id".data(using: .utf8)!,
+      ephemeralId: 222,
+      timestamp: 1_653_580_439_357_351_000,
+      encrypted: true,
+      roundId: 333,
+      roundURL: "round-url"
+    )
+    registeredListeners.first?.handle(xxMessage)
+
+    XCTAssertNoDifference(didReceiveError.count, 1)
+    XCTAssertNoDifference(didReceiveError.first as? Failure, error)
+  }
+}
-- 
GitLab