diff --git a/Modules/Domain/MEGADomain/Sources/MEGADomain/Entity/User/UserAttributeErrorEntity.swift b/Modules/Domain/MEGADomain/Sources/MEGADomain/Entity/User/UserAttributeErrorEntity.swift new file mode 100644 index 0000000000..a48c675aee --- /dev/null +++ b/Modules/Domain/MEGADomain/Sources/MEGADomain/Entity/User/UserAttributeErrorEntity.swift @@ -0,0 +1,3 @@ +public enum UserAttributeErrorEntity: Error { + case attributeNotFound +} diff --git a/Modules/Domain/MEGADomain/Sources/MEGADomain/RepositoryProtocol/User/UserAttributeRepositoryProtocol.swift b/Modules/Domain/MEGADomain/Sources/MEGADomain/RepositoryProtocol/User/UserAttributeRepositoryProtocol.swift index fd918d707a..cbfe0d71d4 100644 --- a/Modules/Domain/MEGADomain/Sources/MEGADomain/RepositoryProtocol/User/UserAttributeRepositoryProtocol.swift +++ b/Modules/Domain/MEGADomain/Sources/MEGADomain/RepositoryProtocol/User/UserAttributeRepositoryProtocol.swift @@ -13,6 +13,12 @@ public protocol UserAttributeRepositoryProtocol: Sendable { /// - object: Encodable object to be stored as a JSON string. func mergeUserAttribute(_ attribute: UserAttributeEntity, key: String, object: Encodable) async throws func updateUserAttribute(_ attribute: UserAttributeEntity, key: String, value: String) async throws + + /// Fetches dictionary structure under the given attribute. If the attribute does not exist or was never set before, it will throw an error. If a optional value has been set previously it will return the value stored under the attribute. + /// - Parameter attribute: UserAttributeEntity location of where the value will be fetched from . + /// - Returns: Optional [String: String] dictionary stored at the attribute, if attribute was never set previously it will throw. + /// + /// - Throws: UserAttributeErrorEntity.attributeNotFound if the attribute has never set before. func userAttribute(for attribute: UserAttributeEntity) async throws -> [String: String]? /// Retrieve the decodable object from the associated user attribute for the given key. If the object for the attribute and key does not exist it will throw an error. diff --git a/Modules/Repository/MEGASDKRepo/Sources/MEGASDKRepo/Repository/User/UserAttributeRepository.swift b/Modules/Repository/MEGASDKRepo/Sources/MEGASDKRepo/Repository/User/UserAttributeRepository.swift index 83742b9479..3b0fa4fbfb 100644 --- a/Modules/Repository/MEGASDKRepo/Sources/MEGASDKRepo/Repository/User/UserAttributeRepository.swift +++ b/Modules/Repository/MEGASDKRepo/Sources/MEGASDKRepo/Repository/User/UserAttributeRepository.swift @@ -33,7 +33,7 @@ public struct UserAttributeRepository: UserAttributeRepositoryProtocol { public func mergeUserAttribute(_ attribute: UserAttributeEntity, key: String, object: Encodable) async throws { let supportedModelDictionary = try object.convertToDictionary() - let currentAppsPreference = try await userAttribute(for: attribute) + let currentAppsPreference = try? await userAttribute(for: attribute) let contentToSave: [String: Any] = if let existingEncodedString = currentAppsPreference?[key], existingEncodedString.isNotEmpty, @@ -74,8 +74,14 @@ public struct UserAttributeRepository: UserAttributeRepositoryProtocol { switch result { case .success(let request): completion(.success(request.megaStringDictionary)) - case .failure: - completion(.failure(GenericErrorEntity())) + case .failure(let error): + let mappedError: any Error = switch error.type { + case .apiERange: + UserAttributeErrorEntity.attributeNotFound + default: + GenericErrorEntity() + } + completion(.failure(mappedError)) } }) }) diff --git a/Modules/Repository/MEGASDKRepo/Sources/MEGASDKRepoMock/SDK/MockSdk.swift b/Modules/Repository/MEGASDKRepo/Sources/MEGASDKRepoMock/SDK/MockSdk.swift index 7118a8e116..b94e146d33 100644 --- a/Modules/Repository/MEGASDKRepo/Sources/MEGASDKRepoMock/SDK/MockSdk.swift +++ b/Modules/Repository/MEGASDKRepo/Sources/MEGASDKRepoMock/SDK/MockSdk.swift @@ -48,7 +48,8 @@ public final class MockSdk: MEGASdk { private var _lastReadNotificationId: Int32 private var _isNodeInheritingSensitivity: Bool private var _hasVersionsForNode: Bool - + private let setUserAttributeTypeMegaSetError: (MEGAUserAttribute) -> MEGAErrorType + public private(set) var sendEvent_Calls = [( eventType: Int, message: String, @@ -128,7 +129,8 @@ public final class MockSdk: MEGASdk { enabledNotificationIdList: MEGAIntegerList? = nil, lastReadNotificationId: Int32 = 0, isNodeInheritingSensitivity: Bool = false, - hasVersionsForNode: Bool = false + hasVersionsForNode: Bool = false, + setUserAttributeTypeMegaSetError: @escaping (MEGAUserAttribute) -> MEGAErrorType = { _ in .apiOk } ) { self.nodes = nodes self.rubbishNodes = rubbishNodes @@ -175,6 +177,7 @@ public final class MockSdk: MEGASdk { _lastReadNotificationId = lastReadNotificationId _isNodeInheritingSensitivity = isNodeInheritingSensitivity _hasVersionsForNode = hasVersionsForNode + self.setUserAttributeTypeMegaSetError = setUserAttributeTypeMegaSetError super.init() } @@ -574,7 +577,7 @@ public final class MockSdk: MEGASdk { return } - delegate.onRequestFinish?(self, request: MockRequest(handle: 1), error: MockError(errorType: megaSetError)) + delegate.onRequestFinish?(self, request: MockRequest(handle: 1), error: MockError(errorType: setUserAttributeTypeMegaSetError(type))) } public override func deviceId() -> String? { diff --git a/Modules/Repository/MEGASDKRepo/Tests/MEGASDKRepoTests/UserAttributeRepositoryTests.swift b/Modules/Repository/MEGASDKRepo/Tests/MEGASDKRepoTests/UserAttributeRepositoryTests.swift index d1785ee3b8..fd9d1d5c26 100644 --- a/Modules/Repository/MEGASDKRepo/Tests/MEGASDKRepoTests/UserAttributeRepositoryTests.swift +++ b/Modules/Repository/MEGASDKRepo/Tests/MEGASDKRepoTests/UserAttributeRepositoryTests.swift @@ -101,8 +101,35 @@ final class UserAttributeRepositoryTests: XCTestCase { XCTAssertEqual(sdk.contentConsumptionPreferences[key]?.sorted(), try XCTUnwrap(targetJson).sorted()) } - private func sut(contentConsumptionPreferences: [String: String] = [:]) -> (UserAttributeRepository, MockSdk) { - let sdk = MockSdk(contentConsumptionPreferences: contentConsumptionPreferences) + func testMergeUserAttribute_withErrorWhenRetrievingAttribute_shouldSave() async throws { + let targetJson = """ + {"ios":{"timeline":{"mediaType":"videos","location":"cloudDrive","usePreference":false},"sensitives":{"showHiddenNodes":false}},"sensitives":{"onboarded":false}} + """.trim + let key = ContentConsumptionKeysEntity.key + let (sut, sdk) = sut(megaSetError: .apiERange) + let objectToSave = ContentConsumptionEntity( + ios: .init( + timeline: .init(mediaType: .videos, location: .cloudDrive, usePreference: false), + sensitives: .init(showHiddenNodes: false)), + sensitives: .init(onboarded: false)) + + try await sut.mergeUserAttribute( + .contentConsumptionPreferences, + key: ContentConsumptionKeysEntity.key, + object: objectToSave) + + XCTAssertEqual(sdk.contentConsumptionPreferences[key]?.sorted(), try XCTUnwrap(targetJson).sorted()) + } + + private func sut( + contentConsumptionPreferences: [String: String] = [:], + megaSetError: MEGAErrorType = .apiOk, + setUserAttributeTypeMegaSetError: @escaping (MEGAUserAttribute) -> MEGAErrorType = { _ in .apiOk } + ) -> (UserAttributeRepository, MockSdk) { + let sdk = MockSdk( + megaSetError: megaSetError, + contentConsumptionPreferences: contentConsumptionPreferences, + setUserAttributeTypeMegaSetError: setUserAttributeTypeMegaSetError) return (UserAttributeRepository(sdk: sdk), sdk) } }