Reworked test DSL to speed up build time and added more tests

Fixed a bug where the group invite message could be incorrectly added in some cases
pull/941/head
Morgan Pretty 1 year ago
parent 315d78b500
commit 3d60757c40

@ -442,8 +442,6 @@
E984778319BDF24A7ADF100A /* Pods_GlobalDependencies_SessionUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E517F8611575B37B76BCC54 /* Pods_GlobalDependencies_SessionUIKit.framework */; };
FC3BD9881A30A790005B96BB /* Social.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC3BD9871A30A790005B96BB /* Social.framework */; };
FCB11D8C1A129A76002F93FB /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FCB11D8B1A129A76002F93FB /* CoreMedia.framework */; };
FD078E4827E02561000769AF /* CommonMockedExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD078E4727E02561000769AF /* CommonMockedExtensions.swift */; };
FD078E4927E02576000769AF /* CommonMockedExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD078E4727E02561000769AF /* CommonMockedExtensions.swift */; };
FD078E4D27E17156000769AF /* MockOGMCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD078E4C27E17156000769AF /* MockOGMCache.swift */; };
FD078E5427E197CA000769AF /* OpenGroupManagerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC2909D27D85751005DAE71 /* OpenGroupManagerSpec.swift */; };
FD0969F92A69FFE700C5C365 /* Mocked.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0969F82A69FFE700C5C365 /* Mocked.swift */; };
@ -542,7 +540,6 @@
FD23EA5C28ED00F80058676E /* Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC290A527D860CE005DAE71 /* Mock.swift */; };
FD23EA5D28ED00FA0058676E /* TestConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD83B9BD27CF2243005E1583 /* TestConstants.swift */; };
FD23EA5E28ED00FD0058676E /* NimbleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC290A727D9B46D005DAE71 /* NimbleExtensions.swift */; };
FD23EA5F28ED00FF0058676E /* CommonMockedExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD078E4727E02561000769AF /* CommonMockedExtensions.swift */; };
FD23EA6128ED0B260058676E /* CombineExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23EA6028ED0B260058676E /* CombineExtensions.swift */; };
FD23EA6228ED0B260058676E /* CombineExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23EA6028ED0B260058676E /* CombineExtensions.swift */; };
FD23EA6328ED0B260058676E /* CombineExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23EA6028ED0B260058676E /* CombineExtensions.swift */; };
@ -665,6 +662,11 @@
FD47E0B82AA6E62600A55E41 /* Request+OpenGroupAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD47E0B62AA6E5FF00A55E41 /* Request+OpenGroupAPI.swift */; };
FD47E0BA2AA6EBA200A55E41 /* Request+PushNotificationAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD47E0B92AA6EBA200A55E41 /* Request+PushNotificationAPI.swift */; };
FD47E0C02AA83D7300A55E41 /* SwarmDrainBehaviour.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD47E0BF2AA83D7300A55E41 /* SwarmDrainBehaviour.swift */; };
FD49E2462B05C1D500FFBBB5 /* MockKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD49E2452B05C1D500FFBBB5 /* MockKeychain.swift */; };
FD49E2472B05C1D500FFBBB5 /* MockKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD49E2452B05C1D500FFBBB5 /* MockKeychain.swift */; };
FD49E2482B05C1D500FFBBB5 /* MockKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD49E2452B05C1D500FFBBB5 /* MockKeychain.swift */; };
FD49E2492B05C1D500FFBBB5 /* MockKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD49E2452B05C1D500FFBBB5 /* MockKeychain.swift */; };
FD49E24C2B05D00900FFBBB5 /* MessageReceiverGroupsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD49E24A2B05D00900FFBBB5 /* MessageReceiverGroupsSpec.swift */; };
FD4B200E283492210034334B /* InsetLockableTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD4B200D283492210034334B /* InsetLockableTableView.swift */; };
FD4C4E9C2B02E2A300C72199 /* DisplayPictureError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD4C4E9B2B02E2A300C72199 /* DisplayPictureError.swift */; };
FD4C4EA22B03093200C72199 /* GRDBExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD4C4E9F2B0308FD00C72199 /* GRDBExtensions.swift */; };
@ -840,7 +842,6 @@
FDB5DB122A981FA8002C8721 /* NimbleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC290A727D9B46D005DAE71 /* NimbleExtensions.swift */; };
FDB5DB142A981FAE002C8721 /* CombineExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23EA6028ED0B260058676E /* CombineExtensions.swift */; };
FDB5DB152A981FB0002C8721 /* SynchronousStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD2AAAEF28ED57B500A49611 /* SynchronousStorage.swift */; };
FDB5DB162A9821DF002C8721 /* CommonMockedExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD078E4727E02561000769AF /* CommonMockedExtensions.swift */; };
FDB6A87C2AD75B7F002D4F96 /* PhotosUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FDB6A87B2AD75B7F002D4F96 /* PhotosUI.framework */; };
FDB7400B28EB99A70094D718 /* TimeInterval+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDB7400A28EB99A70094D718 /* TimeInterval+Utilities.swift */; };
FDB7400D28EBEC240094D718 /* DateHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDB7400C28EBEC240094D718 /* DateHeaderCell.swift */; };
@ -1714,7 +1715,6 @@
F60C5B6CD14329816B0E8CC0 /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.app store release.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.app store release.xcconfig"; sourceTree = "<group>"; };
FC3BD9871A30A790005B96BB /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; };
FCB11D8B1A129A76002F93FB /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
FD078E4727E02561000769AF /* CommonMockedExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonMockedExtensions.swift; sourceTree = "<group>"; };
FD078E4C27E17156000769AF /* MockOGMCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockOGMCache.swift; sourceTree = "<group>"; };
FD0969F82A69FFE700C5C365 /* Mocked.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mocked.swift; sourceTree = "<group>"; };
FD09796A27F6C67500936362 /* Failable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Failable.swift; sourceTree = "<group>"; };
@ -1892,6 +1892,8 @@
FD47E0B62AA6E5FF00A55E41 /* Request+OpenGroupAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Request+OpenGroupAPI.swift"; sourceTree = "<group>"; };
FD47E0B92AA6EBA200A55E41 /* Request+PushNotificationAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Request+PushNotificationAPI.swift"; sourceTree = "<group>"; };
FD47E0BF2AA83D7300A55E41 /* SwarmDrainBehaviour.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwarmDrainBehaviour.swift; sourceTree = "<group>"; };
FD49E2452B05C1D500FFBBB5 /* MockKeychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockKeychain.swift; sourceTree = "<group>"; };
FD49E24A2B05D00900FFBBB5 /* MessageReceiverGroupsSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageReceiverGroupsSpec.swift; sourceTree = "<group>"; };
FD4B200D283492210034334B /* InsetLockableTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsetLockableTableView.swift; sourceTree = "<group>"; };
FD4C4E9B2B02E2A300C72199 /* DisplayPictureError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayPictureError.swift; sourceTree = "<group>"; };
FD4C4E9F2B0308FD00C72199 /* GRDBExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GRDBExtensions.swift; sourceTree = "<group>"; };
@ -4128,9 +4130,10 @@
FD3C906B27E43C2400CD579F /* Sending & Receiving */ = {
isa = PBXGroup;
children = (
FDF01FAA2A9EBAD500CAF969 /* MessageSenderGroupsSpec.swift */,
FD3C907027E445E500CD579F /* MessageReceiverDecryptionSpec.swift */,
7B6ACADD2A32D3A9009AFB73 /* MessageReceiverSpec.swift */,
FD3C907027E445E500CD579F /* MessageReceiverDecryptionSpec.swift */,
FD49E24A2B05D00900FFBBB5 /* MessageReceiverGroupsSpec.swift */,
FDF01FAA2A9EBAD500CAF969 /* MessageSenderGroupsSpec.swift */,
FD3C906C27E43C4B00CD579F /* MessageSenderEncryptionSpec.swift */,
);
path = "Sending & Receiving";
@ -4329,13 +4332,13 @@
FD3FAB6A2AF1B27800DC5421 /* MockFileManager.swift */,
FDFD645C27F273F300808CA1 /* MockGeneralCache.swift */,
FD83B9D127D59495005E1583 /* MockUserDefaults.swift */,
FD49E2452B05C1D500FFBBB5 /* MockKeychain.swift */,
FD23CE312A67C38D0000B97C /* MockNetwork.swift */,
FD96F3A629DBD43D00401309 /* MockJobRunner.swift */,
FD83B9BD27CF2243005E1583 /* TestConstants.swift */,
FD6531892AA025C500DFEEAA /* TestDependencies.swift */,
FD9DD2702A72516D00ECB68E /* TestExtensions.swift */,
FDC290A727D9B46D005DAE71 /* NimbleExtensions.swift */,
FD078E4727E02561000769AF /* CommonMockedExtensions.swift */,
FD23EA6028ED0B260058676E /* CombineExtensions.swift */,
FD4C4E9F2B0308FD00C72199 /* GRDBExtensions.swift */,
FD2AAAEF28ED57B500A49611 /* SynchronousStorage.swift */,
@ -6773,7 +6776,6 @@
FD23CE332A67C4D90000B97C /* MockNetwork.swift in Sources */,
FD71161528D00D6700B47552 /* ThreadDisappearingMessagesViewModelSpec.swift in Sources */,
FD23EA5E28ED00FD0058676E /* NimbleExtensions.swift in Sources */,
FD23EA5F28ED00FF0058676E /* CommonMockedExtensions.swift in Sources */,
FD23EA5D28ED00FA0058676E /* TestConstants.swift in Sources */,
FD1936432ACBE11F004BCF0F /* CommonSMKMockExtensions.swift in Sources */,
FD71161A28D00E1100B47552 /* NotificationContentViewModelSpec.swift in Sources */,
@ -6788,6 +6790,7 @@
FD65318A2AA025C500DFEEAA /* TestDependencies.swift in Sources */,
FD2AAAED28ED3E1000A49611 /* MockGeneralCache.swift in Sources */,
FDB5DB0D2A981F9D002C8721 /* MockJobRunner.swift in Sources */,
FD49E2462B05C1D500FFBBB5 /* MockKeychain.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -6797,8 +6800,8 @@
files = (
FD4C4EA92B043A8800C72199 /* RequestSpec.swift in Sources */,
FD2AAAF228ED57B500A49611 /* SynchronousStorage.swift in Sources */,
FD078E4927E02576000769AF /* CommonMockedExtensions.swift in Sources */,
FD65318D2AA025C500DFEEAA /* TestDependencies.swift in Sources */,
FD49E2492B05C1D500FFBBB5 /* MockKeychain.swift in Sources */,
FD83B9BF27CF2294005E1583 /* TestConstants.swift in Sources */,
FDFBB7542A2023EB00CA7350 /* BencodeEncoderSpec.swift in Sources */,
FD9DD2732A72516D00ECB68E /* TestExtensions.swift in Sources */,
@ -6835,11 +6838,11 @@
buildActionMask = 2147483647;
files = (
FDB5DB062A981C67002C8721 /* PreparedRequestOnionRequestsSpec.swift in Sources */,
FD49E2482B05C1D500FFBBB5 /* MockKeychain.swift in Sources */,
FDB5DB082A981F8B002C8721 /* Mocked.swift in Sources */,
FD3765E22AD8F53B00DC1489 /* CommonSSKMockExtensions.swift in Sources */,
FDB5DB142A981FAE002C8721 /* CombineExtensions.swift in Sources */,
FD3765DF2AD8F03100DC1489 /* MockSnodeAPICache.swift in Sources */,
FDB5DB162A9821DF002C8721 /* CommonMockedExtensions.swift in Sources */,
FDB5DB112A981FA6002C8721 /* TestExtensions.swift in Sources */,
FDB5DB092A981F8D002C8721 /* MockCrypto.swift in Sources */,
FDAA167B2AC28E2F00DDBF77 /* SnodeRequestSpec.swift in Sources */,
@ -6874,7 +6877,6 @@
FD83B9C727CF3F10005E1583 /* CapabilitiesSpec.swift in Sources */,
FDC2909A27D71376005DAE71 /* NonceGeneratorSpec.swift in Sources */,
FD2AAAF128ED57B500A49611 /* SynchronousStorage.swift in Sources */,
FD078E4827E02561000769AF /* CommonMockedExtensions.swift in Sources */,
FD23CE2A2A6775660000B97C /* MockCrypto.swift in Sources */,
FDC2909827D7129B005DAE71 /* PersonalizationSpec.swift in Sources */,
FD078E4D27E17156000769AF /* MockOGMCache.swift in Sources */,
@ -6883,10 +6885,12 @@
FDC290A627D860CE005DAE71 /* Mock.swift in Sources */,
FDF01FAB2A9EBAD500CAF969 /* MessageSenderGroupsSpec.swift in Sources */,
FD3765DC2AD8CC8B00DC1489 /* MockPoller.swift in Sources */,
FD49E24C2B05D00900FFBBB5 /* MessageReceiverGroupsSpec.swift in Sources */,
FDC290A627D860CE005DAE71 /* Mock.swift in Sources */,
FDA1E83D29AC71A800C5C3BD /* SessionUtilSpec.swift in Sources */,
FD83B9C027CF2294005E1583 /* TestConstants.swift in Sources */,
FD65318B2AA025C500DFEEAA /* TestDependencies.swift in Sources */,
FD49E2472B05C1D500FFBBB5 /* MockKeychain.swift in Sources */,
FD3765E32AD8F56200DC1489 /* CommonSSKMockExtensions.swift in Sources */,
FDC4389A27BA002500C60D73 /* OpenGroupAPISpec.swift in Sources */,
FD23EA6228ED0B260058676E /* CombineExtensions.swift in Sources */,

@ -44,7 +44,7 @@ class DeveloperSettingsViewModel: SessionTableViewModel, NavigatableStateHolder,
case .database: return "Database"
}
}
//default: return .titleRoundedContent // .padding
var style: SessionTableSectionStyle {
switch self {
case .developerMode: return .padding
@ -486,6 +486,8 @@ class DeveloperSettingsViewModel: SessionTableViewModel, NavigatableStateHolder,
})
else { return }
SNLog("[DevSettings] Swapping to \(String(describing: updatedNetwork)), clearing data")
/// Stop all pollers
dependencies[singleton: .currentUserPoller].stopAllPollers()
dependencies[singleton: .groupsPoller].stopAllPollers()
@ -549,6 +551,8 @@ class DeveloperSettingsViewModel: SessionTableViewModel, NavigatableStateHolder,
_ = try ConfigDump.deleteAll(db)
}
SNLog("[DevSettings] Reloading state for \(String(describing: updatedNetwork))")
/// Reload the libSession state
SessionUtil.clearMemoryState(using: dependencies)
@ -570,6 +574,8 @@ class DeveloperSettingsViewModel: SessionTableViewModel, NavigatableStateHolder,
/// Re-sync the push tokens (if there are any)
SyncPushTokensJob.run(uploadOnlyIfStale: false)
SNLog("[DevSettings] Completed swap to \(String(describing: updatedNetwork))")
},
using: dependencies
)

@ -531,8 +531,8 @@ public extension ClosedGroup {
}
}
var infoString: String? {
guard let messageInfoData: Data = try? JSONEncoder().encode(self) else { return nil }
func infoString(using dependencies: Dependencies) -> String? {
guard let messageInfoData: Data = try? JSONEncoder(using: dependencies).encode(self) else { return nil }
return String(data: messageInfoData, encoding: .utf8)
}

@ -164,7 +164,8 @@ extension MessageReceiver {
isHidden: false
).upsert(db)
/// If the thread didn't already exist then insert an 'invited' info message
/// If the thread didn't already exist, or the user had previously been kicked but has since been re-added to the group, then insert
/// an 'invited' info message
guard !threadAlreadyExisted || wasKickedFromGroup else { return }
let interaction: Interaction = try Interaction(
@ -177,7 +178,7 @@ extension MessageReceiver {
.defaulting(to: Profile.truncated(id: sender, threadVariant: .group)),
message.groupName
)
.infoString,
.infoString(using: dependencies),
timestampMs: Int64(sentTimestampMs),
wasRead: SessionUtil.timestampAlreadyRead(
threadId: message.groupSessionId.hexString,
@ -444,7 +445,7 @@ extension MessageReceiver {
body: message.updatedName
.map { ClosedGroup.MessageInfo.updatedName($0) }
.defaulting(to: ClosedGroup.MessageInfo.updatedNameFallback)
.infoString,
.infoString(using: dependencies),
timestampMs: Int64(sentTimestampMs)
).inserted(db)
@ -456,7 +457,7 @@ extension MessageReceiver {
variant: .infoGroupInfoUpdated,
body: ClosedGroup.MessageInfo
.updatedDisplayPicture
.infoString,
.infoString(using: dependencies),
timestampMs: Int64(sentTimestampMs)
).inserted(db)
@ -531,9 +532,20 @@ extension MessageReceiver {
variant: .infoGroupMembersUpdated,
body: {
switch message.changeType {
case .added: return ClosedGroup.MessageInfo.addedUsers(names: names).infoString
case .removed: return ClosedGroup.MessageInfo.removedUsers(names: names).infoString
case .promoted: return ClosedGroup.MessageInfo.promotedUsers(names: names).infoString
case .added:
return ClosedGroup.MessageInfo
.addedUsers(names: names)
.infoString(using: dependencies)
case .removed:
return ClosedGroup.MessageInfo
.removedUsers(names: names)
.infoString(using: dependencies)
case .promoted:
return ClosedGroup.MessageInfo
.promotedUsers(names: names)
.infoString(using: dependencies)
}
}(),
timestampMs: Int64(sentTimestampMs)
@ -564,7 +576,7 @@ extension MessageReceiver {
Profile.truncated(id: sender, truncating: .middle)
)
)
.infoString,
.infoString(using: dependencies),
timestampMs: Int64(sentTimestampMs)
).inserted(db)

@ -251,7 +251,7 @@ extension MessageSender {
variant: .infoGroupInfoUpdated,
body: ClosedGroup.MessageInfo
.updatedName(name)
.infoString,
.infoString(using: dependencies),
timestampMs: changeTimestampMs
).inserted(db)
@ -326,7 +326,7 @@ extension MessageSender {
variant: .infoGroupInfoUpdated,
body: ClosedGroup.MessageInfo
.updatedDisplayPicture
.infoString,
.infoString(using: dependencies),
timestampMs: changeTimestampMs
).inserted(db)
@ -499,7 +499,7 @@ extension MessageSender {
Profile.truncated(id: id, truncating: .middle)
}
)
.infoString,
.infoString(using: dependencies),
timestampMs: changeTimestampMs
).inserted(db)
@ -692,7 +692,7 @@ extension MessageSender {
Profile.truncated(id: id, truncating: .middle)
}
)
.infoString,
.infoString(using: dependencies),
timestampMs: targetChangeTimestampMs
).inserted(db)
@ -799,7 +799,7 @@ extension MessageSender {
Profile.truncated(id: id, truncating: .middle)
}
)
.infoString,
.infoString(using: dependencies),
timestampMs: changeTimestampMs
).inserted(db)

@ -16,7 +16,7 @@ public extension KeychainStorage.DataKey { static let pushNotificationEncryption
// MARK: - PushNotificationAPI
public enum PushNotificationAPI {
private static let encryptionKeyLength: Int = 32
internal static let encryptionKeyLength: Int = 32
private static let maxRetryCount: Int = 4
private static let tokenExpirationInterval: TimeInterval = (12 * 60 * 60)

@ -1120,12 +1120,12 @@ public extension SessionUtil {
var cGroupId: [CChar] = groupSessionId.hexString.cArray.nullTerminated()
var userGroup: ugroups_group_info = ugroups_group_info()
// If the group doesn't exist then assume the user was kicked
guard user_groups_get_group(conf, &userGroup, &cGroupId) else { return true }
// If the group doesn't exist then assume the user hasn't been kicked
guard user_groups_get_group(conf, &userGroup, &cGroupId) else { return false }
return ugroups_group_is_kicked(&userGroup)
})
.defaulting(to: true)
.defaulting(to: false)
}
static func remove(

@ -207,7 +207,7 @@ public struct DisplayPictureManager {
failure: ((DisplayPictureError) -> ())? = nil,
using dependencies: Dependencies
) {
queue.async {
queue.async(using: dependencies) {
// If the profile avatar was updated or removed then encrypt with a new profile key
// to ensure that other users know that our profile picture was updated
let newEncryptionKey: Data
@ -320,8 +320,8 @@ public struct DisplayPictureManager {
preparedUpload
.send(using: dependencies)
.subscribe(on: DispatchQueue.global(qos: .userInitiated))
.receive(on: queue)
.subscribe(on: DispatchQueue.global(qos: .userInitiated), using: dependencies)
.receive(on: queue, using: dependencies)
.sinkUntilComplete(
receiveCompletion: { result in
switch result {

@ -50,28 +50,18 @@ class DisplayPictureDownloadJobSpec: QuickSpec {
@TestState(singleton: .network, in: dependencies) var mockNetwork: MockNetwork! = MockNetwork(
initialSetup: { network in
network
.when {
$0.send(
.selectedNetworkRequest(
any(),
to: any(),
with: any(),
timeout: FileServerAPI.fileDownloadTimeout,
using: any()
)
)
}
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, timeout: .any, using: .any)) }
.thenReturn(MockNetwork.response(data: encryptedData))
}
)
@TestState(singleton: .fileManager, in: dependencies) var mockFileManager: MockFileManager! = MockFileManager(
initialSetup: { fileManager in
fileManager
.when { $0.createFile(atPath: any(), contents: any(), attributes: any()) }
.when { $0.createFile(atPath: .any, contents: .any, attributes: .any) }
.thenReturn(true)
fileManager
.when { $0.containerURL(forSecurityApplicationGroupIdentifier: any()) }
.when { $0.containerURL(forSecurityApplicationGroupIdentifier: .any) }
.thenReturn(URL(fileURLWithPath: "/test"))
}
)
@ -79,16 +69,14 @@ class DisplayPictureDownloadJobSpec: QuickSpec {
initialSetup: { crypto in
crypto.when { $0.generate(.uuid()) }.thenReturn(filenameUuid)
crypto
.when { $0.generate(.decryptedDataDisplayPicture(data: any(), key: any(), using: any())) }
.when { $0.generate(.decryptedDataDisplayPicture(data: .any, key: .any, using: .any)) }
.thenReturn(imageData)
crypto
.when { $0.generate(.hash(message: anyArray(), outputLength: any())) }
.when { $0.generate(.hash(message: .any, outputLength: .any)) }
.thenReturn([])
crypto
.when { crypto in
crypto.generate(
.blindedKeyPair(serverPublicKey: any(), edKeyPair: any(), using: any())
)
crypto.generate(.blindedKeyPair(serverPublicKey: .any, edKeyPair: .any, using: .any))
}
.thenReturn(
KeyPair(
@ -103,10 +91,10 @@ class DisplayPictureDownloadJobSpec: QuickSpec {
.when {
$0.generate(
.signatureSOGS(
message: anyArray(),
secretKey: anyArray(),
blindedSecretKey: anyArray(),
blindedPublicKey: anyArray()
message: .any,
secretKey: .any,
blindedSecretKey: .any,
blindedPublicKey: .any
)
)
}
@ -116,7 +104,7 @@ class DisplayPictureDownloadJobSpec: QuickSpec {
@TestState(cache: .displayPicture, in: dependencies) var mockDisplayPictureCache: MockDisplayPictureCache! = MockDisplayPictureCache(
initialSetup: { displayPictureCache in
displayPictureCache.when { $0.imageData }.thenReturn([:])
displayPictureCache.when { $0.imageData = any() }.thenReturn(())
displayPictureCache.when { $0.imageData = .any }.thenReturn(())
}
)
@ -528,14 +516,14 @@ class DisplayPictureDownloadJobSpec: QuickSpec {
)
expect(mockNetwork)
.to(call(.exactly(times: 1), matchingParameters: .all) { [dependencies = dependencies!] network in
.to(call(.exactly(times: 1), matchingParameters: .all) { network in
network.send(
.selectedNetworkRequest(
expectedRequest,
to: FileServerAPI.server,
with: FileServerAPI.serverPublicKey,
timeout: FileServerAPI.fileDownloadTimeout,
using: dependencies
using: .any
)
)
})
@ -589,14 +577,14 @@ class DisplayPictureDownloadJobSpec: QuickSpec {
)
expect(mockNetwork)
.to(call(.exactly(times: 1), matchingParameters: .all) { [dependencies = dependencies!] network in
.to(call(.exactly(times: 1), matchingParameters: .all) { network in
network.send(
.selectedNetworkRequest(
expectedRequest,
to: "testserver",
with: TestConstants.serverPublicKey,
timeout: FileServerAPI.fileDownloadTimeout,
using: dependencies
using: .any
)
)
})
@ -645,15 +633,15 @@ class DisplayPictureDownloadJobSpec: QuickSpec {
context("when it fails to decrypt the data") {
beforeEach {
mockCrypto
.when { $0.generate(.decryptedDataDisplayPicture(data: any(), key: any(), using: any())) }
.when { $0.generate(.decryptedDataDisplayPicture(data: .any, key: .any, using: .any)) }
.thenReturn(nil)
}
// MARK: ------ does not save the picture
it("does not save the picture") {
expect(mockFileManager)
.toNot(call { $0.createFile(atPath: any(), contents: any(), attributes: any()) })
expect(mockDisplayPictureCache).toNot(call { $0.imageData = any() })
.toNot(call { $0.createFile(atPath: .any, contents: .any, attributes: .any) })
expect(mockDisplayPictureCache).toNot(call { $0.imageData = .any })
expect(mockStorage.read { db in try Profile.fetchOne(db) }).to(equal(profile))
}
}
@ -662,15 +650,15 @@ class DisplayPictureDownloadJobSpec: QuickSpec {
context("when it decrypts invalid image data") {
beforeEach {
mockCrypto
.when { $0.generate(.decryptedDataDisplayPicture(data: any(), key: any(), using: any())) }
.when { $0.generate(.decryptedDataDisplayPicture(data: .any, key: .any, using: .any)) }
.thenReturn(Data([1, 2, 3]))
}
// MARK: ------ does not save the picture
it("does not save the picture") {
expect(mockFileManager)
.toNot(call { $0.createFile(atPath: any(), contents: any(), attributes: any()) })
expect(mockDisplayPictureCache).toNot(call { $0.imageData = any() })
.toNot(call { $0.createFile(atPath: .any, contents: .any, attributes: .any) })
expect(mockDisplayPictureCache).toNot(call { $0.imageData = .any })
expect(mockStorage.read { db in try Profile.fetchOne(db) }).to(equal(profile))
}
}
@ -679,13 +667,13 @@ class DisplayPictureDownloadJobSpec: QuickSpec {
context("when it fails to write to disk") {
beforeEach {
mockFileManager
.when { $0.createFile(atPath: any(), contents: any(), attributes: any()) }
.when { $0.createFile(atPath: .any, contents: .any, attributes: .any) }
.thenReturn(false)
}
// MARK: ------ does not save the picture
it("does not save the picture") {
expect(mockDisplayPictureCache).toNot(call { $0.imageData = any() })
expect(mockDisplayPictureCache).toNot(call { $0.imageData = .any })
expect(mockStorage.read { db in try Profile.fetchOne(db) }).to(equal(profile))
}
}
@ -742,11 +730,11 @@ class DisplayPictureDownloadJobSpec: QuickSpec {
it("does not save the picture") {
expect(mockCrypto)
.toNot(call {
$0.generate(.decryptedDataDisplayPicture(data: any(), key: any(), using: any()))
$0.generate(.decryptedDataDisplayPicture(data: .any, key: .any, using: .any))
})
expect(mockFileManager)
.toNot(call { $0.createFile(atPath: any(), contents: any(), attributes: any()) })
expect(mockDisplayPictureCache).toNot(call { $0.imageData = any() })
.toNot(call { $0.createFile(atPath: .any, contents: .any, attributes: .any) })
expect(mockDisplayPictureCache).toNot(call { $0.imageData = .any })
expect(mockStorage.read { db in try Profile.fetchOne(db) }).to(beNil())
}
}
@ -768,11 +756,11 @@ class DisplayPictureDownloadJobSpec: QuickSpec {
it("does not save the picture") {
expect(mockCrypto)
.toNot(call {
$0.generate(.decryptedDataDisplayPicture(data: any(), key: any(), using: any()))
$0.generate(.decryptedDataDisplayPicture(data: .any, key: .any, using: .any))
})
expect(mockFileManager)
.toNot(call { $0.createFile(atPath: any(), contents: any(), attributes: any()) })
expect(mockDisplayPictureCache).toNot(call { $0.imageData = any() })
.toNot(call { $0.createFile(atPath: .any, contents: .any, attributes: .any) })
expect(mockDisplayPictureCache).toNot(call { $0.imageData = .any })
expect(mockStorage.read { db in try Profile.fetchOne(db) })
.toNot(equal(
Profile(
@ -804,11 +792,11 @@ class DisplayPictureDownloadJobSpec: QuickSpec {
it("does not save the picture") {
expect(mockCrypto)
.toNot(call {
$0.generate(.decryptedDataDisplayPicture(data: any(), key: any(), using: any()))
$0.generate(.decryptedDataDisplayPicture(data: .any, key: .any, using: .any))
})
expect(mockFileManager)
.toNot(call { $0.createFile(atPath: any(), contents: any(), attributes: any()) })
expect(mockDisplayPictureCache).toNot(call { $0.imageData = any() })
.toNot(call { $0.createFile(atPath: .any, contents: .any, attributes: .any) })
expect(mockDisplayPictureCache).toNot(call { $0.imageData = .any })
expect(mockStorage.read { db in try Profile.fetchOne(db) })
.toNot(equal(
Profile(
@ -839,7 +827,7 @@ class DisplayPictureDownloadJobSpec: QuickSpec {
it("saves the picture") {
expect(mockCrypto)
.to(call {
$0.generate(.decryptedDataDisplayPicture(data: any(), key: any(), using: any()))
$0.generate(.decryptedDataDisplayPicture(data: .any, key: .any, using: .any))
})
expect(mockFileManager).to(call(.exactly(times: 1), matchingParameters: .all) {
$0.createFile(

@ -56,7 +56,7 @@ class MessageSendJobSpec: QuickSpec {
}
.thenReturn([:])
jobRunner
.when { $0.insert(any(), job: any(), before: any()) }
.when { $0.insert(.any, job: .any, before: .any) }
.then { args, untrackedArgs in
let db: Database = untrackedArgs[0] as! Database
var job: Job = args[0] as! Job
@ -374,7 +374,7 @@ class MessageSendJobSpec: QuickSpec {
expect(mockJobRunner)
.to(call(.exactly(times: 1), matchingParameters: .all) {
$0.insert(
any(),
.any,
job: Job(
variant: .attachmentUpload,
behaviour: .runOnce,

@ -43,7 +43,7 @@ class SessionUtilSpec: QuickSpec {
@TestState(singleton: .crypto, in: dependencies) var mockCrypto: MockCrypto! = MockCrypto(
initialSetup: { crypto in
crypto
.when { $0.generate(.ed25519KeyPair(seed: any(), using: any())) }
.when { $0.generate(.ed25519KeyPair(seed: .any, using: .any)) }
.thenReturn(
KeyPair(
publicKey: Data.data(
@ -56,35 +56,31 @@ class SessionUtilSpec: QuickSpec {
)
)
crypto
.when { try $0.tryGenerate(.signature(message: anyArray(), secretKey: anyArray())) }
.when { try $0.tryGenerate(.signature(message: .any, secretKey: .any)) }
.thenReturn(
Authentication.Signature.standard(signature: Array("TestSignature".data(using: .utf8)!))
)
}
)
@TestState(singleton: .network, in: dependencies) var mockNetwork: MockNetwork! = MockNetwork(
initialSetup: { [dependencies = dependencies!] network in
initialSetup: { network in
network
.when {
$0.send(
.selectedNetworkRequest(
any(),
to: any(),
timeout: any(),
using: dependencies
)
)
}
.when { $0.send(.selectedNetworkRequest(.any, to: .any, timeout: .any, using: .any)) }
.thenReturn(MockNetwork.response(data: Data([1, 2, 3])))
}
)
@TestState(singleton: .jobRunner, in: dependencies) var mockJobRunner: MockJobRunner! = MockJobRunner(
initialSetup: { jobRunner in
jobRunner
.when { $0.add(any(), job: any(), dependantJob: any(), canStartJob: any(), using: any()) }
.when { $0.add(.any, job: .any, dependantJob: .any, canStartJob: .any, using: .any) }
.thenReturn(nil)
}
)
@TestState(defaults: .standard, in: dependencies) var mockUserDefaults: MockUserDefaults! = MockUserDefaults(
initialSetup: { userDefaults in
userDefaults.when { $0.string(forKey: .any) }.thenReturn(nil)
}
)
@TestState var createGroupOutput: SessionUtil.CreatedGroupInfo! = {
mockStorage.write(using: dependencies) { db in
@ -133,14 +129,14 @@ class SessionUtilSpec: QuickSpec {
var secretKey: [UInt8] = Array(Data(hex: TestConstants.edSecretKey))
_ = user_groups_init(&conf, &secretKey, nil, 0, nil)
cache.when { $0.setConfig(for: any(), sessionId: any(), to: any()) }.thenReturn(())
cache.when { $0.config(for: .userGroups, sessionId: any()) }
cache.when { $0.setConfig(for: .any, sessionId: .any, to: .any) }.thenReturn(())
cache.when { $0.config(for: .userGroups, sessionId: .any) }
.thenReturn(Atomic(.object(conf)))
cache.when { $0.config(for: .groupInfo, sessionId: any()) }
cache.when { $0.config(for: .groupInfo, sessionId: .any) }
.thenReturn(Atomic(createGroupOutput.groupState[.groupInfo]))
cache.when { $0.config(for: .groupMembers, sessionId: any()) }
cache.when { $0.config(for: .groupMembers, sessionId: .any) }
.thenReturn(Atomic(createGroupOutput.groupState[.groupMembers]))
cache.when { $0.config(for: .groupKeys, sessionId: any()) }
cache.when { $0.config(for: .groupKeys, sessionId: .any) }
.thenReturn(Atomic(createGroupOutput.groupState[.groupKeys]))
}
)
@ -358,7 +354,7 @@ class SessionUtilSpec: QuickSpec {
userGroupsConfig = .object(userGroupsConf)
mockSessionUtilCache
.when { $0.config(for: .userGroups, sessionId: any()) }
.when { $0.config(for: .userGroups, sessionId: .any) }
.thenReturn(Atomic(userGroupsConfig))
}
@ -393,7 +389,7 @@ class SessionUtilSpec: QuickSpec {
var resultError: Error? = nil
mockCrypto
.when { $0.generate(.ed25519KeyPair(seed: any(), using: any())) }
.when { $0.generate(.ed25519KeyPair(seed: .any, using: .any)) }
.thenReturn(nil)
mockStorage.write { db in
@ -625,7 +621,7 @@ class SessionUtilSpec: QuickSpec {
}
expect(mockSessionUtilCache).to(call(.exactly(times: 3)) {
$0.setConfig(for: any(), sessionId: any(), to: any())
$0.setConfig(for: .any, sessionId: .any, to: .any)
})
expect(mockSessionUtilCache)
.to(call(matchingParameters: .atLeast(2)) {
@ -635,7 +631,7 @@ class SessionUtilSpec: QuickSpec {
.group,
hex: "cbd569f56fb13ea95a3f0c05c331cc24139c0090feb412069dc49fab34406ece"
),
to: any()
to: .any
)
})
expect(mockSessionUtilCache)
@ -646,7 +642,7 @@ class SessionUtilSpec: QuickSpec {
.group,
hex: "cbd569f56fb13ea95a3f0c05c331cc24139c0090feb412069dc49fab34406ece"
),
to: any()
to: .any
)
})
expect(mockSessionUtilCache)
@ -657,7 +653,7 @@ class SessionUtilSpec: QuickSpec {
.group,
hex: "cbd569f56fb13ea95a3f0c05c331cc24139c0090feb412069dc49fab34406ece"
),
to: any()
to: .any
)
})
}
@ -960,7 +956,7 @@ class SessionUtilSpec: QuickSpec {
expect(mockJobRunner)
.to(call(.exactly(times: 1), matchingParameters: .all) { jobRunner in
jobRunner.add(
any(),
.any,
job: Job(
variant: .displayPictureDownload,
behaviour: .runOnce,
@ -980,7 +976,7 @@ class SessionUtilSpec: QuickSpec {
)
),
canStartJob: true,
using: any()
using: .any
)
})
}
@ -1205,7 +1201,7 @@ class SessionUtilSpec: QuickSpec {
expect(mockJobRunner)
.to(call(.exactly(times: 1), matchingParameters: .all) { jobRunner in
jobRunner.add(
any(),
.any,
job: Job(
variant: .garbageCollection,
behaviour: .runOnce,
@ -1217,7 +1213,7 @@ class SessionUtilSpec: QuickSpec {
)
),
canStartJob: true,
using: any()
using: .any
)
})
}
@ -1403,7 +1399,7 @@ class SessionUtilSpec: QuickSpec {
expectedRequest.httpBody!,
to: dependencies.randomElement(mockSwarmCache)!,
timeout: HTTP.defaultTimeout,
using: any()
using: .any
)
)
})
@ -1446,15 +1442,8 @@ class SessionUtilSpec: QuickSpec {
}
expect(numInteractions).to(equal(0))
expect(mockNetwork)
.toNot(call { [dependencies = dependencies!] network in
network.send(
.selectedNetworkRequest(
any(),
to: any(),
timeout: any(),
using: dependencies
)
)
.toNot(call { network in
network.send(.selectedNetworkRequest(.any, to: .any, timeout: .any, using: .any))
})
}
}

@ -199,9 +199,7 @@ class SOGSMessageSpec: QuickSpec {
// MARK: -------- succeeds if it succeeds verification
it("succeeds if it succeeds verification") {
mockCrypto
.when {
$0.verify(.signature(message: anyArray(), publicKey: anyArray(), signature: anyArray()))
}
.when { $0.verify(.signature(message: .any, publicKey: .any, signature: .any)) }
.thenReturn(true)
expect {
@ -213,9 +211,7 @@ class SOGSMessageSpec: QuickSpec {
// MARK: -------- provides the correct values as parameters
it("provides the correct values as parameters") {
mockCrypto
.when {
$0.verify(.signature(message: anyArray(), publicKey: anyArray(), signature: anyArray()))
}
.when { $0.verify(.signature(message: .any, publicKey: .any, signature: .any)) }
.thenReturn(true)
_ = try? decoder.decode(OpenGroupAPI.Message.self, from: messageData)
@ -235,9 +231,7 @@ class SOGSMessageSpec: QuickSpec {
// MARK: -------- throws if it fails verification
it("throws if it fails verification") {
mockCrypto
.when {
$0.verify(.signature(message: anyArray(), publicKey: anyArray(), signature: anyArray()))
}
.when { $0.verify(.signature(message: .any, publicKey: .any, signature: .any)) }
.thenReturn(false)
expect {
@ -252,7 +246,7 @@ class SOGSMessageSpec: QuickSpec {
// MARK: -------- succeeds if it succeeds verification
it("succeeds if it succeeds verification") {
mockCrypto
.when { $0.verify(.signatureEd25519(any(), publicKey: any(), data: any())) }
.when { $0.verify(.signatureEd25519(.any, publicKey: .any, data: .any)) }
.thenReturn(true)
expect {
@ -264,7 +258,7 @@ class SOGSMessageSpec: QuickSpec {
// MARK: -------- provides the correct values as parameters
it("provides the correct values as parameters") {
mockCrypto
.when { $0.verify(.signatureEd25519(any(), publicKey: any(), data: any())) }
.when { $0.verify(.signatureEd25519(.any, publicKey: .any, data: .any)) }
.thenReturn(true)
_ = try? decoder.decode(OpenGroupAPI.Message.self, from: messageData)
@ -284,7 +278,7 @@ class SOGSMessageSpec: QuickSpec {
// MARK: -------- throws if it fails verification
it("throws if it fails verification") {
mockCrypto
.when { $0.verify(.signatureEd25519(any(), publicKey: any(), data: any())) }
.when { $0.verify(.signatureEd25519(.any, publicKey: .any, data: .any)) }
.thenReturn(false)
expect {

@ -53,12 +53,12 @@ class OpenGroupAPISpec: QuickSpec {
@TestState(singleton: .crypto, in: dependencies) var mockCrypto: MockCrypto! = MockCrypto(
initialSetup: { crypto in
crypto
.when { $0.generate(.hash(message: anyArray(), outputLength: any())) }
.when { $0.generate(.hash(message: .any, outputLength: .any)) }
.thenReturn([])
crypto
.when { crypto in
crypto.generate(
.blindedKeyPair(serverPublicKey: any(), edKeyPair: any(), using: any())
.blindedKeyPair(serverPublicKey: .any, edKeyPair: .any, using: .any)
)
}
.thenReturn(
@ -71,19 +71,19 @@ class OpenGroupAPISpec: QuickSpec {
.when {
$0.generate(
.signatureSOGS(
message: anyArray(),
secretKey: anyArray(),
blindedSecretKey: anyArray(),
blindedPublicKey: anyArray()
message: .any,
secretKey: .any,
blindedSecretKey: .any,
blindedPublicKey: .any
)
)
}
.thenReturn("TestSogsSignature".bytes)
crypto
.when { $0.generate(.signature(message: anyArray(), secretKey: anyArray())) }
.when { $0.generate(.signature(message: .any, secretKey: .any)) }
.thenReturn(Authentication.Signature.standard(signature: "TestSignature".bytes))
crypto
.when { $0.generate(.signatureEd25519(data: anyArray(), keyPair: any())) }
.when { $0.generate(.signatureEd25519(data: .any, keyPair: .any)) }
.thenReturn("TestStandardSignature".bytes)
crypto
.when { $0.generate(.nonce16()) }
@ -464,7 +464,7 @@ class OpenGroupAPISpec: QuickSpec {
// MARK: ---- processes a valid response correctly
it("processes a valid response correctly") {
mockNetwork
.when { $0.send(.selectedNetworkRequest(any(), to: any(), with: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, using: .any)) }
.thenReturn(HTTP.BatchResponse.mockCapabilitiesAndRoomResponse)
var response: (info: ResponseInfoType, data: OpenGroupAPI.CapabilitiesAndRoomResponse)?
@ -493,7 +493,7 @@ class OpenGroupAPISpec: QuickSpec {
// MARK: ------ errors when not given a room response
it("errors when not given a room response") {
mockNetwork
.when { $0.send(.selectedNetworkRequest(any(), to: any(), with: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, using: .any)) }
.thenReturn(HTTP.BatchResponse.mockCapabilitiesAndBanResponse)
var response: (info: ResponseInfoType, data: OpenGroupAPI.CapabilitiesAndRoomResponse)?
@ -519,7 +519,7 @@ class OpenGroupAPISpec: QuickSpec {
// MARK: ------ errors when not given a capabilities response
it("errors when not given a capabilities response") {
mockNetwork
.when { $0.send(.selectedNetworkRequest(any(), to: any(), with: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, using: .any)) }
.thenReturn(HTTP.BatchResponse.mockBanAndRoomResponse)
var response: (info: ResponseInfoType, data: OpenGroupAPI.CapabilitiesAndRoomResponse)?
@ -569,7 +569,7 @@ class OpenGroupAPISpec: QuickSpec {
// MARK: ---- processes a valid response correctly
it("processes a valid response correctly") {
mockNetwork
.when { $0.send(.selectedNetworkRequest(any(), to: any(), with: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, using: .any)) }
.thenReturn(HTTP.BatchResponse.mockCapabilitiesAndRoomsResponse)
var response: (info: ResponseInfoType, data: OpenGroupAPI.CapabilitiesAndRoomsResponse)?
@ -597,7 +597,7 @@ class OpenGroupAPISpec: QuickSpec {
// MARK: ------ errors when not given a room response
it("errors when not given a room response") {
mockNetwork
.when { $0.send(.selectedNetworkRequest(any(), to: any(), with: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, using: .any)) }
.thenReturn(HTTP.BatchResponse.mockCapabilitiesAndBanResponse)
var response: (info: ResponseInfoType, data: OpenGroupAPI.CapabilitiesAndRoomsResponse)?
@ -622,7 +622,7 @@ class OpenGroupAPISpec: QuickSpec {
// MARK: ------ errors when not given a capabilities response
it("errors when not given a capabilities response") {
mockNetwork
.when { $0.send(.selectedNetworkRequest(any(), to: any(), with: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, using: .any)) }
.thenReturn(HTTP.BatchResponse.mockBanAndRoomsResponse)
var response: (info: ResponseInfoType, data: OpenGroupAPI.CapabilitiesAndRoomsResponse)?
@ -762,7 +762,7 @@ class OpenGroupAPISpec: QuickSpec {
it("fails to sign if no signature is generated") {
mockCrypto.reset() // The 'keyPair' value doesn't equate so have to explicitly reset
mockCrypto
.when { $0.generate(.signatureEd25519(data: anyArray(), keyPair: any())) }
.when { $0.generate(.signatureEd25519(data: .any, keyPair: .any)) }
.thenReturn(nil)
var preparationError: Error?
@ -888,10 +888,10 @@ class OpenGroupAPISpec: QuickSpec {
.when {
$0.generate(
.signatureSOGS(
message: anyArray(),
secretKey: anyArray(),
blindedSecretKey: anyArray(),
blindedPublicKey: anyArray()
message: .any,
secretKey: .any,
blindedSecretKey: .any,
blindedPublicKey: .any
)
)
}
@ -1065,7 +1065,7 @@ class OpenGroupAPISpec: QuickSpec {
it("fails to sign if no signature is generated") {
mockCrypto.reset() // The 'keyPair' value doesn't equate so have to explicitly reset
mockCrypto
.when { $0.generate(.signatureEd25519(data: anyArray(), keyPair: any())) }
.when { $0.generate(.signatureEd25519(data: .any, keyPair: .any)) }
.thenReturn(nil)
var preparationError: Error?
@ -1187,10 +1187,10 @@ class OpenGroupAPISpec: QuickSpec {
.when {
$0.generate(
.signatureSOGS(
message: anyArray(),
secretKey: anyArray(),
blindedSecretKey: anyArray(),
blindedPublicKey: anyArray()
message: .any,
secretKey: .any,
blindedSecretKey: .any,
blindedPublicKey: .any
)
)
}
@ -1798,7 +1798,7 @@ class OpenGroupAPISpec: QuickSpec {
// MARK: ------ fails when the signature is not generated
it("fails when the signature is not generated") {
mockCrypto
.when { try $0.generate(.signature(message: anyArray(), secretKey: anyArray())) }
.when { $0.generate(.signature(message: .any, secretKey: .any)) }
.thenThrow(CryptoError.failedToGenerateOutput)
var preparationError: Error?
@ -1858,7 +1858,7 @@ class OpenGroupAPISpec: QuickSpec {
// MARK: ------ fails when the blindedKeyPair is not generated
it("fails when the blindedKeyPair is not generated") {
mockCrypto
.when { $0.generate(.blindedKeyPair(serverPublicKey: any(), edKeyPair: any(), using: any())) }
.when { $0.generate(.blindedKeyPair(serverPublicKey: .any, edKeyPair: .any, using: .any)) }
.thenReturn(nil)
var preparationError: Error?
@ -1883,7 +1883,7 @@ class OpenGroupAPISpec: QuickSpec {
// MARK: ------ fails when the sogsSignature is not generated
it("fails when the sogsSignature is not generated") {
mockCrypto
.when { $0.generate(.blindedKeyPair(serverPublicKey: any(), edKeyPair: any(), using: any())) }
.when { $0.generate(.blindedKeyPair(serverPublicKey: .any, edKeyPair: .any, using: .any)) }
.thenReturn(nil)
var preparationError: Error?

@ -51,10 +51,10 @@ class OpenGroupManagerSpec: QuickSpec {
infoUpdates: 10,
sequenceNumber: 5
)
@TestState var testPollInfo: OpenGroupAPI.RoomPollInfo! = OpenGroupAPI.RoomPollInfo.mockValue.with(
@TestState var testPollInfo: OpenGroupAPI.RoomPollInfo! = OpenGroupAPI.RoomPollInfo.mock.with(
token: "testRoom",
activeUsers: 10,
details: .mockValue
details: .mock
)
@TestState var testMessage: OpenGroupAPI.Message! = OpenGroupAPI.Message(
id: 127,
@ -119,25 +119,17 @@ class OpenGroupManagerSpec: QuickSpec {
@TestState(singleton: .jobRunner, in: dependencies) var mockJobRunner: MockJobRunner! = MockJobRunner(
initialSetup: { jobRunner in
jobRunner
.when { $0.add(any(), job: any(), dependantJob: any(), canStartJob: any(), using: any()) }
.when { $0.add(.any, job: .any, dependantJob: .any, canStartJob: .any, using: .any) }
.thenReturn(nil)
}
)
@TestState(singleton: .network, in: dependencies) var mockNetwork: MockNetwork! = MockNetwork()
@TestState(singleton: .crypto, in: dependencies) var mockCrypto: MockCrypto! = MockCrypto(
initialSetup: { crypto in
crypto
.when { $0.generate(.hash(message: anyArray(), outputLength: any())) }
.thenReturn([])
crypto.when { $0.generate(.hash(message: .any, outputLength: .any)) }.thenReturn([])
crypto
.when { crypto in
crypto.generate(
.blindedKeyPair(
serverPublicKey: any(),
edKeyPair: any(),
using: any()
)
)
crypto.generate(.blindedKeyPair(serverPublicKey: .any, edKeyPair: .any, using: .any))
}
.thenReturn(
KeyPair(
@ -149,16 +141,16 @@ class OpenGroupManagerSpec: QuickSpec {
.when {
$0.generate(
.signatureSOGS(
message: anyArray(),
secretKey: anyArray(),
blindedSecretKey: anyArray(),
blindedPublicKey: anyArray()
message: .any,
secretKey: .any,
blindedSecretKey: .any,
blindedPublicKey: .any
)
)
}
.thenReturn("TestSogsSignature".bytes)
crypto
.when { try $0.generate(.signature(message: anyArray(), secretKey: anyArray())) }
.when { $0.generate(.signature(message: .any, secretKey: .any)) }
.thenReturn(Authentication.Signature.standard(signature: "TestSignature".bytes))
crypto.when { $0.size(.nonce16) }.thenReturn(16)
crypto
@ -180,14 +172,12 @@ class OpenGroupManagerSpec: QuickSpec {
@TestState(cache: .openGroupManager, in: dependencies) var mockOGMCache: MockOGMCache! = MockOGMCache(
initialSetup: { cache in
cache.when { $0.pendingChanges }.thenReturn([])
cache.when { $0.pollers = any() }.thenReturn(())
cache.when { $0.isPolling = any() }.thenReturn(())
cache.when { $0.pollers = .any }.thenReturn(())
cache.when { $0.isPolling = .any }.thenReturn(())
cache
.when { $0.defaultRoomsPublisher = any(type: [OpenGroupManager.DefaultRoomInfo].self) }
.thenReturn(())
cache
.when { $0.pendingChanges = any(type: OpenGroupAPI.PendingChange.self) }
.when { $0.defaultRoomsPublisher = .any(type: [OpenGroupManager.DefaultRoomInfo].self) }
.thenReturn(())
cache.when { $0.pendingChanges = .any }.thenReturn(())
}
)
@TestState var disposables: [AnyCancellable]! = []
@ -274,7 +264,7 @@ class OpenGroupManagerSpec: QuickSpec {
mockOGMCache.when { $0.hasPerformedInitialPoll }.thenReturn([:])
mockOGMCache.when { $0.timeSinceLastPoll }.thenReturn([:])
mockOGMCache.when { $0.getTimeSinceLastOpen(using: any()) }.thenReturn(0)
mockOGMCache.when { $0.getTimeSinceLastOpen(using: .any) }.thenReturn(0)
mockOGMCache.when { $0.isPolling }.thenReturn(false)
mockOGMCache.when { $0.pollers }.thenReturn([:])
@ -729,7 +719,7 @@ class OpenGroupManagerSpec: QuickSpec {
}
mockNetwork
.when { $0.send(.selectedNetworkRequest(any(), to: any(), with: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, using: .any)) }
.thenReturn(HTTP.BatchResponse.mockCapabilitiesAndRoomResponse)
mockOGMCache.when { $0.pollers }.thenReturn([:])
@ -875,7 +865,7 @@ class OpenGroupManagerSpec: QuickSpec {
context("with an invalid response") {
beforeEach {
mockNetwork
.when { $0.send(.selectedNetworkRequest(any(), to: any(), with: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, using: .any)) }
.thenReturn(MockNetwork.response(data: Data()))
mockUserDefaults
@ -1220,7 +1210,7 @@ class OpenGroupManagerSpec: QuickSpec {
expect(mockJobRunner)
.toNot(call(matchingParameters: .all) {
$0.add(
any(),
.any,
job: Job(
variant: .displayPictureDownload,
shouldBeUnique: true,
@ -1270,7 +1260,7 @@ class OpenGroupManagerSpec: QuickSpec {
expect(mockJobRunner)
.to(call(matchingParameters: .all) {
$0.add(
any(),
.any,
job: Job(
variant: .displayPictureDownload,
shouldBeUnique: true,
@ -1294,10 +1284,10 @@ class OpenGroupManagerSpec: QuickSpec {
context("and updating the moderator list") {
// MARK: ------ successfully updates
it("successfully updates") {
testPollInfo = OpenGroupAPI.RoomPollInfo.mockValue.with(
testPollInfo = OpenGroupAPI.RoomPollInfo.mock.with(
token: "testRoom",
activeUsers: 10,
details: OpenGroupAPI.Room.mockValue.with(
details: OpenGroupAPI.Room.mock.with(
moderators: ["TestMod"],
hiddenModerators: [],
admins: [],
@ -1341,10 +1331,10 @@ class OpenGroupManagerSpec: QuickSpec {
// MARK: ------ updates for hidden moderators
it("updates for hidden moderators") {
testPollInfo = OpenGroupAPI.RoomPollInfo.mockValue.with(
testPollInfo = OpenGroupAPI.RoomPollInfo.mock.with(
token: "testRoom",
activeUsers: 10,
details: OpenGroupAPI.Room.mockValue.with(
details: OpenGroupAPI.Room.mock.with(
moderators: [],
hiddenModerators: ["TestMod2"],
admins: [],
@ -1388,7 +1378,7 @@ class OpenGroupManagerSpec: QuickSpec {
// MARK: ------ does not insert mods if no moderators are provided
it("does not insert mods if no moderators are provided") {
testPollInfo = OpenGroupAPI.RoomPollInfo.mockValue.with(
testPollInfo = OpenGroupAPI.RoomPollInfo.mock.with(
token: "testRoom",
activeUsers: 10
)
@ -1413,10 +1403,10 @@ class OpenGroupManagerSpec: QuickSpec {
context("and updating the admin list") {
// MARK: ------ successfully updates
it("successfully updates") {
testPollInfo = OpenGroupAPI.RoomPollInfo.mockValue.with(
testPollInfo = OpenGroupAPI.RoomPollInfo.mock.with(
token: "testRoom",
activeUsers: 10,
details: OpenGroupAPI.Room.mockValue.with(
details: OpenGroupAPI.Room.mock.with(
moderators: [],
hiddenModerators: [],
admins: ["TestAdmin"],
@ -1460,10 +1450,10 @@ class OpenGroupManagerSpec: QuickSpec {
// MARK: ------ updates for hidden admins
it("updates for hidden admins") {
testPollInfo = OpenGroupAPI.RoomPollInfo.mockValue.with(
testPollInfo = OpenGroupAPI.RoomPollInfo.mock.with(
token: "testRoom",
activeUsers: 10,
details: OpenGroupAPI.Room.mockValue.with(
details: OpenGroupAPI.Room.mock.with(
moderators: [],
hiddenModerators: [],
admins: [],
@ -1507,7 +1497,7 @@ class OpenGroupManagerSpec: QuickSpec {
// MARK: ------ does not insert an admin if no admins are provided
it("does not insert an admin if no admins are provided") {
testPollInfo = OpenGroupAPI.RoomPollInfo.mockValue.with(
testPollInfo = OpenGroupAPI.RoomPollInfo.mock.with(
token: "testRoom",
activeUsers: 10,
details: nil
@ -1883,25 +1873,25 @@ class OpenGroupManagerSpec: QuickSpec {
.when {
$0.generate(
.sharedBlindedEncryptionKey(
secretKey: anyArray(),
otherBlindedPublicKey: anyArray(),
fromBlindedPublicKey: anyArray(),
toBlindedPublicKey: anyArray(),
using: any()
secretKey: .any,
otherBlindedPublicKey: .any,
fromBlindedPublicKey: .any,
toBlindedPublicKey: .any,
using: .any
)
)
}
.thenReturn([])
mockCrypto
.when { $0.generate(.blindingFactor(serverPublicKey: any(), using: any())) }
.when { $0.generate(.blindingFactor(serverPublicKey: .any, using: .any)) }
.thenReturn([])
mockCrypto
.when {
try $0.generate(
$0.generate(
.decryptedBytesAeadXChaCha20(
authenticatedCipherText: anyArray(),
secretKey: anyArray(),
nonce: anyArray()
authenticatedCipherText: .any,
secretKey: .any,
nonce: .any
)
)
}
@ -1910,7 +1900,7 @@ class OpenGroupManagerSpec: QuickSpec {
[UInt8](repeating: 0, count: 32)
)
mockCrypto
.when { $0.generate(.x25519(ed25519PublicKey: anyArray())) }
.when { $0.generate(.x25519(ed25519PublicKey: .any)) }
.thenReturn(Data(hex: TestConstants.publicKey).bytes)
}
@ -2006,16 +1996,16 @@ class OpenGroupManagerSpec: QuickSpec {
context("for the inbox") {
beforeEach {
mockCrypto
.when { $0.generate(.combinedKeys(lhsKeyBytes: anyArray(), rhsKeyBytes: anyArray())) }
.when { $0.generate(.combinedKeys(lhsKeyBytes: .any, rhsKeyBytes: .any)) }
.thenReturn(SessionId(.standard, hex: testDirectMessage.sender).publicKey)
mockCrypto
.when {
$0.verify(
.sessionId(
any(),
matchesBlindedId: any(),
serverPublicKey: any(),
using: any()
.any,
matchesBlindedId: .any,
serverPublicKey: .any,
using: .any
)
)
}
@ -2113,16 +2103,16 @@ class OpenGroupManagerSpec: QuickSpec {
context("for the outbox") {
beforeEach {
mockCrypto
.when { $0.generate(.combinedKeys(lhsKeyBytes: anyArray(), rhsKeyBytes: anyArray())) }
.when { $0.generate(.combinedKeys(lhsKeyBytes: .any, rhsKeyBytes: .any)) }
.thenReturn(SessionId(.standard, hex: testDirectMessage.recipient).publicKey)
mockCrypto
.when {
$0.verify(
.sessionId(
any(),
matchesBlindedId: any(),
serverPublicKey: any(),
using: any()
.any,
matchesBlindedId: .any,
serverPublicKey: .any,
using: .any
)
)
}
@ -2482,7 +2472,7 @@ class OpenGroupManagerSpec: QuickSpec {
it("returns true if the key is the current users and the users blinded id is a moderator or admin") {
let otherKey: String = TestConstants.publicKey.replacingOccurrences(of: "7", with: "6")
mockCrypto
.when { $0.generate(.blindedKeyPair(serverPublicKey: any(), edKeyPair: any(), using: any())) }
.when { $0.generate(.blindedKeyPair(serverPublicKey: .any, edKeyPair: .any, using: .any)) }
.thenReturn(
KeyPair(
publicKey: Data(hex: otherKey).bytes,
@ -2593,7 +2583,7 @@ class OpenGroupManagerSpec: QuickSpec {
it("returns true if the key is the current users and the users blinded id is a moderator or admin") {
let otherKey: String = TestConstants.publicKey.replacingOccurrences(of: "7", with: "6")
mockCrypto
.when { $0.generate(.blindedKeyPair(serverPublicKey: any(), edKeyPair: any(), using: any())) }
.when { $0.generate(.blindedKeyPair(serverPublicKey: .any, edKeyPair: .any, using: .any)) }
.thenReturn(
KeyPair(
publicKey: Data(hex: otherKey).bytes,
@ -2654,7 +2644,7 @@ class OpenGroupManagerSpec: QuickSpec {
// MARK: ------ returns false if unable generate a blinded key
it("returns false if unable generate a blinded key") {
mockCrypto
.when { $0.generate(.blindedKeyPair(serverPublicKey: any(), edKeyPair: any(), using: any())) }
.when { $0.generate(.blindedKeyPair(serverPublicKey: .any, edKeyPair: .any, using: .any)) }
.thenReturn(nil)
expect(
@ -2674,7 +2664,7 @@ class OpenGroupManagerSpec: QuickSpec {
it("returns false if the key is not the users blinded id") {
let otherKey: String = TestConstants.publicKey.replacingOccurrences(of: "7", with: "6")
mockCrypto
.when { $0.generate(.blindedKeyPair(serverPublicKey: any(), edKeyPair: any(), using: any())) }
.when { $0.generate(.blindedKeyPair(serverPublicKey: .any, edKeyPair: .any, using: .any)) }
.thenReturn(
KeyPair(
publicKey: Data(hex: otherKey).bytes,
@ -2700,7 +2690,7 @@ class OpenGroupManagerSpec: QuickSpec {
let otherKey: String = TestConstants.publicKey.replacingOccurrences(of: "7", with: "6")
mockGeneralCache.when { $0.sessionId }.thenReturn(SessionId(.standard, hex: otherKey))
mockCrypto
.when { $0.generate(.blindedKeyPair(serverPublicKey: any(), edKeyPair: any(), using: any())) }
.when { $0.generate(.blindedKeyPair(serverPublicKey: .any, edKeyPair: .any, using: .any)) }
.thenReturn(
KeyPair(
publicKey: Data(hex: TestConstants.publicKey).bytes,
@ -2738,7 +2728,7 @@ class OpenGroupManagerSpec: QuickSpec {
// MARK: ------ returns true if the key is the current users and the users unblinded id is a moderator or admin
it("returns true if the key is the current users and the users unblinded id is a moderator or admin") {
mockCrypto
.when { $0.generate(.blindedKeyPair(serverPublicKey: any(), edKeyPair: any(), using: any())) }
.when { $0.generate(.blindedKeyPair(serverPublicKey: .any, edKeyPair: .any, using: .any)) }
.thenReturn(
KeyPair(
publicKey: Data(hex: TestConstants.publicKey).bytes,
@ -2781,7 +2771,7 @@ class OpenGroupManagerSpec: QuickSpec {
context("when getting the default rooms if needed") {
beforeEach {
mockNetwork
.when { $0.send(.selectedNetworkRequest(any(), to: any(), with: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, using: .any)) }
.thenReturn(HTTP.BatchResponse.mockCapabilitiesAndRoomsResponse)
mockStorage.write { db in
@ -2802,10 +2792,10 @@ class OpenGroupManagerSpec: QuickSpec {
mockOGMCache.when { $0.defaultRoomsPublisher }.thenReturn(nil)
mockUserDefaults.when { (defaults: inout any UserDefaultsType) -> Any? in
defaults.object(forKey: any())
defaults.object(forKey: .any)
}.thenReturn(nil)
mockUserDefaults.when { (defaults: inout any UserDefaultsType) -> Any? in
defaults.set(anyAny(), forKey: any())
defaults.set(anyAny(), forKey: .any)
}.thenReturn(())
}
@ -2821,7 +2811,7 @@ class OpenGroupManagerSpec: QuickSpec {
// MARK: ---- returns the cached publisher if there is one
it("returns the cached publisher if there is one") {
let uniqueRoomInstance: OpenGroupAPI.Room = OpenGroupAPI.Room.mockValue.with(
let uniqueRoomInstance: OpenGroupAPI.Room = OpenGroupAPI.Room.mock.with(
token: "UniqueId",
name: ""
)
@ -2888,13 +2878,13 @@ class OpenGroupManagerSpec: QuickSpec {
.sinkAndStore(in: &disposables)
expect(response?.map { $0.room })
.to(equal([OpenGroupAPI.Room.mockValue]))
.to(equal([OpenGroupAPI.Room.mock]))
}
// MARK: ---- will retry fetching rooms 8 times before it fails
it("will retry fetching rooms 8 times before it fails") {
mockNetwork
.when { $0.send(.selectedNetworkRequest(any(), to: any(), with: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, using: .any)) }
.thenReturn(MockNetwork.nullResponse())
var error: Error?
@ -2905,15 +2895,15 @@ class OpenGroupManagerSpec: QuickSpec {
expect(error).to(matchError(HTTPError.parsingFailed))
expect(mockNetwork) // First attempt + 8 retries
.to(call(.exactly(times: 9)) { [dependencies = dependencies!] network in
network.send(.selectedNetworkRequest(any(), to: any(), with: any(), using: dependencies))
.to(call(.exactly(times: 9)) { network in
network.send(.selectedNetworkRequest(.any, to: .any, with: .any, using: .any))
})
}
// MARK: ---- removes the cache publisher if all retries fail
it("removes the cache publisher if all retries fail") {
mockNetwork
.when { $0.send(.selectedNetworkRequest(any(), to: any(), with: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, using: .any)) }
.thenReturn(MockNetwork.nullResponse())
var error: Error?
@ -2948,7 +2938,7 @@ class OpenGroupManagerSpec: QuickSpec {
(
OpenGroupAPI.Endpoint.rooms,
[
OpenGroupAPI.Room.mockValue.with(
OpenGroupAPI.Room.mock.with(
token: "test2",
name: "test2",
infoUpdates: 11,
@ -2967,7 +2957,7 @@ class OpenGroupManagerSpec: QuickSpec {
expect(mockJobRunner)
.to(call(matchingParameters: .all) {
$0.add(
any(),
.any,
job: Job(
variant: .displayPictureDownload,
shouldBeUnique: true,
@ -3038,7 +3028,7 @@ extension OpenGroupAPI.RoomPollInfo {
func with(
token: String? = nil,
activeUsers: Int64? = nil,
details: OpenGroupAPI.Room? = .mockValue
details: OpenGroupAPI.Room? = .mock
) -> OpenGroupAPI.RoomPollInfo {
return OpenGroupAPI.RoomPollInfo(
token: (token ?? self.token),
@ -3062,11 +3052,11 @@ extension OpenGroupAPI.RoomPollInfo {
// MARK: - Mock Types
extension OpenGroupAPI.Capabilities: Mocked {
static var mockValue: OpenGroupAPI.Capabilities = OpenGroupAPI.Capabilities(capabilities: [], missing: nil)
static var mock: OpenGroupAPI.Capabilities = OpenGroupAPI.Capabilities(capabilities: [], missing: nil)
}
extension OpenGroupAPI.Room: Mocked {
static var mockValue: OpenGroupAPI.Room = OpenGroupAPI.Room(
static var mock: OpenGroupAPI.Room = OpenGroupAPI.Room(
token: "test",
name: "testRoom",
roomDescription: nil,
@ -3096,7 +3086,7 @@ extension OpenGroupAPI.Room: Mocked {
}
extension OpenGroupAPI.RoomPollInfo: Mocked {
static var mockValue: OpenGroupAPI.RoomPollInfo = OpenGroupAPI.RoomPollInfo(
static var mock: OpenGroupAPI.RoomPollInfo = OpenGroupAPI.RoomPollInfo(
token: "test",
activeUsers: 1,
admin: false,
@ -3110,12 +3100,12 @@ extension OpenGroupAPI.RoomPollInfo: Mocked {
defaultWrite: nil,
upload: true,
defaultUpload: false,
details: .mockValue
details: .mock
)
}
extension OpenGroupAPI.Message: Mocked {
static var mockValue: OpenGroupAPI.Message = OpenGroupAPI.Message(
static var mock: OpenGroupAPI.Message = OpenGroupAPI.Message(
id: 100,
sender: TestConstants.blindedPublicKey,
posted: 1,
@ -3132,7 +3122,7 @@ extension OpenGroupAPI.Message: Mocked {
}
extension OpenGroupAPI.SendDirectMessageResponse: Mocked {
static var mockValue: OpenGroupAPI.SendDirectMessageResponse = OpenGroupAPI.SendDirectMessageResponse(
static var mock: OpenGroupAPI.SendDirectMessageResponse = OpenGroupAPI.SendDirectMessageResponse(
id: 1,
sender: TestConstants.blindedPublicKey,
recipient: "testRecipient",
@ -3142,7 +3132,7 @@ extension OpenGroupAPI.SendDirectMessageResponse: Mocked {
}
extension OpenGroupAPI.DirectMessage: Mocked {
static var mockValue: OpenGroupAPI.DirectMessage = OpenGroupAPI.DirectMessage(
static var mock: OpenGroupAPI.DirectMessage = OpenGroupAPI.DirectMessage(
id: 101,
sender: TestConstants.blindedPublicKey,
recipient: "testRecipient",

@ -33,10 +33,10 @@ class MessageReceiverDecryptionSpec: QuickSpec {
.when { crypto in
crypto.generate(
.encryptedBytesAeadXChaCha20(
message: anyArray(),
secretKey: anyArray(),
nonce: anyArray(),
using: any()
message: .any,
secretKey: .any,
nonce: .any,
using: .any
)
)
}
@ -45,9 +45,9 @@ class MessageReceiverDecryptionSpec: QuickSpec {
.when {
$0.generate(
.openedBytes(
anonymousCipherText: anyArray(),
recipientPublicKey: anyArray(),
recipientSecretKey: anyArray()
anonymousCipherText: .any,
recipientPublicKey: .any,
recipientSecretKey: .any
)
)
}
@ -56,9 +56,9 @@ class MessageReceiverDecryptionSpec: QuickSpec {
.when { crypto in
crypto.generate(
.blindedKeyPair(
serverPublicKey: any(),
edKeyPair: any(),
using: any()
serverPublicKey: .any,
edKeyPair: .any,
using: .any
)
)
}
@ -72,34 +72,34 @@ class MessageReceiverDecryptionSpec: QuickSpec {
.when { crypto in
crypto.generate(
.sharedBlindedEncryptionKey(
secretKey: anyArray(),
otherBlindedPublicKey: anyArray(),
fromBlindedPublicKey: anyArray(),
toBlindedPublicKey: anyArray(),
using: any()
secretKey: .any,
otherBlindedPublicKey: .any,
fromBlindedPublicKey: .any,
toBlindedPublicKey: .any,
using: .any
)
)
}
.thenReturn([])
crypto
.when { crypto in crypto.generate(.blindingFactor(serverPublicKey: any(), using: any())) }
.when { crypto in crypto.generate(.blindingFactor(serverPublicKey: .any, using: .any)) }
.thenReturn([])
crypto
.when { $0.generate(.combinedKeys(lhsKeyBytes: anyArray(), rhsKeyBytes: anyArray())) }
.when { $0.generate(.combinedKeys(lhsKeyBytes: .any, rhsKeyBytes: .any)) }
.thenReturn(Data(hex: TestConstants.blindedPublicKey).bytes)
crypto
.when { $0.generate(.x25519(ed25519PublicKey: anyArray())) }
.when { $0.generate(.x25519(ed25519PublicKey: .any)) }
.thenReturn(Data(hex: TestConstants.publicKey).bytes)
crypto
.when { $0.verify(.signature(message: anyArray(), publicKey: anyArray(), signature: anyArray())) }
.when { $0.verify(.signature(message: .any, publicKey: .any, signature: .any)) }
.thenReturn(true)
crypto
.when {
$0.generate(
.decryptedBytesAeadXChaCha20(
authenticatedCipherText: anyArray(),
secretKey: anyArray(),
nonce: anyArray()
authenticatedCipherText: .any,
secretKey: .any,
nonce: .any
)
)
}
@ -143,9 +143,9 @@ class MessageReceiverDecryptionSpec: QuickSpec {
.when {
$0.generate(
.openedBytes(
anonymousCipherText: anyArray(),
recipientPublicKey: anyArray(),
recipientSecretKey: anyArray()
anonymousCipherText: .any,
recipientPublicKey: .any,
recipientSecretKey: .any
)
)
}
@ -170,9 +170,9 @@ class MessageReceiverDecryptionSpec: QuickSpec {
.when {
$0.generate(
.openedBytes(
anonymousCipherText: anyArray(),
recipientPublicKey: anyArray(),
recipientSecretKey: anyArray()
anonymousCipherText: .any,
recipientPublicKey: .any,
recipientSecretKey: .any
)
)
}
@ -194,7 +194,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
// MARK: ---- throws an error if it cannot verify the message
it("throws an error if it cannot verify the message") {
mockCrypto
.when { $0.verify(.signature(message: anyArray(), publicKey: anyArray(), signature: anyArray())) }
.when { $0.verify(.signature(message: .any, publicKey: .any, signature: .any)) }
.thenReturn(false)
expect {
@ -212,7 +212,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
// MARK: ---- throws an error if it cannot get the senders x25519 public key
it("throws an error if it cannot get the senders x25519 public key") {
mockCrypto.when { $0.generate(.x25519(ed25519PublicKey: anyArray())) }.thenReturn(nil)
mockCrypto.when { $0.generate(.x25519(ed25519PublicKey: .any)) }.thenReturn(nil)
expect {
try MessageReceiver.decryptWithSessionProtocol(
@ -297,7 +297,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
// MARK: ---- throws an error if it cannot get the blinded keyPair
it("throws an error if it cannot get the blinded keyPair") {
mockCrypto
.when { $0.generate(.blindedKeyPair(serverPublicKey: any(), edKeyPair: any(), using: any())) }
.when { $0.generate(.blindedKeyPair(serverPublicKey: .any, edKeyPair: .any, using: .any)) }
.thenReturn(nil)
expect {
@ -326,11 +326,11 @@ class MessageReceiverDecryptionSpec: QuickSpec {
.when {
$0.generate(
.sharedBlindedEncryptionKey(
secretKey: anyArray(),
otherBlindedPublicKey: anyArray(),
fromBlindedPublicKey: anyArray(),
toBlindedPublicKey: anyArray(),
using: any()
secretKey: .any,
otherBlindedPublicKey: .any,
fromBlindedPublicKey: .any,
toBlindedPublicKey: .any,
using: .any
)
)
}
@ -384,9 +384,9 @@ class MessageReceiverDecryptionSpec: QuickSpec {
.when {
$0.generate(
.decryptedBytesAeadXChaCha20(
authenticatedCipherText: anyArray(),
secretKey: anyArray(),
nonce: anyArray()
authenticatedCipherText: .any,
secretKey: .any,
nonce: .any
)
)
}
@ -418,9 +418,9 @@ class MessageReceiverDecryptionSpec: QuickSpec {
.when {
$0.generate(
.decryptedBytesAeadXChaCha20(
authenticatedCipherText: anyArray(),
secretKey: anyArray(),
nonce: anyArray()
authenticatedCipherText: .any,
secretKey: .any,
nonce: .any
)
)
}
@ -449,7 +449,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
// MARK: ---- throws an error if it cannot generate the blinding factor
it("throws an error if it cannot generate the blinding factor") {
mockCrypto
.when { $0.generate(.blindingFactor(serverPublicKey: any(), using: any())) }
.when { $0.generate(.blindingFactor(serverPublicKey: .any, using: .any)) }
.thenReturn(nil)
expect {
@ -475,7 +475,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
// MARK: ---- throws an error if it cannot generate the combined key
it("throws an error if it cannot generate the combined key") {
mockCrypto
.when { $0.generate(.combinedKeys(lhsKeyBytes: anyArray(), rhsKeyBytes: anyArray())) }
.when { $0.generate(.combinedKeys(lhsKeyBytes: .any, rhsKeyBytes: .any)) }
.thenReturn(nil)
expect {
@ -501,7 +501,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
// MARK: ---- throws an error if the combined key does not match kA
it("throws an error if the combined key does not match kA") {
mockCrypto
.when { $0.generate(.combinedKeys(lhsKeyBytes: anyArray(), rhsKeyBytes: anyArray())) }
.when { $0.generate(.combinedKeys(lhsKeyBytes: .any, rhsKeyBytes: .any)) }
.thenReturn(Data(hex: TestConstants.publicKey).bytes)
expect {
@ -527,7 +527,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
// MARK: ---- throws an error if it cannot get the senders x25519 public key
it("throws an error if it cannot get the senders x25519 public key") {
mockCrypto
.when { $0.generate(.x25519(ed25519PublicKey: anyArray())) }
.when { $0.generate(.x25519(ed25519PublicKey: .any)) }
.thenReturn(nil)
expect {

@ -0,0 +1,340 @@
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import Combine
import GRDB
import Quick
import Nimble
import SessionUtil
import SessionUtilitiesKit
import SessionUIKit
@testable import SessionMessagingKit
class MessageReceiverGroupsSpec: QuickSpec {
override class func spec() {
// MARK: Configuration
let groupSeed: Data = Data(hex: "0123456789abcdef0123456789abcdeffedcba9876543210fedcba9876543210")
let groupKeyPair: KeyPair = Crypto().generate(.ed25519KeyPair(seed: groupSeed))!
@TestState var groupId: SessionId! = SessionId(.group, hex: "03cbd569f56fb13ea95a3f0c05c331cc24139c0090feb412069dc49fab34406ece")
@TestState var groupSecretKey: Data! = Data(hex:
"0123456789abcdef0123456789abcdeffedcba9876543210fedcba9876543210" +
"cbd569f56fb13ea95a3f0c05c331cc24139c0090feb412069dc49fab34406ece"
)
@TestState var dependencies: TestDependencies! = TestDependencies { dependencies in
dependencies.dateNow = Date(timeIntervalSince1970: 1234567890)
dependencies.forceSynchronous = true
dependencies.setMockableValue(JSONEncoder.OutputFormatting.sortedKeys) // Deterministic ordering
}
@TestState(singleton: .storage, in: dependencies) var mockStorage: Storage! = SynchronousStorage(
customWriter: try! DatabaseQueue(),
migrationTargets: [
SNUtilitiesKit.self,
SNMessagingKit.self,
SNUIKit.self
],
using: dependencies,
initialData: { db in
try Identity(variant: .x25519PublicKey, data: Data(hex: TestConstants.publicKey)).insert(db)
try Identity(variant: .x25519PrivateKey, data: Data(hex: TestConstants.privateKey)).insert(db)
try Identity(variant: .ed25519PublicKey, data: Data(hex: TestConstants.edPublicKey)).insert(db)
try Identity(variant: .ed25519SecretKey, data: Data(hex: TestConstants.edSecretKey)).insert(db)
try Profile(
id: "05\(TestConstants.publicKey)",
name: "TestCurrentUser"
).insert(db)
}
)
@TestState(defaults: .standard, in: dependencies) var mockUserDefaults: MockUserDefaults! = MockUserDefaults(
initialSetup: { userDefaults in
userDefaults.when { $0.string(forKey: .any) }.thenReturn(nil)
}
)
@TestState(singleton: .jobRunner, in: dependencies) var mockJobRunner: MockJobRunner! = MockJobRunner(
initialSetup: { jobRunner in
jobRunner
.when { $0.jobInfoFor(jobs: .any, state: .any, variant: .any) }
.thenReturn([:])
jobRunner
.when { $0.add(.any, job: .any, dependantJob: .any, canStartJob: .any, using: .any) }
.thenReturn(nil)
}
)
@TestState(singleton: .network, in: dependencies) var mockNetwork: MockNetwork! = MockNetwork(
initialSetup: { network in
network
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, timeout: .any, using: .any)) }
.thenReturn(MockNetwork.response(with: FileUploadResponse(id: "1")))
}
)
@TestState(singleton: .crypto, in: dependencies) var mockCrypto: MockCrypto! = MockCrypto(
initialSetup: { crypto in
crypto
.when { try $0.tryGenerate(.signature(message: .any, secretKey: .any)) }
.thenReturn(Authentication.Signature.standard(signature: "TestSignature".bytes))
crypto
.when { $0.verify(.signature(message: .any, publicKey: .any, signature: .any)) }
.thenReturn(true)
}
)
@TestState(cache: .general, in: dependencies) var mockGeneralCache: MockGeneralCache! = MockGeneralCache(
initialSetup: { cache in
cache.when { $0.sessionId }.thenReturn(SessionId(.standard, hex: TestConstants.publicKey))
}
)
@TestState var secretKey: [UInt8]! = Array(Data(hex: TestConstants.edSecretKey))
@TestState var groupEdPK: [UInt8]! = groupKeyPair.publicKey
@TestState var groupEdSK: [UInt8]! = groupKeyPair.secretKey
@TestState var userGroupsConfig: SessionUtil.Config! = {
var conf: UnsafeMutablePointer<config_object>!
_ = user_groups_init(&conf, &secretKey, nil, 0, nil)
return .object(conf)
}()
@TestState var convoInfoVolatileConfig: SessionUtil.Config! = {
var conf: UnsafeMutablePointer<config_object>!
_ = convo_info_volatile_init(&conf, &secretKey, nil, 0, nil)
return .object(conf)
}()
@TestState var groupInfoConf: UnsafeMutablePointer<config_object>! = {
var conf: UnsafeMutablePointer<config_object>!
_ = groups_info_init(&conf, &groupEdPK, &groupEdSK, nil, 0, nil)
return conf
}()
@TestState var groupMembersConf: UnsafeMutablePointer<config_object>! = {
var conf: UnsafeMutablePointer<config_object>!
_ = groups_members_init(&conf, &groupEdPK, &groupEdSK, nil, 0, nil)
return conf
}()
@TestState var groupInfoConfig: SessionUtil.Config! = .object(groupInfoConf)
@TestState var groupMembersConfig: SessionUtil.Config! = .object(groupMembersConf)
@TestState var groupKeysConfig: SessionUtil.Config! = {
var groupKeysConf: UnsafeMutablePointer<config_group_keys>!
_ = groups_keys_init(&groupKeysConf, &secretKey, &groupEdPK, &groupEdSK, groupInfoConf, groupMembersConf, nil, 0, nil)
return .groupKeys(groupKeysConf, info: groupInfoConf, members: groupMembersConf)
}()
@TestState(cache: .sessionUtil, in: dependencies) var mockSessionUtilCache: MockSessionUtilCache! = MockSessionUtilCache(
initialSetup: { cache in
let userSessionId: SessionId = SessionId(.standard, hex: TestConstants.publicKey)
cache
.when { $0.setConfig(for: .any, sessionId: .any, to: .any) }
.thenReturn(())
cache
.when { $0.config(for: .userGroups, sessionId: userSessionId) }
.thenReturn(Atomic(userGroupsConfig))
cache
.when { $0.config(for: .convoInfoVolatile, sessionId: userSessionId) }
.thenReturn(Atomic(convoInfoVolatileConfig))
cache
.when { $0.config(for: .groupInfo, sessionId: groupId) }
.thenReturn(Atomic(groupInfoConfig))
cache
.when { $0.config(for: .groupMembers, sessionId: groupId) }
.thenReturn(Atomic(groupMembersConfig))
cache
.when { $0.config(for: .groupKeys, sessionId: groupId) }
.thenReturn(Atomic(groupKeysConfig))
}
)
@TestState(singleton: .groupsPoller, in: dependencies) var mockGroupsPoller: MockPoller! = MockPoller(
initialSetup: { poller in
poller
.when { $0.startIfNeeded(for: .any, using: .any) }
.thenReturn(())
}
)
// MARK: - a MessageReceiver dealing with Groups
describe("a MessageReceiver dealing with Groups") {
// MARK: -- when receiving a group invigation
context("when receiving a group invigation") {
@TestState var inviteMessage: GroupUpdateInviteMessage! = {
let result: GroupUpdateInviteMessage? = try? GroupUpdateInviteMessage(
inviteeSessionIdHexString: "TestId",
groupSessionId: groupId,
groupName: "TestGroup",
memberAuthData: Data([1, 2, 3]),
sentTimestamp: 1234567890,
authMethod: Authentication.groupAdmin(
groupSessionId: groupId,
ed25519SecretKey: []
),
using: dependencies
)
result?.sender = "051111111111111111111111111111111111111111111111111111111111111111"
return result
}()
// MARK: ---- ignores the invitation if the signature is invalid
it("ignores the invitation if the signature is invalid") {
mockCrypto
.when { $0.verify(.signature(message: .any, publicKey: .any, signature: .any)) }
.thenReturn(false)
mockStorage.write { db in
try MessageReceiver.handleGroupUpdateMessage(
db,
threadId: groupId.hexString,
threadVariant: .group,
message: inviteMessage,
using: dependencies
)
}
let threads: [SessionThread]? = mockStorage.read { db in try SessionThread.fetchAll(db) }
expect(threads).to(beEmpty())
}
// MARK: ---- with profile information
context("with profile information") {
// MARK: ------ updates the profile name
it("updates the profile name") {
inviteMessage.profile = VisibleMessage.VMProfile(displayName: "TestName")
mockStorage.write { db in
try MessageReceiver.handleGroupUpdateMessage(
db,
threadId: groupId.hexString,
threadVariant: .group,
message: inviteMessage,
using: dependencies
)
}
let profiles: [Profile]? = mockStorage.read { db in try Profile.fetchAll(db) }
expect(profiles?.map { $0.name }.sorted()).to(equal(["TestCurrentUser", "TestName"]))
}
// MARK: ------ schedules a displayPictureDownload job if there is a profile picture
it("schedules a displayPictureDownload job if there is a profile picture") {
inviteMessage.profile = VisibleMessage.VMProfile(
displayName: "TestName",
profileKey: Data((0..<DisplayPictureManager.aes256KeyByteLength)
.map { _ in 1 }),
profilePictureUrl: "https://www.oxen.io/1234"
)
mockStorage.write { db in
try MessageReceiver.handleGroupUpdateMessage(
db,
threadId: groupId.hexString,
threadVariant: .group,
message: inviteMessage,
using: dependencies
)
}
expect(mockJobRunner)
.to(call(.exactly(times: 1), matchingParameters: .all) {
$0.add(
.any,
job: Job(
variant: .displayPictureDownload,
shouldBeUnique: true,
details: DisplayPictureDownloadJob.Details(
target: .profile(
id: "051111111111111111111111111111111" + "111111111111111111111111111111111",
url: "https://www.oxen.io/1234",
encryptionKey: Data((0..<DisplayPictureManager.aes256KeyByteLength)
.map { _ in 1 })
),
timestamp: 1234567890
)
),
canStartJob: true,
using: .any
)
})
}
}
// MARK: ---- creates the thread
it("creates the thread") {
mockStorage.write { db in
try MessageReceiver.handleGroupUpdateMessage(
db,
threadId: groupId.hexString,
threadVariant: .group,
message: inviteMessage,
using: dependencies
)
}
let threads: [SessionThread]? = mockStorage.read { db in try SessionThread.fetchAll(db) }
expect(threads?.count).to(equal(1))
expect(threads?.first?.id).to(equal(groupId.hexString))
}
// MARK: ---- creates the group
it("creates the group") {
mockStorage.write { db in
try MessageReceiver.handleGroupUpdateMessage(
db,
threadId: groupId.hexString,
threadVariant: .group,
message: inviteMessage,
using: dependencies
)
}
let groups: [ClosedGroup]? = mockStorage.read { db in try ClosedGroup.fetchAll(db) }
expect(groups?.count).to(equal(1))
expect(groups?.first?.id).to(equal(groupId.hexString))
expect(groups?.first?.name).to(equal("TestGroup"))
}
// MARK: ---- adds the invited control message if the thread does not exist
it("adds the invited control message if the thread does not exist") {
mockStorage.write { db in
try MessageReceiver.handleGroupUpdateMessage(
db,
threadId: groupId.hexString,
threadVariant: .group,
message: inviteMessage,
using: dependencies
)
}
let interactions: [Interaction]? = mockStorage.read { db in try Interaction.fetchAll(db) }
expect(interactions?.count).to(equal(1))
expect(interactions?.first?.body)
.to(equal("{\"invited\":{\"_0\":\"0511...1111\",\"_1\":\"TestGroup\"}}"))
}
// MARK: ---- does not add the invited control message if the thread already exists
it("does not add the invited control message if the thread already exists") {
mockStorage.write { db in
try SessionThread.fetchOrCreate(
db,
id: groupId.hexString,
variant: .group,
shouldBeVisible: true,
calledFromConfigHandling: false,
using: dependencies
)
}
mockStorage.write { db in
try MessageReceiver.handleGroupUpdateMessage(
db,
threadId: groupId.hexString,
threadVariant: .group,
message: inviteMessage,
using: dependencies
)
}
let interactions: [Interaction]? = mockStorage.read { db in try Interaction.fetchAll(db) }
expect(interactions?.count).to(equal(0))
}
}
}
}
}

@ -41,10 +41,10 @@ class MessageSenderEncryptionSpec: QuickSpec {
context("when encrypting with the session protocol") {
beforeEach {
mockCrypto
.when { $0.generate(.sealedBytes(message: anyArray(), recipientPublicKey: anyArray())) }
.when { $0.generate(.sealedBytes(message: .any, recipientPublicKey: .any)) }
.thenReturn([1, 2, 3])
mockCrypto
.when { $0.generate(.signature(message: anyArray(), secretKey: anyArray())) }
.when { $0.generate(.signature(message: .any, secretKey: .any)) }
.thenReturn(Authentication.Signature.standard(signature: []))
}
@ -101,7 +101,7 @@ class MessageSenderEncryptionSpec: QuickSpec {
// MARK: ---- throws an error if the signature generation fails
it("throws an error if the signature generation fails") {
mockCrypto
.when { try $0.generate(.signature(message: anyArray(), secretKey: anyArray())) }
.when { $0.generate(.signature(message: .any, secretKey: .any)) }
.thenReturn(nil)
mockStorage.read { db in
@ -120,7 +120,7 @@ class MessageSenderEncryptionSpec: QuickSpec {
// MARK: ---- throws an error if the encryption fails
it("throws an error if the encryption fails") {
mockCrypto
.when { $0.generate(.sealedBytes(message: anyArray(), recipientPublicKey: anyArray())) }
.when { $0.generate(.sealedBytes(message: .any, recipientPublicKey: .any)) }
.thenReturn(nil)
mockStorage.read { db in
@ -141,7 +141,7 @@ class MessageSenderEncryptionSpec: QuickSpec {
context("when encrypting with the blinded session protocol") {
beforeEach {
mockCrypto
.when { $0.generate(.blindedKeyPair(serverPublicKey: any(), edKeyPair: any(), using: any())) }
.when { $0.generate(.blindedKeyPair(serverPublicKey: .any, edKeyPair: .any, using: .any)) }
.thenReturn(
KeyPair(
publicKey: Data(hex: TestConstants.publicKey).bytes,
@ -152,11 +152,11 @@ class MessageSenderEncryptionSpec: QuickSpec {
.when {
$0.generate(
.sharedBlindedEncryptionKey(
secretKey: anyArray(),
otherBlindedPublicKey: anyArray(),
fromBlindedPublicKey: anyArray(),
toBlindedPublicKey: anyArray(),
using: any()
secretKey: .any,
otherBlindedPublicKey: .any,
fromBlindedPublicKey: .any,
toBlindedPublicKey: .any,
using: .any
)
)
}
@ -165,11 +165,11 @@ class MessageSenderEncryptionSpec: QuickSpec {
.when {
$0.generate(
.encryptedBytesAeadXChaCha20(
message: anyArray(),
secretKey: anyArray(),
nonce: anyArray(),
additionalData: anyArray(),
using: any()
message: .any,
secretKey: .any,
nonce: .any,
additionalData: .any,
using: .any
)
)
}
@ -282,7 +282,7 @@ class MessageSenderEncryptionSpec: QuickSpec {
// MARK: ---- throws an error if it fails to generate a blinded keyPair
it("throws an error if it fails to generate a blinded keyPair") {
mockCrypto
.when { $0.generate(.blindedKeyPair(serverPublicKey: any(), edKeyPair: any(), using: any())) }
.when { $0.generate(.blindedKeyPair(serverPublicKey: .any, edKeyPair: .any, using: .any)) }
.thenReturn(nil)
mockStorage.read { db in
@ -305,11 +305,11 @@ class MessageSenderEncryptionSpec: QuickSpec {
.when {
$0.generate(
.sharedBlindedEncryptionKey(
secretKey: anyArray(),
otherBlindedPublicKey: anyArray(),
fromBlindedPublicKey: anyArray(),
toBlindedPublicKey: anyArray(),
using: any()
secretKey: .any,
otherBlindedPublicKey: .any,
fromBlindedPublicKey: .any,
toBlindedPublicKey: .any,
using: .any
)
)
}
@ -335,10 +335,10 @@ class MessageSenderEncryptionSpec: QuickSpec {
.when {
$0.generate(
.encryptedBytesAeadXChaCha20(
message: anyArray(),
secretKey: anyArray(),
nonce: anyArray(),
additionalData: anyArray(),
message: .any,
secretKey: .any,
nonce: .any,
additionalData: .any,
using: dependencies
)
)

@ -47,17 +47,35 @@ class MessageSenderGroupsSpec: QuickSpec {
).insert(db)
}
)
@TestState(defaults: .standard, in: dependencies) var mockUserDefaults: MockUserDefaults! = MockUserDefaults(
initialSetup: { userDefaults in
userDefaults.when { $0.string(forKey: .any) }.thenReturn(nil)
}
)
@TestState(singleton: .jobRunner, in: dependencies) var mockJobRunner: MockJobRunner! = MockJobRunner(
initialSetup: { jobRunner in
jobRunner
.when { $0.jobInfoFor(jobs: .any, state: .any, variant: .any) }
.thenReturn([:])
jobRunner
.when { $0.add(.any, job: .any, dependantJob: .any, canStartJob: .any, using: .any) }
.thenReturn(nil)
}
)
@TestState(singleton: .network, in: dependencies) var mockNetwork: MockNetwork! = MockNetwork(
initialSetup: { network in
network
.when { $0.send(.selectedNetworkRequest(any(), to: any(), timeout: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, timeout: .any, using: .any)) }
.thenReturn(HTTP.BatchResponse.mockConfigSyncResponse)
network
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, timeout: .any, using: .any)) }
.thenReturn(MockNetwork.response(with: FileUploadResponse(id: "1")))
}
)
@TestState(singleton: .crypto, in: dependencies) var mockCrypto: MockCrypto! = MockCrypto(
initialSetup: { crypto in
crypto
.when { crypto in crypto.generate(.ed25519KeyPair(seed: any(), using: any())) }
.when { crypto in crypto.generate(.ed25519KeyPair(seed: .any, using: .any)) }
.thenReturn(
KeyPair(
publicKey: Data(hex: groupId.hexString).bytes,
@ -65,14 +83,30 @@ class MessageSenderGroupsSpec: QuickSpec {
)
)
crypto
.when { try $0.generate(.signature(message: anyArray(), secretKey: anyArray())) }
.when { $0.generate(.signature(message: .any, secretKey: .any)) }
.thenReturn(Authentication.Signature.standard(signature: "TestSignature".bytes))
crypto
.when { try $0.generate(.memberAuthData(config: any(), groupSessionId: any(), memberId: any())) }
.when { $0.generate(.memberAuthData(config: .any, groupSessionId: .any, memberId: .any)) }
.thenReturn(Authentication.Info.groupMember(
groupSessionId: SessionId(.standard, hex: TestConstants.publicKey),
authData: "TestAuthData".data(using: .utf8)!
))
crypto
.when { try $0.tryGenerate(.randomBytes(numberBytes: .any)) }
.thenReturn(Data((0..<DisplayPictureManager.aes256KeyByteLength).map { _ in 1 }))
crypto
.when { $0.generate(.uuid()) }
.thenReturn(UUID(uuidString: "00000000-0000-0000-0000-000000000000")!)
crypto
.when { $0.generate(.encryptedDataDisplayPicture(data: .any, key: .any, using: .any)) }
.thenReturn(TestConstants.validImageData)
}
)
@TestState(singleton: .keychain, in: dependencies) var mockKeychain: MockKeychain! = MockKeychain(
initialSetup: { keychain in
keychain
.when { try $0.data(forService: .pushNotificationAPI, key: .pushNotificationEncryptionKey) }
.thenReturn(Data((0..<PushNotificationAPI.encryptionKeyLength).map { _ in 1 }))
}
)
@TestState(cache: .general, in: dependencies) var mockGeneralCache: MockGeneralCache! = MockGeneralCache(
@ -114,7 +148,7 @@ class MessageSenderGroupsSpec: QuickSpec {
let userSessionId: SessionId = SessionId(.standard, hex: TestConstants.publicKey)
cache
.when { $0.setConfig(for: any(), sessionId: any(), to: any()) }
.when { $0.setConfig(for: .any, sessionId: .any, to: .any) }
.thenReturn(())
cache
.when { $0.config(for: .userGroups, sessionId: userSessionId) }
@ -160,7 +194,7 @@ class MessageSenderGroupsSpec: QuickSpec {
@TestState(singleton: .groupsPoller, in: dependencies) var mockGroupsPoller: MockPoller! = MockPoller(
initialSetup: { poller in
poller
.when { $0.startIfNeeded(for: any(), using: any()) }
.when { $0.startIfNeeded(for: .any, using: .any) }
.thenReturn(())
}
)
@ -301,8 +335,8 @@ class MessageSenderGroupsSpec: QuickSpec {
.sinkAndStore(in: &disposables)
expect(mockGroupsPoller)
.to(call(.exactly(times: 1), matchingParameters: .all) { [dependencies = dependencies!] poller in
poller.startIfNeeded(for: groupId.hexString, using: dependencies)
.to(call(.exactly(times: 1), matchingParameters: .all) { poller in
poller.startIfNeeded(for: groupId.hexString, using: .any)
})
}
@ -376,13 +410,13 @@ class MessageSenderGroupsSpec: QuickSpec {
.sinkAndStore(in: &disposables)
expect(mockNetwork)
.to(call(.exactly(times: 1), matchingParameters: .all) { [dependencies = dependencies!] network in
.to(call(.exactly(times: 1), matchingParameters: .all) { network in
network.send(
.selectedNetworkRequest(
expectedSendData,
to: dependencies.randomElement(mockSwarmCache)!,
timeout: HTTP.defaultTimeout,
using: dependencies
using: .any
)
)
})
@ -392,7 +426,7 @@ class MessageSenderGroupsSpec: QuickSpec {
context("and the group configuration sync fails") {
beforeEach {
mockNetwork
.when { $0.send(.selectedNetworkRequest(any(), to: any(), timeout: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, timeout: .any, using: .any)) }
.thenReturn(MockNetwork.errorResponse())
}
@ -467,6 +501,281 @@ class MessageSenderGroupsSpec: QuickSpec {
expect(members).to(beEmpty())
}
}
// MARK: ------ does not upload an image if none is provided
it("does not upload an image if none is provided") {
MessageSender
.createGroup(
name: "TestGroupName",
description: nil,
displayPictureData: nil,
members: [
("051111111111111111111111111111111111111111111111111111111111111111", nil)
],
using: dependencies
)
.mapError { error.setting(to: $0) }
.sinkAndStore(in: &disposables)
let expectedRequest: URLRequest = try FileServerAPI
.preparedUpload(TestConstants.validImageData, using: dependencies)
.request
expect(mockNetwork)
.toNot(call { network in
network.send(
.selectedNetworkRequest(
expectedRequest,
to: FileServerAPI.server,
with: FileServerAPI.serverPublicKey,
timeout: FileServerAPI.fileUploadTimeout,
using: .any
)
)
})
}
// MARK: ------ with an image
context("with an image") {
// MARK: ------ uploads the image
it("uploads the image") {
MessageSender
.createGroup(
name: "TestGroupName",
description: nil,
displayPictureData: TestConstants.validImageData,
members: [
("051111111111111111111111111111111111111111111111111111111111111111", nil)
],
using: dependencies
)
.mapError { error.setting(to: $0) }
.sinkAndStore(in: &disposables)
let expectedRequest: URLRequest = try FileServerAPI
.preparedUpload(TestConstants.validImageData, using: dependencies)
.request
expect(mockNetwork)
.to(call(.exactly(times: 1), matchingParameters: .all) { network in
network.send(
.selectedNetworkRequest(
expectedRequest,
to: FileServerAPI.server,
with: FileServerAPI.serverPublicKey,
timeout: FileServerAPI.fileUploadTimeout,
using: .any
)
)
})
}
// MARK: ------ saves the image info to the group
it("saves the image info to the group") {
MessageSender
.createGroup(
name: "TestGroupName",
description: nil,
displayPictureData: TestConstants.validImageData,
members: [
("051111111111111111111111111111111111111111111111111111111111111111", nil)
],
using: dependencies
)
.mapError { error.setting(to: $0) }
.sinkAndStore(in: &disposables)
let groups: [ClosedGroup]? = mockStorage.read { db in try ClosedGroup.fetchAll(db) }
expect(groups?.first?.displayPictureUrl).to(equal("http://filev2.getsession.org/file/1"))
expect(groups?.first?.displayPictureFilename)
.to(equal("00000000-0000-0000-0000-000000000000.jpg"))
expect(groups?.first?.displayPictureEncryptionKey)
.to(equal(Data((0..<DisplayPictureManager.aes256KeyByteLength).map { _ in 1 })))
}
// MARK: ------ fails if the image fails to upload
it("fails if the image fails to upload") {
mockNetwork
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, timeout: .any, using: .any)) }
.thenReturn(Fail(error: HTTPError.generic).eraseToAnyPublisher())
MessageSender
.createGroup(
name: "TestGroupName",
description: nil,
displayPictureData: TestConstants.validImageData,
members: [
("051111111111111111111111111111111111111111111111111111111111111111", nil)
],
using: dependencies
)
.mapError { error.setting(to: $0) }
.sinkAndStore(in: &disposables)
expect(error).to(matchError(DisplayPictureError.uploadFailed))
}
}
// MARK: ---- schedules member invite jobs
it("schedules member invite jobs") {
MessageSender
.createGroup(
name: "TestGroupName",
description: nil,
displayPictureData: nil,
members: [
("051111111111111111111111111111111111111111111111111111111111111111", nil)
],
using: dependencies
)
.sinkAndStore(in: &disposables)
expect(mockJobRunner)
.to(call(.exactly(times: 1), matchingParameters: .all) { jobRunner in
jobRunner.add(
.any,
job: Job(
variant: .groupInviteMember,
threadId: groupId.hexString,
details: try? GroupInviteMemberJob.Details(
memberSessionIdHexString: "051111111111111111111111111111111111111111111111111111111111111111",
authInfo: .groupMember(
groupSessionId: SessionId(.standard, hex: TestConstants.publicKey),
authData: "TestAuthData".data(using: .utf8)!
)
)
),
dependantJob: nil,
canStartJob: true,
using: .any
)
})
}
// MARK: ------ and trying to subscribe for push notifications
context("and trying to subscribe for push notifications") {
// MARK: ---- subscribes when they are enabled
it("subscribes when they are enabled") {
mockUserDefaults
.when { $0.string(forKey: UserDefaults.StringKey.deviceToken.rawValue) }
.thenReturn(Data([5, 4, 3, 2, 1]).toHexString())
mockUserDefaults
.when { $0.bool(forKey: UserDefaults.BoolKey.isUsingFullAPNs.rawValue) }
.thenReturn(true)
MessageSender
.createGroup(
name: "TestGroupName",
description: nil,
displayPictureData: nil,
members: [
("051111111111111111111111111111111111111111111111111111111111111111", nil)
],
using: dependencies
)
.sinkAndStore(in: &disposables)
let expectedRequest: URLRequest = mockStorage.read(using: dependencies) { db in
try PushNotificationAPI
.preparedSubscribe(
db,
token: Data([5, 4, 3, 2, 1]),
sessionIds: [
SessionId(
.standard,
hex: "051111111111111111111111111111111111111111111111111111111111111111"
)
],
using: dependencies
)
.request
}!
expect(mockNetwork)
.to(call(.exactly(times: 1), matchingParameters: .all) { network in
network.send(
.selectedNetworkRequest(
expectedRequest,
to: PushNotificationAPI.server.value(using: dependencies),
with: PushNotificationAPI.serverPublicKey,
timeout: HTTP.defaultTimeout,
using: .any
)
)
})
}
// MARK: ---- does not subscribe if push notifications are disabled
it("does not subscribe if push notifications are disabled") {
mockUserDefaults
.when { $0.string(forKey: UserDefaults.StringKey.deviceToken.rawValue) }
.thenReturn(Data([5, 4, 3, 2, 1]).toHexString())
mockUserDefaults
.when { $0.bool(forKey: UserDefaults.BoolKey.isUsingFullAPNs.rawValue) }
.thenReturn(false)
MessageSender
.createGroup(
name: "TestGroupName",
description: nil,
displayPictureData: nil,
members: [
("051111111111111111111111111111111111111111111111111111111111111111", nil)
],
using: dependencies
)
.sinkAndStore(in: &disposables)
expect(mockNetwork)
.toNot(call { network in
network.send(
.selectedNetworkRequest(
.any,
to: PushNotificationAPI.server.value(using: dependencies),
with: PushNotificationAPI.serverPublicKey,
timeout: HTTP.defaultTimeout,
using: .any
)
)
})
}
// MARK: ---- does not subscribe if there is no push token
it("does not subscribe if there is no push token") {
mockUserDefaults
.when { $0.string(forKey: UserDefaults.StringKey.deviceToken.rawValue) }
.thenReturn(nil)
mockUserDefaults
.when { $0.bool(forKey: UserDefaults.BoolKey.isUsingFullAPNs.rawValue) }
.thenReturn(true)
MessageSender
.createGroup(
name: "TestGroupName",
description: nil,
displayPictureData: nil,
members: [
("051111111111111111111111111111111111111111111111111111111111111111", nil)
],
using: dependencies
)
.sinkAndStore(in: &disposables)
expect(mockNetwork)
.toNot(call { network in
network.send(
.selectedNetworkRequest(
.any,
to: PushNotificationAPI.server.value(using: dependencies),
with: PushNotificationAPI.serverPublicKey,
timeout: HTTP.defaultTimeout,
using: .any
)
)
})
}
}
}
}
}
@ -475,7 +784,7 @@ class MessageSenderGroupsSpec: QuickSpec {
// MARK: - Mock Types
extension SendMessagesResponse: Mocked {
static var mockValue: SendMessagesResponse = SendMessagesResponse(
static var mock: SendMessagesResponse = SendMessagesResponse(
hash: "hash",
swarm: [:],
hardFork: [1, 2],

@ -64,7 +64,7 @@ class CryptoSMKSpec: QuickSpec {
dependencies[singleton: .crypto] = mockCrypto
mockCrypto
.when { $0.generate(.hash(message: anyArray(), outputLength: any())) }
.when { $0.generate(.hash(message: .any, outputLength: .any)) }
.thenReturn(nil)
let result = crypto.generate(

@ -5,9 +5,9 @@ import SessionUtil
import SessionMessagingKit
extension SessionUtil.Config: Mocked {
static var mockValue: SessionUtil.Config = .invalid
static var mock: SessionUtil.Config = .invalid
}
extension ConfigDump.Variant: Mocked {
static var mockValue: ConfigDump.Variant = .userProfile
static var mock: ConfigDump.Variant = .userProfile
}

@ -9,11 +9,11 @@ import SessionUtilitiesKit
class MockPoller: Mock<PollerType>, PollerType {
func start(using dependencies: Dependencies) {
mockNoReturn(args: [dependencies])
mockNoReturn(untrackedArgs: [dependencies])
}
func startIfNeeded(for publicKey: String, using dependencies: Dependencies) {
mockNoReturn(args: [publicKey, dependencies])
mockNoReturn(args: [publicKey], untrackedArgs: [dependencies])
}
func stopAllPollers() {

@ -42,7 +42,7 @@ class PreparedRequestOnionRequestsSpec: QuickSpec {
context("when sending") {
beforeEach {
mockNetwork
.when { $0.send(.selectedNetworkRequest(any(), to: any(), with: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, using: .any)) }
.thenReturn(MockNetwork.response(with: 1))
}
@ -341,7 +341,7 @@ class PreparedRequestOnionRequestsSpec: QuickSpec {
beforeEach {
mockNetwork
.when { $0.send(.selectedNetworkRequest(any(), to: any(), with: any(), using: any())) }
.when { $0.send(.selectedNetworkRequest(.any, to: .any, with: .any, using: .any)) }
.thenReturn(
MockNetwork.batchResponseData(with: [
(endpoint: TestEndpoint.endpoint1, data: TestType.mockBatchSubResponse()),
@ -490,6 +490,7 @@ class PreparedRequestOnionRequestsSpec: QuickSpec {
expect(receivedCompletion).toNot(beNil())
}
}
}
}
}
@ -517,7 +518,7 @@ fileprivate enum TestEndpoint: EndpointType {
}
fileprivate struct TestType: Codable, Equatable, Mocked {
static var mockValue: TestType { TestType(intValue: 100, stringValue: "Test", optionalStringValue: nil) }
static var mock: TestType { TestType(intValue: 100, stringValue: "Test", optionalStringValue: nil) }
let intValue: Int
let stringValue: String

@ -5,7 +5,7 @@ import Foundation
@testable import SessionSnodeKit
extension Snode: Mocked {
static var mockValue: Snode = Snode(
static var mock: Snode = Snode(
address: "test",
port: 0,
ed25519PublicKey: TestConstants.edPublicKey,

@ -1,77 +0,0 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import Combine
import GRDB
import Sodium
import Curve25519Kit
import SessionUtilitiesKit
extension KeyPair: Mocked {
static var mockValue: KeyPair = KeyPair(
publicKey: Data(hex: TestConstants.publicKey).bytes,
secretKey: Data(hex: TestConstants.edSecretKey).bytes
)
}
extension ECKeyPair: Mocked {
static var mockValue: Self {
try! Self.init(
publicKeyData: Data(hex: TestConstants.publicKey),
privateKeyData: Data(hex: TestConstants.privateKey)
)
}
}
extension Database: Mocked {
static var mockValue: Database {
var result: Database!
try! DatabaseQueue().read { result = $0 }
return result!
}
}
extension Job: Mocked {
static var mockValue: Job = Job(variant: .messageSend)
}
extension Job.Variant: Mocked {
static var mockValue: Job.Variant = .messageSend
}
extension Network.RequestType: MockedGeneric {
typealias Generic = T
static func mockValue(type: T.Type) -> Network.RequestType<T> {
return Network.RequestType(id: "mock") { Fail(error: MockError.mockedData).eraseToAnyPublisher() }
}
}
extension AnyPublisher: MockedGeneric where Failure == Error {
typealias Generic = Output
static func mockValue(type: Output.Type) -> AnyPublisher<Output, Error> {
return Fail(error: MockError.mockedData).eraseToAnyPublisher()
}
}
extension Array: MockedGeneric {
typealias Generic = Element
static func mockValue(type: Element.Type) -> [Element] { return [] }
}
extension Dictionary: MockedDoubleGeneric {
typealias GenericA = Key
typealias GenericB = Value
static func mockValue(typeA: Key.Type, typeB: Value.Type) -> [Key: Value] { return [:] }
}
extension URLRequest: Mocked {
static var mockValue: URLRequest = URLRequest(url: URL(fileURLWithPath: "mock"))
}
extension NoResponse: Mocked {
static var mockValue: NoResponse = NoResponse()
}

@ -0,0 +1,33 @@
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import SessionUtilitiesKit
class MockKeychain: Mock<KeychainStorageType>, KeychainStorageType {
func string(forService service: KeychainStorage.ServiceKey, key: KeychainStorage.StringKey) throws -> String {
return try mockThrowing(args: [service, key])
}
func set(string: String, service: KeychainStorage.ServiceKey, key: KeychainStorage.StringKey) throws {
return try mockThrowing(args: [service, key])
}
func remove(service: KeychainStorage.ServiceKey, key: KeychainStorage.StringKey) throws {
return try mockThrowing(args: [service, key])
}
func data(forService service: KeychainStorage.ServiceKey, key: KeychainStorage.DataKey) throws -> Data {
return try mockThrowing(args: [service, key])
}
func set(data: Data, service: KeychainStorage.ServiceKey, key: KeychainStorage.DataKey) throws {
return try mockThrowing(args: [service, key])
}
func remove(service: KeychainStorage.ServiceKey, key: KeychainStorage.DataKey) throws {
return try mockThrowing(args: [service, key])
}
func removeAll() { mockNoReturn() }
}

@ -15,22 +15,22 @@ class MockNetwork: Mock<NetworkType>, NetworkType {
return mock(funcName: "send<\(T.self)>(\(request.id))", args: request.args)
}
static func response<T: Encodable>(info: MockResponseInfo = .mockValue, with value: T) -> AnyPublisher<(ResponseInfoType, Data?), Error> {
static func response<T: Encodable>(info: MockResponseInfo = .mock, with value: T) -> AnyPublisher<(ResponseInfoType, Data?), Error> {
return Just((info, try? JSONEncoder().with(outputFormatting: .sortedKeys).encode(value)))
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
static func response<T: Mocked & Encodable>(info: MockResponseInfo = .mockValue, type: T.Type) -> AnyPublisher<(ResponseInfoType, Data?), Error> {
return response(info: info, with: T.mockValue)
static func response<T: Mocked & Encodable>(info: MockResponseInfo = .mock, type: T.Type) -> AnyPublisher<(ResponseInfoType, Data?), Error> {
return response(info: info, with: T.mock)
}
static func response<T: Mocked & Encodable>(info: MockResponseInfo = .mockValue, type: Array<T>.Type) -> AnyPublisher<(ResponseInfoType, Data?), Error> {
return response(info: info, with: [T.mockValue])
static func response<T: Mocked & Encodable>(info: MockResponseInfo = .mock, type: Array<T>.Type) -> AnyPublisher<(ResponseInfoType, Data?), Error> {
return response(info: info, with: [T.mock])
}
static func batchResponseData<E: EndpointType>(
info: MockResponseInfo = .mockValue,
info: MockResponseInfo = .mock,
with value: [(endpoint: E, data: Data)]
) -> AnyPublisher<(ResponseInfoType, Data?), Error> {
let data: Data = "[\(value.map { String(data: $0.data, encoding: .utf8)! }.joined(separator: ","))]"
@ -41,13 +41,13 @@ class MockNetwork: Mock<NetworkType>, NetworkType {
.eraseToAnyPublisher()
}
static func response(info: MockResponseInfo = .mockValue, data: Data) -> AnyPublisher<(ResponseInfoType, Data?), Error> {
static func response(info: MockResponseInfo = .mock, data: Data) -> AnyPublisher<(ResponseInfoType, Data?), Error> {
return Just((info, data))
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
static func nullResponse(info: MockResponseInfo = .mockValue) -> AnyPublisher<(ResponseInfoType, Data?), Error> {
static func nullResponse(info: MockResponseInfo = .mock) -> AnyPublisher<(ResponseInfoType, Data?), Error> {
return Just((info, nil))
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
@ -61,7 +61,7 @@ class MockNetwork: Mock<NetworkType>, NetworkType {
// MARK: - MockResponseInfo
struct MockResponseInfo: ResponseInfoType, Mocked {
static let mockValue: MockResponseInfo = MockResponseInfo(requestData: .fallbackData, code: 200, headers: [:])
static let mock: MockResponseInfo = MockResponseInfo(requestData: .fallbackData, code: 200, headers: [:])
let requestData: RequestData
let code: Int
@ -110,9 +110,9 @@ extension Encodable where Self: Codable {
}
extension Mocked where Self: Codable {
static func mockBatchSubResponse() -> Data { return mockValue.batchSubResponse() }
static func mockBatchSubResponse() -> Data { return mock.batchSubResponse() }
}
extension Array where Element: Mocked, Element: Codable {
static func mockBatchSubResponse() -> Data { return [Element.mockValue].batchSubResponse() }
static func mockBatchSubResponse() -> Data { return [Element.mock].batchSubResponse() }
}

@ -1,77 +1,146 @@
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import Combine
import GRDB
import SessionUtilitiesKit
// MARK: - Mocked
protocol Mocked { static var mockValue: Self { get } }
protocol Mocked { static var mock: Self { get } }
protocol MockedGeneric {
associatedtype Generic
static func mockValue(type: Generic.Type) -> Self
static func mock(type: Generic.Type) -> Self
}
protocol MockedDoubleGeneric {
associatedtype GenericA
associatedtype GenericB
static func mockValue(typeA: GenericA.Type, typeB: GenericB.Type) -> Self
static func mock(typeA: GenericA.Type, typeB: GenericB.Type) -> Self
}
// MARK: - DSL
func any<R: Mocked>() -> R { R.mockValue }
func any<R: MockedGeneric>(type: R.Generic.Type) -> R { R.mockValue(type: type) }
func any<R: MockedDoubleGeneric>(typeA: R.GenericA.Type, typeB: R.GenericB.Type) -> R {
R.mockValue(typeA: typeA, typeB: typeB)
}
func any<R: FixedWidthInteger>() -> R { unsafeBitCast(0, to: R.self) }
func any<K: Hashable, V>() -> [K: V] { [:] }
func any() -> Float { 0 }
func any() -> Double { 0 }
func any() -> String { "" }
func any() -> Data { Data() }
func any() -> Bool { false }
func any() -> Error { TestError.mock }
func any() -> SessionId { SessionId.invalid }
func any() -> TestDependencies {
TestDependencies { dependencies in
dependencies.dateNow = Date(timeIntervalSince1970: 1234567890)
dependencies.forceSynchronous = true
/// Needs to be a function as you can't extend 'Any'
func anyAny() -> Any { 0 }
extension Mocked { static var any: Self { mock } }
extension Int: Mocked { static var mock: Int { 0 } }
extension Dictionary: Mocked { static var mock: Self { [:] } }
extension Float: Mocked { static var mock: Float { 0 } }
extension Double: Mocked { static var mock: Double { 0 } }
extension String: Mocked { static var mock: String { "" } }
extension Data: Mocked { static var mock: Data { Data() } }
extension Bool: Mocked { static var mock: Bool { false } }
// The below types either can't be mocked or use the 'MockedGeneric' or 'MockedDoubleGeneric' types
// so need their own direct 'any' values
extension Array { static var any: Self { mock(type: Element.self) } }
extension Dictionary { static var any: Self { mock(typeA: Key.self, typeB: Value.self) } }
extension Error { static var any: Error { TestError.mock } }
extension TimeInterval { static var any: TimeInterval { 0 } }
extension SessionId { static var any: SessionId { SessionId.invalid } }
extension Dependencies {
static var any: Dependencies {
TestDependencies { dependencies in
dependencies.dateNow = Date(timeIntervalSince1970: 1234567890)
dependencies.forceSynchronous = true
}
}
}
func anyAny() -> Any { 0 } // Unique name for compilation performance reasons
func anyArray<R>() -> [R] { [] } // Unique name for compilation performance reasons
func anySet<R>() -> Set<R> { Set() } // Unique name for compilation performance reasons
// MARK: - Conformance
// MARK: - Extensions
extension Database: Mocked {
static var mock: Database {
var result: Database!
try! DatabaseQueue().read { result = $0 }
return result!
}
}
extension URLRequest: Mocked {
static var mock: URLRequest = URLRequest(url: URL(fileURLWithPath: "mock"))
}
extension Array: MockedGeneric {
typealias Generic = Element
static func mock(type: Element.Type) -> [Element] { return [] }
}
extension Dictionary: MockedDoubleGeneric {
typealias GenericA = Key
typealias GenericB = Value
static func mock(typeA: Key.Type, typeB: Value.Type) -> [Key: Value] { return [:] }
}
extension AnyPublisher: MockedGeneric where Failure == Error {
typealias Generic = Output
static func any(type: Output.Type) -> AnyPublisher<Output, Error> { mock(type: type) }
static func mock(type: Output.Type) -> AnyPublisher<Output, Error> {
return Fail(error: MockError.mockedData).eraseToAnyPublisher()
}
}
extension HTTP.BatchSubResponse: MockedGeneric where T: Mocked {
typealias Generic = T
static func mockValue(type: Generic.Type) -> HTTP.BatchSubResponse<Generic> {
static func mock(type: Generic.Type) -> HTTP.BatchSubResponse<Generic> {
return HTTP.BatchSubResponse(
code: 200,
headers: [:],
body: Generic.mockValue,
body: Generic.mock,
failedToParseBody: false
)
}
}
extension HTTP.BatchSubResponse {
static func mockArrayValue<M: Mocked>(type: M.Type) -> HTTP.BatchSubResponse<Array<M>> {
static func mockArray<M: Mocked>(type: M.Type) -> HTTP.BatchSubResponse<Array<M>> {
return HTTP.BatchSubResponse(
code: 200,
headers: [:],
body: [M.mockValue],
body: [M.mock],
failedToParseBody: false
)
}
}
extension KeyPair: Mocked {
static var mock: KeyPair = KeyPair(
publicKey: Data(hex: TestConstants.publicKey).bytes,
secretKey: Data(hex: TestConstants.edSecretKey).bytes
)
}
extension Job: Mocked {
static var mock: Job = Job(variant: .mock)
}
extension Job.Variant: Mocked {
static var mock: Job.Variant = .messageSend
}
extension Network.RequestType: MockedGeneric {
typealias Generic = T
static func mock(type: T.Type) -> Network.RequestType<T> {
return Network.RequestType(id: "mock") { Fail(error: MockError.mockedData).eraseToAnyPublisher() }
}
}
extension NoResponse: Mocked {
static var mock: NoResponse = NoResponse()
}
// MARK: - Encodable Convenience
extension Mocked where Self: Encodable {

@ -11,6 +11,26 @@ enum TestConstants {
static let edSecretKey: String = "c010d89eccbaf5d1c6d19df766c6eedf965d4a28a56f87c9fc819edb59896dd9bac6e71efd7dfa4a83c98ed24f254ab2c267f9ccdb172a5280a0444ad24e89cc"
static let blindedPublicKey: String = "98932d4bccbe595a8789d7eb1629cefc483a0eaddc7e20e8fe5c771efafd9af5"
static let serverPublicKey: String = "c3b3c6f32f0ab5a57f853cc4f30f5da7fda5624b0c77b3fb0829de562ada081d"
static let invalidImageData: Data = Data([1, 2, 3])
static let validImageData: Data = Data(hex: "ffd8ffe000104a46494600010100004800480000ffe1008045" +
"78696600004d4d002a000000080005011200030000000100010000011a0005000000010000004a011b000500000001" +
"0000005201280003000000010002000087690004000000010000005a00000000000000480000000100000048000000" +
"010002a00200040000000100000001a0030004000000010000000100000000ffed003850686f746f73686f7020332e" +
"30003842494d04040000000000003842494d0425000000000010d41d8cd98f00b204e9800998ecf8427effc0001108" +
"0001000103011100021101031101ffc4001f0000010501010101010100000000000000000102030405060708090a0b" +
"ffc400b5100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342" +
"b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a" +
"636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6" +
"b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc4001f01" +
"00030101010101010101010000000000000102030405060708090a0bffc400b5110002010204040304070504040001" +
"0277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718" +
"191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a8283" +
"8485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5" +
"d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffdb00430001010101010101010101010101010101010101" +
"010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101ffdb" +
"0043010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" +
"0101010101010101010101010101010101010101ffdd00040001ffda000c03010002110311003f00fefe2803ffd9")
}
public enum TestError: Error, Equatable {

Loading…
Cancel
Save