From 4b3b46b57bfab55d9fba09c65c9755c91f31be7f Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Tue, 13 Sep 2022 10:23:50 +0200
Subject: [PATCH] Add ListenersRegistry

---
 .../Utils/ListenersRegistry.swift             | 39 +++++++++++++++++
 .../TestHelpers/Message+stubs.swift           | 18 ++++++++
 .../Utils/ListenersRegistryTests.swift        | 43 +++++++++++++++++++
 3 files changed, 100 insertions(+)
 create mode 100644 Sources/XXMessengerClient/Utils/ListenersRegistry.swift
 create mode 100644 Tests/XXMessengerClientTests/TestHelpers/Message+stubs.swift
 create mode 100644 Tests/XXMessengerClientTests/Utils/ListenersRegistryTests.swift

diff --git a/Sources/XXMessengerClient/Utils/ListenersRegistry.swift b/Sources/XXMessengerClient/Utils/ListenersRegistry.swift
new file mode 100644
index 00000000..6378e3b0
--- /dev/null
+++ b/Sources/XXMessengerClient/Utils/ListenersRegistry.swift
@@ -0,0 +1,39 @@
+import Foundation
+import XCTestDynamicOverlay
+import XXClient
+
+public struct ListenersRegistry {
+  public var register: (Listener) -> Cancellable
+  public var registered: () -> Listener
+}
+
+extension ListenersRegistry {
+  public static func live() -> ListenersRegistry {
+    class Registry {
+      var listeners: [UUID: Listener] = [:]
+    }
+    let registry = Registry()
+    return ListenersRegistry(
+      register: { listener in
+        let id = UUID()
+        registry.listeners[id] = listener
+        return Cancellable { registry.listeners[id] = nil }
+      },
+      registered: {
+        Listener(name: "listeners-registry") { message in
+          registry.listeners.values.forEach { $0.handle(message) }
+        }
+      }
+    )
+  }
+}
+
+extension ListenersRegistry {
+  public static let unimplemented = ListenersRegistry(
+    register: XCTUnimplemented("\(Self.self).register", placeholder: Cancellable {}),
+    registered: XCTUnimplemented("\(Self.self).registered", placeholder: Listener(
+      name: "unimplemented",
+      handle: { _ in }
+    ))
+  )
+}
diff --git a/Tests/XXMessengerClientTests/TestHelpers/Message+stubs.swift b/Tests/XXMessengerClientTests/TestHelpers/Message+stubs.swift
new file mode 100644
index 00000000..e10bea4a
--- /dev/null
+++ b/Tests/XXMessengerClientTests/TestHelpers/Message+stubs.swift
@@ -0,0 +1,18 @@
+import XXClient
+
+extension Message {
+  static func stub(_ stubId: Int) -> Message {
+    .init(
+      messageType: stubId,
+      id: "id-\(stubId)".data(using: .utf8)!,
+      payload: "payload-\(stubId)".data(using: .utf8)!,
+      sender: "sender-\(stubId)".data(using: .utf8)!,
+      recipientId: "recipientId-\(stubId)".data(using: .utf8)!,
+      ephemeralId: stubId,
+      timestamp: stubId,
+      encrypted: stubId % 2 == 0,
+      roundId: stubId,
+      roundURL: "roundURL-\(stubId)"
+    )
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Utils/ListenersRegistryTests.swift b/Tests/XXMessengerClientTests/Utils/ListenersRegistryTests.swift
new file mode 100644
index 00000000..763f92b6
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Utils/ListenersRegistryTests.swift
@@ -0,0 +1,43 @@
+import CustomDump
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+
+final class ListenersRegistryTestsTests: XCTestCase {
+  func testRegistry() {
+    var firstListenerDidHandle: [Message] = []
+    var secondListenerDidHandle: [Message] = []
+
+    let firstListener = Listener { message in
+      firstListenerDidHandle.append(message)
+    }
+    let secondListener = Listener { message in
+      secondListenerDidHandle.append(message)
+    }
+    let listenersRegistry: ListenersRegistry = .live()
+    let registeredListeners = listenersRegistry.registered()
+    let firstListenerCancellable = listenersRegistry.register(firstListener)
+    let secondListenerCancellable = listenersRegistry.register(secondListener)
+
+    let firstMessage = Message.stub(1)
+    registeredListeners.handle(firstMessage)
+
+    XCTAssertNoDifference(firstListenerDidHandle, [firstMessage])
+    XCTAssertNoDifference(secondListenerDidHandle, [firstMessage])
+
+    firstListenerCancellable.cancel()
+    let secondMessage = Message.stub(2)
+    registeredListeners.handle(secondMessage)
+
+    XCTAssertNoDifference(firstListenerDidHandle, [firstMessage])
+    XCTAssertNoDifference(secondListenerDidHandle, [firstMessage, secondMessage])
+
+    secondListenerCancellable.cancel()
+
+    let thirdMessage = Message.stub(3)
+    registeredListeners.handle(thirdMessage)
+
+    XCTAssertNoDifference(firstListenerDidHandle, [firstMessage])
+    XCTAssertNoDifference(secondListenerDidHandle, [firstMessage, secondMessage])
+  }
+}
-- 
GitLab