diff --git a/CHANGELOG.md b/CHANGELOG.md index a2ff8aa7e07..dabab300995 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). # Upcoming -### 🔄 Changed +## StreamChat +### ✅ Added +- Add additional data to `Device` (`pushProvider`, `pushProviderName`, `userId`, `disabled`, `disabledReason`, `hardwareId`, and `voip`) [#4161](https://github.com/GetStream/stream-chat-swift/pull/4161) # [5.6.0](https://github.com/GetStream/stream-chat-swift/releases/tag/5.6.0) _July 03, 2026_ diff --git a/Scripts/openapi_generate.sh b/Scripts/openapi_generate.sh index ed2c3b2a6b0..86b95cca8ba 100755 --- a/Scripts/openapi_generate.sh +++ b/Scripts/openapi_generate.sh @@ -47,6 +47,7 @@ allowed_models=( # unlike allowed_models above which uses the generator's original names. allowed_hashable_models=( AppSettings + Device UploadConfig ) @@ -164,11 +165,23 @@ prune_models() { } prune_models +# Relax selected generated stored properties back to optional. Some models are +# exposed as public API where a property was historically optional (e.g. +# Device.createdAt was Date? before the OpenAPI migration). +optionalize_property() { + local file="$OUTPUT_DIR_CHAT/models/$1.swift" + sed -i '' -E \ + -e "s/^( let $2: [^?]+)$/\1?/" \ + "$file" +} +optionalize_property DeviceResponse createdAt + # 4b. Rename selected generated models for clarity and to avoid generic-name # pollution / collisions with hand-written SDK types. Runs AFTER prune_models # so allowed_models above still matches the generator's original names. rename_generated Action AttachmentActionPayload rename_generated AppResponseFields AppSettings +rename_generated DeviceResponse Device rename_generated Field AttachmentFieldPayload rename_generated FileUploadConfig UploadConfig rename_generated ImageData GiphyImageData @@ -189,6 +202,7 @@ publicize_model() { "$file" } publicize_model AppSettings +publicize_model Device publicize_model UploadConfig # 4d. Strip the generated Hashable conformance from every model not in diff --git a/Sources/StreamChat/APIClient/Endpoints/Payloads/CurrentUserPayloads.swift b/Sources/StreamChat/APIClient/Endpoints/Payloads/CurrentUserPayloads.swift index c0c12a118b5..c63cc19260e 100644 --- a/Sources/StreamChat/APIClient/Endpoints/Payloads/CurrentUserPayloads.swift +++ b/Sources/StreamChat/APIClient/Endpoints/Payloads/CurrentUserPayloads.swift @@ -7,7 +7,7 @@ import Foundation /// An object describing the incoming current user JSON payload. final class CurrentUserPayload: UserPayload, @unchecked Sendable { /// A list of devices. - let devices: [DevicePayload] + let devices: [Device] /// Muted users. let mutedUsers: [MutedUserPayload] /// Muted channels. @@ -37,7 +37,7 @@ final class CurrentUserPayload: UserPayload, @unchecked Sendable { teams: [TeamId] = [], language: String?, extraData: [String: RawJSON], - devices: [DevicePayload] = [], + devices: [Device] = [], mutedUsers: [MutedUserPayload] = [], mutedChannels: [MutedChannelPayload] = [], unreadCount: UnreadCountPayload? = nil, @@ -74,7 +74,7 @@ final class CurrentUserPayload: UserPayload, @unchecked Sendable { required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: UserPayloadsCodingKeys.self) - devices = try container.decodeIfPresent([DevicePayload].self, forKey: .devices) ?? [] + devices = try container.decodeIfPresent([Device].self, forKey: .devices) ?? [] mutedUsers = try container.decodeIfPresent([MutedUserPayload].self, forKey: .mutedUsers) ?? [] mutedChannels = try container.decodeIfPresent([MutedChannelPayload].self, forKey: .mutedChannels) ?? [] unreadCount = try? UnreadCountPayload(from: decoder) diff --git a/Sources/StreamChat/APIClient/Endpoints/Payloads/DevicePayloads.swift b/Sources/StreamChat/APIClient/Endpoints/Payloads/DevicePayloads.swift deleted file mode 100644 index 0ae448e7e15..00000000000 --- a/Sources/StreamChat/APIClient/Endpoints/Payloads/DevicePayloads.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import Foundation - -struct DevicePayload: Decodable, Equatable { - private enum CodingKeys: String, CodingKey { - case id - case createdAt = "created_at" - } - - /// Device identifier. - let id: DeviceId - /// Date the device was created for the user. - let createdAt: Date? - - init(id: DeviceId, createdAt: Date? = .init()) { - self.id = id - self.createdAt = createdAt - } -} - -struct DeviceListPayload: Decodable { - /// List of devices belonging to user. - let devices: [DevicePayload] -} diff --git a/Sources/StreamChat/Database/DTOs/CurrentUserDTO.swift b/Sources/StreamChat/Database/DTOs/CurrentUserDTO.swift index 15003352ad5..9d2abc989e1 100644 --- a/Sources/StreamChat/Database/DTOs/CurrentUserDTO.swift +++ b/Sources/StreamChat/Database/DTOs/CurrentUserDTO.swift @@ -170,7 +170,7 @@ extension NSManagedObjectContext: CurrentUserDatabaseSession { dto.unreadChannelCountsByGroup = counts } - func saveCurrentUserDevices(_ devices: [DevicePayload], clearExisting: Bool) throws -> [DeviceDTO] { + func saveCurrentUserDevices(_ devices: [Device], clearExisting: Bool) throws -> [DeviceDTO] { invalidateCurrentUserCache() guard let currentUser = currentUser else { @@ -187,6 +187,13 @@ extension NSManagedObjectContext: CurrentUserDatabaseSession { let deviceDTOs = devices.map { device -> DeviceDTO in let dto = DeviceDTO.loadOrCreate(id: device.id, context: self) dto.createdAt = device.createdAt?.bridgeDate + dto.disabled = device.disabled.map { NSNumber(value: $0) } + dto.disabledReason = device.disabledReason + dto.hardwareId = device.hardwareId + dto.pushProvider = device.pushProvider + dto.pushProviderName = device.pushProviderName + dto.userId = device.userId + dto.voip = device.voip.map { NSNumber(value: $0) } dto.user = currentUser return dto } diff --git a/Sources/StreamChat/Database/DTOs/DeviceDTO.swift b/Sources/StreamChat/Database/DTOs/DeviceDTO.swift index ddca94dc8c0..d6a17ee18a7 100644 --- a/Sources/StreamChat/Database/DTOs/DeviceDTO.swift +++ b/Sources/StreamChat/Database/DTOs/DeviceDTO.swift @@ -9,6 +9,13 @@ import Foundation class DeviceDTO: NSManagedObject { @NSManaged var id: String @NSManaged var createdAt: DBDate? + @NSManaged var disabled: NSNumber? + @NSManaged var disabledReason: String? + @NSManaged var hardwareId: String? + @NSManaged var pushProvider: String + @NSManaged var pushProviderName: String? + @NSManaged var userId: String + @NSManaged var voip: NSNumber? @NSManaged var user: CurrentUserDTO } @@ -46,6 +53,16 @@ extension DeviceDTO { extension DeviceDTO { func asModel() throws -> Device { try isNotDeleted() - return Device(id: id, createdAt: createdAt?.bridgeDate) + return Device( + createdAt: createdAt?.bridgeDate ?? Date(timeIntervalSince1970: 0), + disabled: disabled?.boolValue, + disabledReason: disabledReason, + hardwareId: hardwareId, + id: id, + pushProvider: pushProvider, + pushProviderName: pushProviderName, + userId: userId, + voip: voip?.boolValue + ) } } diff --git a/Sources/StreamChat/Database/DatabaseSession.swift b/Sources/StreamChat/Database/DatabaseSession.swift index 2e1aed992f3..c6af2f8c58c 100644 --- a/Sources/StreamChat/Database/DatabaseSession.swift +++ b/Sources/StreamChat/Database/DatabaseSession.swift @@ -65,10 +65,10 @@ protocol CurrentUserDatabaseSession { /// Adjusts `CurrentUserDTO.unreadChannelCountsByGroup[groupKey]` by `delta`, flooring at 0. func adjustUnreadChannelCount(forGroup groupKey: String, by delta: Int) - /// Updates the `CurrentUserDTO.devices` with the provided `DevicesPayload` + /// Updates the `CurrentUserDTO.devices` with the provided devices. /// If there's no current user set, an error will be thrown. @discardableResult - func saveCurrentUserDevices(_ devices: [DevicePayload], clearExisting: Bool) throws -> [DeviceDTO] + func saveCurrentUserDevices(_ devices: [Device], clearExisting: Bool) throws -> [DeviceDTO] /// Saves the `currentDevice` for current user. func saveCurrentDevice(_ deviceId: String) throws @@ -92,7 +92,7 @@ protocol CurrentUserDatabaseSession { extension CurrentUserDatabaseSession { @discardableResult - func saveCurrentUserDevices(_ devices: [DevicePayload]) throws -> [DeviceDTO] { + func saveCurrentUserDevices(_ devices: [Device]) throws -> [DeviceDTO] { try saveCurrentUserDevices(devices, clearExisting: false) } } diff --git a/Sources/StreamChat/Database/StreamChatModel.xcdatamodeld/StreamChatModel.xcdatamodel/contents b/Sources/StreamChat/Database/StreamChatModel.xcdatamodeld/StreamChatModel.xcdatamodel/contents index 86bb78d5592..d4fe1ce2d8d 100644 --- a/Sources/StreamChat/Database/StreamChatModel.xcdatamodeld/StreamChatModel.xcdatamodel/contents +++ b/Sources/StreamChat/Database/StreamChatModel.xcdatamodeld/StreamChatModel.xcdatamodel/contents @@ -193,7 +193,14 @@ + + + + + + + diff --git a/Sources/StreamChat/Generated/OpenAPI/models/DeviceResponse.swift b/Sources/StreamChat/Generated/OpenAPI/models/Device.swift similarity index 52% rename from Sources/StreamChat/Generated/OpenAPI/models/DeviceResponse.swift rename to Sources/StreamChat/Generated/OpenAPI/models/Device.swift index b52d9cf5dd0..9a38fa83884 100644 --- a/Sources/StreamChat/Generated/OpenAPI/models/DeviceResponse.swift +++ b/Sources/StreamChat/Generated/OpenAPI/models/Device.swift @@ -4,25 +4,25 @@ import Foundation -final class DeviceResponse: Sendable, Codable, JSONEncodable { +public final class Device: Sendable, Codable, JSONEncodable { /// Date/time of creation - let createdAt: Date + public let createdAt: Date? /// Whether device is disabled or not - let disabled: Bool? + public let disabled: Bool? /// Reason explaining why device had been disabled - let disabledReason: String? + public let disabledReason: String? /// Stable physical device identifier used to deduplicate pushes across push providers - let hardwareId: String? + public let hardwareId: String? /// Device ID - let id: String + public let id: String /// Push provider - let pushProvider: String + public let pushProvider: String /// Push provider name - let pushProviderName: String? + public let pushProviderName: String? /// User ID - let userId: String + public let userId: String /// When true the token is for Apple VoIP push notifications - let voip: Bool? + public let voip: Bool? init(createdAt: Date, disabled: Bool? = nil, disabledReason: String? = nil, hardwareId: String? = nil, id: String, pushProvider: String, pushProviderName: String? = nil, userId: String, voip: Bool? = nil) { self.createdAt = createdAt @@ -48,3 +48,29 @@ final class DeviceResponse: Sendable, Codable, JSONEncodable { case voip } } + +extension Device: Hashable { + public static func == (lhs: Device, rhs: Device) -> Bool { + lhs.createdAt == rhs.createdAt && + lhs.disabled == rhs.disabled && + lhs.disabledReason == rhs.disabledReason && + lhs.hardwareId == rhs.hardwareId && + lhs.id == rhs.id && + lhs.pushProvider == rhs.pushProvider && + lhs.pushProviderName == rhs.pushProviderName && + lhs.userId == rhs.userId && + lhs.voip == rhs.voip + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(createdAt) + hasher.combine(disabled) + hasher.combine(disabledReason) + hasher.combine(hardwareId) + hasher.combine(id) + hasher.combine(pushProvider) + hasher.combine(pushProviderName) + hasher.combine(userId) + hasher.combine(voip) + } +} diff --git a/Sources/StreamChat/Generated/OpenAPI/models/ListDevicesResponse.swift b/Sources/StreamChat/Generated/OpenAPI/models/ListDevicesResponse.swift index fc20511e2fa..9782a1ddbd3 100644 --- a/Sources/StreamChat/Generated/OpenAPI/models/ListDevicesResponse.swift +++ b/Sources/StreamChat/Generated/OpenAPI/models/ListDevicesResponse.swift @@ -6,10 +6,10 @@ import Foundation final class ListDevicesResponse: Sendable, Codable, JSONEncodable { /// List of devices - let devices: [DeviceResponse] + let devices: [Device] let duration: String - init(devices: [DeviceResponse], duration: String) { + init(devices: [Device], duration: String) { self.devices = devices self.duration = duration } diff --git a/Sources/StreamChat/Models/Device+Extensions.swift b/Sources/StreamChat/Models/Device+Extensions.swift new file mode 100644 index 00000000000..9e92921d213 --- /dev/null +++ b/Sources/StreamChat/Models/Device+Extensions.swift @@ -0,0 +1,15 @@ +// +// Copyright © 2026 Stream.io Inc. All rights reserved. +// + +import Foundation + +/// A unique identifier of a device. +public typealias DeviceId = String + +extension Data { + /// Generates a device id string from device token data. + var deviceId: DeviceId { map { String(format: "%02x", $0) }.joined() } +} + +extension Device: Identifiable {} diff --git a/Sources/StreamChat/Models/Device.swift b/Sources/StreamChat/Models/Device.swift deleted file mode 100644 index 2b2ce19654f..00000000000 --- a/Sources/StreamChat/Models/Device.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import Foundation - -/// A unique identifier of a device. -public typealias DeviceId = String - -extension Data { - /// Generates a device id string from device token data. - var deviceId: DeviceId { map { String(format: "%02x", $0) }.joined() } -} - -/// An object representing a device which can receive push notifications. -public struct Device: Codable, Equatable, Identifiable, Sendable { - private enum CodingKeys: String, CodingKey { - case id - case createdAt = "created_at" - } - - /// The device identifier. - public let id: DeviceId - /// The date when the device for created. - public let createdAt: Date? -} diff --git a/Sources/StreamChat/Workers/CurrentUserUpdater.swift b/Sources/StreamChat/Workers/CurrentUserUpdater.swift index 3153cfe691a..4b7f242cf52 100644 --- a/Sources/StreamChat/Workers/CurrentUserUpdater.swift +++ b/Sources/StreamChat/Workers/CurrentUserUpdater.swift @@ -137,12 +137,11 @@ class CurrentUserUpdater: Worker, @unchecked Sendable { do { nonisolated(unsafe) var devices = [Device]() let response = try result.get() - let devicePayloads = response.devices.map { DevicePayload(id: $0.id, createdAt: $0.createdAt) } self?.database.write({ (session) in // Since this call always return all device, we want' to clear the existing ones // to remove the deleted devices. devices = try session.saveCurrentUserDevices( - devicePayloads, + response.devices, clearExisting: true ) .map { try $0.asModel() } diff --git a/StreamChat.xcodeproj/project.pbxproj b/StreamChat.xcodeproj/project.pbxproj index dc430e1e1c3..1481b175fa6 100644 --- a/StreamChat.xcodeproj/project.pbxproj +++ b/StreamChat.xcodeproj/project.pbxproj @@ -758,7 +758,6 @@ StreamChatTests/APIClient/Endpoints/Payloads/ChannelReadPayload_Tests.swift, StreamChatTests/APIClient/Endpoints/Payloads/CurrentUserPayloads_Tests.swift, StreamChatTests/APIClient/Endpoints/Payloads/CustomDataHashMap_Tests.swift, - StreamChatTests/APIClient/Endpoints/Payloads/DevicePayloads_Tests.swift, StreamChatTests/APIClient/Endpoints/Payloads/DraftPayloads_Tests.swift, StreamChatTests/APIClient/Endpoints/Payloads/FileUploadPayload_Tests.swift, StreamChatTests/APIClient/Endpoints/Payloads/FlagMessagePayload_Tests.swift, diff --git a/TestTools/StreamChatTestTools/Fixtures/JSONs/Devices.json b/TestTools/StreamChatTestTools/Fixtures/JSONs/Devices.json deleted file mode 100644 index 268426f4015..00000000000 --- a/TestTools/StreamChatTestTools/Fixtures/JSONs/Devices.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "devices" : [ - { - "id" : "2552c2ec3ba609bd6ebe5d437e6926de20fde3adae2d2e7f0a5a72bc90285fa5", - "push_provider" : "apn" - } - ], - "duration" : "0.43ms" -} diff --git a/TestTools/StreamChatTestTools/Mocks/StreamChat/Database/DatabaseSession_Mock.swift b/TestTools/StreamChatTestTools/Mocks/StreamChat/Database/DatabaseSession_Mock.swift index 207fda34bf4..65780f9de76 100644 --- a/TestTools/StreamChatTestTools/Mocks/StreamChat/Database/DatabaseSession_Mock.swift +++ b/TestTools/StreamChatTestTools/Mocks/StreamChat/Database/DatabaseSession_Mock.swift @@ -49,7 +49,7 @@ class DatabaseSession_Mock: DatabaseSession { return try underlyingSession.saveCurrentDevice(deviceId) } - func saveCurrentUserDevices(_ devices: [DevicePayload], clearExisting: Bool) throws -> [DeviceDTO] { + func saveCurrentUserDevices(_ devices: [Device], clearExisting: Bool) throws -> [DeviceDTO] { try throwErrorIfNeeded() return try underlyingSession.saveCurrentUserDevices(devices, clearExisting: clearExisting) } diff --git a/TestTools/StreamChatTestTools/TestData/DummyData/CurrentUserPayload.swift b/TestTools/StreamChatTestTools/TestData/DummyData/CurrentUserPayload.swift index b1c363b3086..a0ad25a9388 100644 --- a/TestTools/StreamChatTestTools/TestData/DummyData/CurrentUserPayload.swift +++ b/TestTools/StreamChatTestTools/TestData/DummyData/CurrentUserPayload.swift @@ -22,7 +22,7 @@ extension CurrentUserPayload { teamsRole: [String: UserRole]? = nil, unreadCount: UnreadCountPayload? = .dummy, extraData: [String: RawJSON] = [:], - devices: [DevicePayload] = [], + devices: [Device] = [], mutedUsers: [MutedUserPayload] = [], teams: [TeamId] = [], language: String? = nil, @@ -57,7 +57,7 @@ extension CurrentUserPayload { static func dummy( userPayload: UserPayload, unreadCount: UnreadCountPayload? = .dummy, - devices: [DevicePayload] = [], + devices: [Device] = [], mutedUsers: [MutedUserPayload] = [], mutedChannels: [MutedChannelPayload] = [], privacySettings: UserPrivacySettingsPayload? = nil, diff --git a/TestTools/StreamChatTestTools/TestData/DummyData/DeviceResponse+Dummy.swift b/TestTools/StreamChatTestTools/TestData/DummyData/Device+Dummy.swift similarity index 72% rename from TestTools/StreamChatTestTools/TestData/DummyData/DeviceResponse+Dummy.swift rename to TestTools/StreamChatTestTools/TestData/DummyData/Device+Dummy.swift index 8776c40b4b7..b8a2e91de75 100644 --- a/TestTools/StreamChatTestTools/TestData/DummyData/DeviceResponse+Dummy.swift +++ b/TestTools/StreamChatTestTools/TestData/DummyData/Device+Dummy.swift @@ -5,8 +5,8 @@ import Foundation @testable import StreamChat -extension DeviceResponse { - static func dummy(pushProvider: String = "apn", userId: String = .unique) -> DeviceResponse { +extension Device { + static func dummy(pushProvider: String = "apn", userId: String = .unique) -> Device { .init( createdAt: .unique, id: .unique, @@ -17,7 +17,7 @@ extension DeviceResponse { } extension ListDevicesResponse { - static func dummy(devices: [DeviceResponse] = [.dummy(), .dummy()]) -> ListDevicesResponse { + static func dummy(devices: [Device] = [.dummy(), .dummy()]) -> ListDevicesResponse { .init(devices: devices, duration: "") } } diff --git a/TestTools/StreamChatTestTools/TestData/DummyData/DevicePayloads.swift b/TestTools/StreamChatTestTools/TestData/DummyData/DevicePayloads.swift deleted file mode 100644 index 9f7c0aa6760..00000000000 --- a/TestTools/StreamChatTestTools/TestData/DummyData/DevicePayloads.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import Foundation -@testable import StreamChat - -extension DevicePayload { - static var dummy: DevicePayload { - .init(id: .unique, createdAt: .unique) - } -} - -extension DeviceListPayload { - static var dummy: DeviceListPayload { - .init(devices: [DevicePayload.dummy, DevicePayload.dummy]) - } -} diff --git a/Tests/StreamChatTests/APIClient/Endpoints/Payloads/DevicePayloads_Tests.swift b/Tests/StreamChatTests/APIClient/Endpoints/Payloads/DevicePayloads_Tests.swift deleted file mode 100644 index acdb7f2c894..00000000000 --- a/Tests/StreamChatTests/APIClient/Endpoints/Payloads/DevicePayloads_Tests.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -@testable import StreamChat -@testable import StreamChatTestTools -import XCTest - -final class DevicePayloads_Tests: XCTestCase { - let devicesJSON = XCTestCase.mockData(fromJSONFile: "Devices") - - func test_devicesPayload_isSerialized() throws { - let payload = try JSONDecoder.default.decode(DeviceListPayload.self, from: devicesJSON) - - XCTAssertEqual(payload.devices.count, 1) - XCTAssertEqual( - payload.devices.first?.id, - "2552c2ec3ba609bd6ebe5d437e6926de20fde3adae2d2e7f0a5a72bc90285fa5" - ) - } -} diff --git a/Tests/StreamChatTests/Database/DTOs/CurrentUserDTO_Tests.swift b/Tests/StreamChatTests/Database/DTOs/CurrentUserDTO_Tests.swift index c8e7a452442..b8414a77dab 100644 --- a/Tests/StreamChatTests/Database/DTOs/CurrentUserDTO_Tests.swift +++ b/Tests/StreamChatTests/Database/DTOs/CurrentUserDTO_Tests.swift @@ -46,7 +46,7 @@ final class CurrentUserModelDTO_Tests: XCTestCase { let payload: CurrentUserPayload = .dummy( userPayload: userPayload, - devices: [DevicePayload.dummy], + devices: [Device.dummy()], mutedUsers: [ .dummy(userId: .unique), .dummy(userId: .unique), @@ -114,7 +114,7 @@ final class CurrentUserModelDTO_Tests: XCTestCase { } func test_savingCurrentUser_removesCurrentDevice() throws { - let initialDevice = DevicePayload.dummy + let initialDevice = Device.dummy() let initialCurrentUserPayload = CurrentUserPayload.dummy(userId: .unique, role: .admin, devices: [initialDevice]) // Save the payload to the db @@ -133,7 +133,7 @@ final class CurrentUserModelDTO_Tests: XCTestCase { // ..and is set to currentDevice XCTAssertNotEqual(currentUser?.currentDevice, nil) - let newCurrentUserPayload = CurrentUserPayload.dummy(userId: initialCurrentUserPayload.id, role: .admin, devices: [.dummy]) + let newCurrentUserPayload = CurrentUserPayload.dummy(userId: initialCurrentUserPayload.id, role: .admin, devices: [.dummy()]) // Save the payload to the db try database.writeSynchronously { session in diff --git a/Tests/StreamChatTests/Database/DTOs/DeviceDTO_Tests.swift b/Tests/StreamChatTests/Database/DTOs/DeviceDTO_Tests.swift index 689e319ec0b..cf555407264 100644 --- a/Tests/StreamChatTests/Database/DTOs/DeviceDTO_Tests.swift +++ b/Tests/StreamChatTests/Database/DTOs/DeviceDTO_Tests.swift @@ -21,7 +21,7 @@ final class DeviceDTO_Tests: XCTestCase { } func test_deviceListPayload_isStoredAndLoadedFromDB() throws { - let dummyDevices = DeviceListPayload.dummy + let dummyDevices = ListDevicesResponse.dummy() try database.writeSynchronously { (session) in // Save a current user to db for testing @@ -41,4 +41,36 @@ final class DeviceDTO_Tests: XCTestCase { XCTAssertEqual(sortedCurrentUserDevices?.first?.id, sortedDummyDevices.first?.id) XCTAssertEqual(sortedCurrentUserDevices?.first?.createdAt, sortedDummyDevices.first?.createdAt) } + + func test_deviceAllFields_areStoredAndLoadedFromDB() throws { + let device = Device( + createdAt: .unique, + disabled: true, + disabledReason: "spam", + hardwareId: "hw-1", + id: .unique, + pushProvider: "firebase", + pushProviderName: "my-fcm", + userId: .unique, + voip: true + ) + + try database.writeSynchronously { (session) in + try session.saveCurrentUser(payload: self.dummyCurrentUser) + try session.saveCurrentUserDevices([device]) + } + + let loadedCurrentUser: CurrentChatUser? = try database.viewContext.currentUser?.asModel() + let loadedDevice = loadedCurrentUser?.devices.first + + XCTAssertEqual(loadedDevice?.id, device.id) + XCTAssertEqual(loadedDevice?.createdAt, device.createdAt) + XCTAssertEqual(loadedDevice?.disabled, device.disabled) + XCTAssertEqual(loadedDevice?.disabledReason, device.disabledReason) + XCTAssertEqual(loadedDevice?.hardwareId, device.hardwareId) + XCTAssertEqual(loadedDevice?.pushProvider, device.pushProvider) + XCTAssertEqual(loadedDevice?.pushProviderName, device.pushProviderName) + XCTAssertEqual(loadedDevice?.userId, device.userId) + XCTAssertEqual(loadedDevice?.voip, device.voip) + } } diff --git a/Tests/StreamChatTests/Database/DTOs/UserDTO_Tests.swift b/Tests/StreamChatTests/Database/DTOs/UserDTO_Tests.swift index c6691b41ac8..6d4d4eb33fd 100644 --- a/Tests/StreamChatTests/Database/DTOs/UserDTO_Tests.swift +++ b/Tests/StreamChatTests/Database/DTOs/UserDTO_Tests.swift @@ -326,7 +326,7 @@ final class UserDTO_Tests: XCTestCase { userId: userId, role: .admin, extraData: [:], - devices: [DevicePayload.dummy], + devices: [Device.dummy()], mutedUsers: [ .dummy(userId: .unique) ] diff --git a/Tests/StreamChatTests/StateLayer/ConnectedUser_Tests.swift b/Tests/StreamChatTests/StateLayer/ConnectedUser_Tests.swift index 49090c158e9..6a9f1627bce 100644 --- a/Tests/StreamChatTests/StateLayer/ConnectedUser_Tests.swift +++ b/Tests/StreamChatTests/StateLayer/ConnectedUser_Tests.swift @@ -205,7 +205,7 @@ final class ConnectedUser_Tests: XCTestCase { } private func currentUserPayload(name: String = "InitialName", deviceCount: Int = 0, role: UserRole = .admin) -> CurrentUserPayload { - let devices = (0..