Files

492 lines
18 KiB
Swift

// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import Combine
import SessionUIKit
import SessionUtilitiesKit
import GRDB
@testable import SessionMessagingKit
class MockLibSessionCache: Mock<LibSessionCacheType>, LibSessionCacheType {
var userSessionId: SessionId { mock() }
var isEmpty: Bool { mock() }
var allDumpSessionIds: Set<SessionId> { mock() }
var proConfig: SessionPro.ProConfig? { mock() }
var proAccessExpiryTimestampMs: UInt64 { mock() }
// MARK: - State Management
func loadState(_ db: ObservingDatabase, requestId: String?) {
mockNoReturn(args: [requestId], untrackedArgs: [db])
}
func loadDefaultStateFor(
variant: ConfigDump.Variant,
sessionId: SessionId,
userEd25519SecretKey: [UInt8],
groupEd25519SecretKey: [UInt8]?
) {
mockNoReturn(args: [variant, sessionId, userEd25519SecretKey, groupEd25519SecretKey])
}
func loadState(
for variant: ConfigDump.Variant,
sessionId: SessionId,
userEd25519SecretKey: [UInt8],
groupEd25519SecretKey: [UInt8]?,
cachedData: Data?
) throws -> LibSession.Config {
return try mockThrowing(args: [variant, sessionId, userEd25519SecretKey, groupEd25519SecretKey, cachedData])
}
func hasConfig(for variant: ConfigDump.Variant, sessionId: SessionId) -> Bool {
return mock(args: [variant, sessionId])
}
func config(for variant: ConfigDump.Variant, sessionId: SessionId) -> LibSession.Config? {
return mock(args: [variant, sessionId])
}
func setConfig(for variant: ConfigDump.Variant, sessionId: SessionId, to config: LibSession.Config) {
mockNoReturn(args: [variant, sessionId, config])
}
func removeConfigs(for sessionId: SessionId) {
mockNoReturn(args: [sessionId])
}
func createDump(
config: LibSession.Config?,
for variant: ConfigDump.Variant,
sessionId: SessionId,
timestampMs: Int64
) throws -> ConfigDump? {
return try mockThrowing(args: [config, variant, sessionId, timestampMs])
}
func stateDescriptionForLogs() -> String { return mock() }
// MARK: - Pushes
func syncAllPendingPushes(_ db: ObservingDatabase) {
mockNoReturn(untrackedArgs: [db])
}
func withCustomBehaviour(_ behaviour: LibSession.CacheBehaviour, for sessionId: SessionId, variant: ConfigDump.Variant?, change: @escaping () throws -> ()) throws {
try mockThrowingNoReturn(args: [behaviour, sessionId, variant], untrackedArgs: [change])
}
func performAndPushChange(
_ db: ObservingDatabase,
for variant: ConfigDump.Variant,
sessionId: SessionId,
change: @escaping (LibSession.Config?) throws -> ()
) throws {
try mockThrowingNoReturn(args: [variant, sessionId], untrackedArgs: [db, change])
}
func perform(
for variant: ConfigDump.Variant,
sessionId: SessionId,
change: @escaping (LibSession.Config?) throws -> ()
) throws -> LibSession.Mutation {
return try mockThrowing(args: [variant, sessionId], untrackedArgs: [change])
}
func pendingPushes(swarmPublicKey: String) throws -> LibSession.PendingPushes {
return mock(args: [swarmPublicKey])
}
func createDumpMarkingAsPushed(
data: [(pushData: LibSession.PendingPushes.PushData, hash: String?)],
sentTimestamp: Int64,
swarmPublicKey: String
) throws -> [ConfigDump] {
return try mockThrowing(args: [data, sentTimestamp, swarmPublicKey])
}
func addEvent(_ event: ObservedEvent) {
mockNoReturn(args: [event])
}
// MARK: - Config Message Handling
func configNeedsDump(_ config: LibSession.Config?) -> Bool {
return mock(args: [config])
}
func activeHashes(for swarmPublicKey: String) -> [String] {
return mock(args: [swarmPublicKey])
}
func mergeConfigMessages(
swarmPublicKey: String,
messages: [ConfigMessageReceiveJob.Details.MessageInfo]
) throws -> [ConfigDump.Variant: Int64] {
return try mockThrowing(args: [swarmPublicKey, messages])
}
func handleConfigMessages(
_ db: ObservingDatabase,
swarmPublicKey: String,
messages: [ConfigMessageReceiveJob.Details.MessageInfo]
) throws {
try mockThrowingNoReturn(args: [swarmPublicKey, messages], untrackedArgs: [db])
}
// MARK: - State Access
var displayName: String? { mock() }
func has(_ key: Setting.EnumKey) -> Bool {
return mock(generics: [Setting.EnumKey.self], args: [key])
}
func get(_ key: Setting.BoolKey) -> Bool {
return mock(generics: [Bool.self], args: [key])
}
func get<T>(_ key: Setting.EnumKey) -> T? where T : LibSessionConvertibleEnum {
return mock(generics: [T.self], args: [key])
}
func set(_ key: Setting.BoolKey, _ value: Bool?) {
mockNoReturn(generics: [Bool.self], args: [key, value])
}
func set<T>(_ key: Setting.EnumKey, _ value: T?) where T : LibSessionConvertibleEnum {
mockNoReturn(generics: [T.self], args: [key, value])
}
func updateProfile(
displayName: Update<String>,
displayPictureUrl: Update<String?>,
displayPictureEncryptionKey: Update<Data?>,
proProfileFeatures: Update<SessionPro.ProfileFeatures>,
isReuploadProfilePicture: Bool
) throws {
try mockThrowingNoReturn(args: [displayName, displayPictureUrl, displayPictureEncryptionKey, proProfileFeatures, isReuploadProfilePicture])
}
func updateProConfig(proConfig: SessionPro.ProConfig) {
mockNoReturn(args: [proConfig])
}
func removeProConfig() {
mockNoReturn()
}
func updateProAccessExpiryTimestampMs(_ proAccessExpiryTimestampMs: UInt64) {
mockNoReturn(args: [proAccessExpiryTimestampMs])
}
func canPerformChange(
threadId: String,
threadVariant: SessionThread.Variant,
changeTimestampMs: Int64
) -> Bool {
return mock(args: [threadId, threadVariant, changeTimestampMs])
}
func conversationInConfig(
threadId: String,
threadVariant: SessionThread.Variant,
visibleOnly: Bool,
openGroupUrlInfo: LibSession.OpenGroupUrlInfo?
) -> Bool {
return mock(args: [threadId, threadVariant, visibleOnly, openGroupUrlInfo])
}
func conversationDisplayName(
threadId: String,
threadVariant: SessionThread.Variant,
contactProfile: Profile?,
visibleMessage: VisibleMessage?,
openGroupName: String?,
openGroupUrlInfo: LibSession.OpenGroupUrlInfo?
) -> String {
return mock(args: [threadId, threadVariant, contactProfile, visibleMessage, openGroupName, openGroupUrlInfo])
}
func conversationLastRead(
threadId: String,
threadVariant: SessionThread.Variant,
openGroupUrlInfo: LibSession.OpenGroupUrlInfo?
) -> Int64? {
return mock(args: [threadId, threadVariant, openGroupUrlInfo])
}
func proProofMetadata(threadId: String) -> LibSession.ProProofMetadata? {
return mock(args: [threadId])
}
func isMessageRequest(
threadId: String,
threadVariant: SessionThread.Variant
) -> Bool {
return mock(args: [threadId, threadVariant])
}
func pinnedPriority(
threadId: String,
threadVariant: SessionThread.Variant,
openGroupUrlInfo: LibSession.OpenGroupUrlInfo?
) -> Int32 {
return mock(args: [threadId, threadVariant, openGroupUrlInfo])
}
func notificationSettings(
threadId: String?,
threadVariant: SessionThread.Variant,
openGroupUrlInfo: LibSession.OpenGroupUrlInfo?
) -> Preferences.NotificationSettings {
return mock(args: [threadId, threadVariant, openGroupUrlInfo])
}
func disappearingMessagesConfig(
threadId: String,
threadVariant: SessionThread.Variant
) -> DisappearingMessagesConfiguration? {
return mock(args: [threadId, threadVariant])
}
func isContactBlocked(contactId: String) -> Bool {
return mock(args: [contactId])
}
func isContactApproved(contactId: String) -> Bool {
return mock(args: [contactId])
}
func profile(
contactId: String,
threadId: String?,
threadVariant: SessionThread.Variant?,
visibleMessage: VisibleMessage?
) -> Profile? {
return mock(args: [contactId, threadId, threadVariant, visibleMessage])
}
func displayPictureUrl(threadId: String, threadVariant: SessionThread.Variant) -> String? {
return mock(args: [threadId, threadVariant])
}
func hasCredentials(groupSessionId: SessionId) -> Bool {
return mock(args: [groupSessionId])
}
func secretKey(groupSessionId: SessionId) -> [UInt8]? {
return mock(args: [groupSessionId])
}
func latestGroupKey(groupSessionId: SessionId) throws -> [UInt8] {
return try mockThrowing(args: [groupSessionId])
}
func allActiveGroupKeys(groupSessionId: SessionId) throws -> [[UInt8]] {
return try mockThrowing(args: [groupSessionId])
}
func isAdmin(groupSessionId: SessionId) -> Bool {
return mock(args: [groupSessionId])
}
func loadAdminKey(
groupIdentitySeed: Data,
groupSessionId: SessionId
) throws {
try mockThrowingNoReturn(args: [groupIdentitySeed, groupSessionId])
}
func markAsInvited(groupSessionIds: [String]) throws {
try mockThrowingNoReturn(args: [groupSessionIds])
}
func markAsKicked(groupSessionIds: [String]) throws {
try mockThrowingNoReturn(args: [groupSessionIds])
}
func wasKickedFromGroup(groupSessionId: SessionId) -> Bool {
return mock(args: [groupSessionId])
}
func groupName(groupSessionId: SessionId) -> String? {
return mock(args: [groupSessionId])
}
func groupIsDestroyed(groupSessionId: SessionId) -> Bool {
return mock(args: [groupSessionId])
}
func groupInfo(for groupIds: Set<String>) -> [LibSession.GroupInfo?] {
return mock(args: [groupIds])
}
func groupDeleteBefore(groupSessionId: SessionId) -> TimeInterval? {
return mock(args: [groupSessionId])
}
func groupDeleteAttachmentsBefore(groupSessionId: SessionId) -> TimeInterval? {
return mock(args: [groupSessionId])
}
func authData(groupSessionId: SessionId) -> GroupAuthData {
return mock(args: [groupSessionId])
}
}
// MARK: - Convenience
extension Mock where T == LibSessionCacheType {
func defaultInitialSetup(configs: [ConfigDump.Variant: LibSession.Config?] = [:]) {
let userSessionId: SessionId = SessionId(.standard, hex: TestConstants.publicKey)
configs.forEach { key, value in
switch value {
case .none: break
case .some(let config): self.when { $0.config(for: key, sessionId: .any) }.thenReturn(config)
}
}
self.when { $0.isEmpty }.thenReturn(false)
self.when { $0.userSessionId }.thenReturn(userSessionId)
self.when { $0.setConfig(for: .any, sessionId: .any, to: .any) }.thenReturn(())
self.when { $0.removeConfigs(for: .any) }.thenReturn(())
self.when { $0.hasConfig(for: .any, sessionId: .any) }.thenReturn(true)
self
.when {
$0.loadDefaultStateFor(
variant: .any,
sessionId: .any,
userEd25519SecretKey: .any,
groupEd25519SecretKey: .any
)
}
.thenReturn(())
self
.when { try $0.pendingPushes(swarmPublicKey: .any) }
.thenReturn(LibSession.PendingPushes())
self.when { $0.configNeedsDump(.any) }.thenReturn(false)
self.when { $0.activeHashes(for: .any) }.thenReturn([])
self
.when { try $0.createDump(config: .any, for: .any, sessionId: .any, timestampMs: .any) }
.thenReturn(nil)
self
.when { try $0.withCustomBehaviour(.any, for: .any, variant: .any, change: { }) }
.then { args, untrackedArgs in
let callback: (() throws -> Void)? = (untrackedArgs[test: 0] as? () throws -> Void)
try? callback?()
}
.thenReturn(())
self
.when { try $0.performAndPushChange(.any, for: .any, sessionId: .any, change: { _ in }) }
.then { args, untrackedArgs in
let callback: ((LibSession.Config?) throws -> Void)? = (untrackedArgs[test: 1] as? (LibSession.Config?) throws -> Void)
switch configs[(args[test: 0] as? ConfigDump.Variant ?? .invalid)] {
case .none: break
case .some(let config): try? callback?(config)
}
}
.thenReturn(())
self
.when { try $0.perform(for: .any, sessionId: .any, change: { _ in }) }
.then { args, untrackedArgs in
let callback: ((LibSession.Config?) throws -> Void)? = (untrackedArgs[test: 0] as? (LibSession.Config?) throws -> Void)
switch configs[(args[test: 0] as? ConfigDump.Variant ?? .invalid)] {
case .none: break
case .some(let config): try? callback?(config)
}
}
.thenReturn(nil)
self
.when {
try $0.createDumpMarkingAsPushed(
data: .any,
sentTimestamp: .any,
swarmPublicKey: .any
)
}
.thenReturn([])
self
.when {
$0.conversationInConfig(
threadId: .any,
threadVariant: .any,
visibleOnly: .any,
openGroupUrlInfo: .any
)
}
.thenReturn(true)
self
.when {
$0.conversationLastRead(
threadId: .any,
threadVariant: .any,
openGroupUrlInfo: .any
)
}
.thenReturn(nil)
self
.when { $0.canPerformChange(threadId: .any, threadVariant: .any, changeTimestampMs: .any) }
.thenReturn(true)
self
.when { $0.isMessageRequest(threadId: .any, threadVariant: .any) }
.thenReturn(false)
self
.when { $0.pinnedPriority(threadId: .any, threadVariant: .any, openGroupUrlInfo: .any) }
.thenReturn(LibSession.defaultNewThreadPriority)
self
.when { $0.disappearingMessagesConfig(threadId: .any, threadVariant: .any) }
.thenReturn(nil)
self.when { $0.isContactBlocked(contactId: .any) }.thenReturn(false)
self
.when { $0.profile(contactId: .any, threadId: .any, threadVariant: .any, visibleMessage: .any) }
.thenReturn(
Profile(
id: "TestProfileId",
name: "TestProfileName",
nickname: nil,
displayPictureUrl: nil,
displayPictureEncryptionKey: nil,
profileLastUpdated: nil,
blocksCommunityMessageRequests: nil,
proFeatures: .none,
proExpiryUnixTimestampMs: 0,
proGenIndexHashHex: nil
)
)
self.when { $0.hasCredentials(groupSessionId: .any) }.thenReturn(true)
self.when { $0.secretKey(groupSessionId: .any) }.thenReturn(nil)
self.when { $0.isAdmin(groupSessionId: .any) }.thenReturn(true)
self.when { try $0.loadAdminKey(groupIdentitySeed: .any, groupSessionId: .any) }.thenReturn(())
self.when { try $0.markAsKicked(groupSessionIds: .any) }.thenReturn(())
self.when { try $0.markAsInvited(groupSessionIds: .any) }.thenReturn(())
self.when { $0.wasKickedFromGroup(groupSessionId: .any) }.thenReturn(false)
self.when { $0.groupName(groupSessionId: .any) }.thenReturn("TestGroupName")
self.when { $0.groupIsDestroyed(groupSessionId: .any) }.thenReturn(false)
self.when { $0.groupInfo(for: .any) }.thenReturn([])
self.when { $0.groupDeleteBefore(groupSessionId: .any) }.thenReturn(nil)
self.when { $0.groupDeleteAttachmentsBefore(groupSessionId: .any) }.thenReturn(nil)
self.when { $0.authData(groupSessionId: .any) }.thenReturn(GroupAuthData(groupIdentityPrivateKey: nil, authData: nil))
self.when { $0.get(.any) }.thenReturn(false)
self.when { $0.get(.any) }.thenReturn(MockLibSessionConvertible.mock)
self.when { $0.get(.any) }.thenReturn(Preferences.Sound.defaultNotificationSound)
self.when { $0.get(.any) }.thenReturn(Preferences.NotificationPreviewType.defaultPreviewType)
self.when { $0.get(.any) }.thenReturn(Theme.defaultTheme)
self.when { $0.get(.any) }.thenReturn(Theme.PrimaryColor.defaultPrimaryColor)
self.when { $0.set(.any, true) }.thenReturn(())
self.when { $0.set(.any, false) }.thenReturn(())
self.when { $0.set(.defaultNotificationSound, Preferences.Sound.mock) }.thenReturn(())
self.when { $0.set(.preferencesNotificationPreviewType, Preferences.NotificationPreviewType.mock) }.thenReturn(())
self.when { $0.set(.theme, Theme.mock) }.thenReturn(())
self.when { $0.set(.themePrimaryColor, Theme.PrimaryColor.mock) }.thenReturn(())
self.when { $0.addEvent(.any) }.thenReturn(())
self
.when { $0.displayPictureUrl(threadId: .any, threadVariant: .any) }
.thenReturn(nil)
}
}