updated existing preview tests and added a test for the single space cases

fixed a bug where was not possible to re-select the space members option with unknown spaces.

pr suggestions
This commit is contained in:
Mauro Romito
2025-11-26 15:50:22 +01:00
committed by Mauro
parent 2292f4bd4f
commit 66266c1223
20 changed files with 147 additions and 55 deletions

View File

@@ -16618,15 +16618,15 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable {
}
//MARK: - joinedParents
var joinedParentsRoomIDUnderlyingCallsCount = 0
var joinedParentsRoomIDCallsCount: Int {
var joinedParentsChildIDUnderlyingCallsCount = 0
var joinedParentsChildIDCallsCount: Int {
get {
if Thread.isMainThread {
return joinedParentsRoomIDUnderlyingCallsCount
return joinedParentsChildIDUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = joinedParentsRoomIDUnderlyingCallsCount
returnValue = joinedParentsChildIDUnderlyingCallsCount
}
return returnValue!
@@ -16634,29 +16634,29 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable {
}
set {
if Thread.isMainThread {
joinedParentsRoomIDUnderlyingCallsCount = newValue
joinedParentsChildIDUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
joinedParentsRoomIDUnderlyingCallsCount = newValue
joinedParentsChildIDUnderlyingCallsCount = newValue
}
}
}
}
var joinedParentsRoomIDCalled: Bool {
return joinedParentsRoomIDCallsCount > 0
var joinedParentsChildIDCalled: Bool {
return joinedParentsChildIDCallsCount > 0
}
var joinedParentsRoomIDReceivedRoomID: String?
var joinedParentsRoomIDReceivedInvocations: [String] = []
var joinedParentsChildIDReceivedChildID: String?
var joinedParentsChildIDReceivedInvocations: [String] = []
var joinedParentsRoomIDUnderlyingReturnValue: Result<[SpaceRoomProxyProtocol], SpaceServiceProxyError>!
var joinedParentsRoomIDReturnValue: Result<[SpaceRoomProxyProtocol], SpaceServiceProxyError>! {
var joinedParentsChildIDUnderlyingReturnValue: Result<[SpaceRoomProxyProtocol], SpaceServiceProxyError>!
var joinedParentsChildIDReturnValue: Result<[SpaceRoomProxyProtocol], SpaceServiceProxyError>! {
get {
if Thread.isMainThread {
return joinedParentsRoomIDUnderlyingReturnValue
return joinedParentsChildIDUnderlyingReturnValue
} else {
var returnValue: Result<[SpaceRoomProxyProtocol], SpaceServiceProxyError>? = nil
DispatchQueue.main.sync {
returnValue = joinedParentsRoomIDUnderlyingReturnValue
returnValue = joinedParentsChildIDUnderlyingReturnValue
}
return returnValue!
@@ -16664,26 +16664,26 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable {
}
set {
if Thread.isMainThread {
joinedParentsRoomIDUnderlyingReturnValue = newValue
joinedParentsChildIDUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
joinedParentsRoomIDUnderlyingReturnValue = newValue
joinedParentsChildIDUnderlyingReturnValue = newValue
}
}
}
}
var joinedParentsRoomIDClosure: ((String) async -> Result<[SpaceRoomProxyProtocol], SpaceServiceProxyError>)?
var joinedParentsChildIDClosure: ((String) async -> Result<[SpaceRoomProxyProtocol], SpaceServiceProxyError>)?
func joinedParents(roomID: String) async -> Result<[SpaceRoomProxyProtocol], SpaceServiceProxyError> {
joinedParentsRoomIDCallsCount += 1
joinedParentsRoomIDReceivedRoomID = roomID
func joinedParents(childID: String) async -> Result<[SpaceRoomProxyProtocol], SpaceServiceProxyError> {
joinedParentsChildIDCallsCount += 1
joinedParentsChildIDReceivedChildID = childID
DispatchQueue.main.async {
self.joinedParentsRoomIDReceivedInvocations.append(roomID)
self.joinedParentsChildIDReceivedInvocations.append(childID)
}
if let joinedParentsRoomIDClosure = joinedParentsRoomIDClosure {
return await joinedParentsRoomIDClosure(roomID)
if let joinedParentsChildIDClosure = joinedParentsChildIDClosure {
return await joinedParentsChildIDClosure(childID)
} else {
return joinedParentsRoomIDReturnValue
return joinedParentsChildIDReturnValue
}
}
}

View File

@@ -22,7 +22,7 @@ extension SpaceServiceProxyMock {
self.init()
joinedSpacesPublisher = .init(configuration.joinedSpaces)
joinedParentsRoomIDReturnValue = .success(configuration.joinedParentSpaces)
joinedParentsChildIDReturnValue = .success(configuration.joinedParentSpaces)
spaceRoomListSpaceIDClosure = { spaceID in
if let spaceRoomList = configuration.spaceRoomLists[spaceID] {
.success(spaceRoomList)

View File

@@ -7,7 +7,6 @@
//
import Foundation
import MatrixRustSDK
enum SecurityAndPrivacyScreenViewModelAction {
case displayEditAddressScreen
@@ -39,14 +38,11 @@ struct SecurityAndPrivacyScreenViewState: BindableState {
var canEditHistoryVisibility = false
var joinedParentSpaces: [SpaceRoomProxyProtocol] = []
/// The count of the intersection between the set of joined parent spaces and the set of spaces in the current access type
var selectableSpacesCount: Int {
Set(joinedParentSpaces.map(\.id) + currentSettings.accessType.spaceIDs).count
}
private var desiredJoinedParentSpaces: [SpaceRoomProxyProtocol] {
joinedParentSpaces.filter { bindings.desiredSettings.accessType.spaceIDs.contains($0.id) }
}
private var hasChanges: Bool {
currentSettings != bindings.desiredSettings
}
@@ -111,13 +107,9 @@ struct SecurityAndPrivacyScreenViewState: BindableState {
var spaceSelection: SpaceSelection {
if selectableSpacesCount > 1 {
.multiple
} else if let desiredJoinedParent = desiredJoinedParentSpaces.first {
// The parent space is joined by the user and is also currently selected
.singleJoined(desiredJoinedParent)
} else if let joinedParent = joinedParentSpaces.first {
// The parent space is joined by the user but is not currently selected
.singleJoined(joinedParent)
} else if let unknownSpaceID = bindings.desiredSettings.accessType.spaceIDs.first {
} else if let unknownSpaceID = currentSettings.accessType.spaceIDs.first {
// The space is not joined by the user but is currently selected
.singleUnknown(id: unknownSpaceID)
} else {

View File

@@ -47,7 +47,7 @@ class SecurityAndPrivacyScreenViewModel: SecurityAndPrivacyScreenViewModelType,
setupRoomDirectoryVisibility()
setupSubscriptions()
Task {
switch await clientProxy.spaceService.joinedParents(roomID: roomProxy.id) {
switch await clientProxy.spaceService.joinedParents(childID: roomProxy.id) {
case .success(let joinedParentSpaces):
state.joinedParentSpaces = joinedParentSpaces
case .failure:

View File

@@ -242,7 +242,7 @@ struct SecurityAndPrivacyScreen_Previews: PreviewProvider, TestablePreview {
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org",
spaceServiceConfiguration: .init(joinedParentSpaces: [space]))),
userIndicatorController: UserIndicatorControllerMock(),
appSettings: AppSettings())
appSettings: appSettings)
}()
static let multipleSpacesMembersViewModel = {
@@ -259,7 +259,7 @@ struct SecurityAndPrivacyScreen_Previews: PreviewProvider, TestablePreview {
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org",
spaceServiceConfiguration: .init(joinedParentSpaces: spaces))),
userIndicatorController: UserIndicatorControllerMock(),
appSettings: AppSettings())
appSettings: appSettings)
}()
static let askToJoinViewModel = {

View File

@@ -49,11 +49,11 @@ class SpaceServiceProxy: SpaceServiceProxyProtocol {
}
}
func joinedParents(roomID: String) async -> Result<[SpaceRoomProxyProtocol], SpaceServiceProxyError> {
func joinedParents(childID: String) async -> Result<[SpaceRoomProxyProtocol], SpaceServiceProxyError> {
do {
return try await .success(spaceService.joinedParentsOfChild(childId: roomID).map(SpaceRoomProxy.init))
return try await .success(spaceService.joinedParentsOfChild(childId: childID).map(SpaceRoomProxy.init))
} catch {
MXLog.error("Failed to get joined parents for \(roomID): \(error)")
MXLog.error("Failed to get joined parents for \(childID): \(error)")
return .failure(.sdkError(error))
}
}

View File

@@ -19,6 +19,6 @@ protocol SpaceServiceProxyProtocol {
func spaceRoomList(spaceID: String) async -> Result<SpaceRoomListProxyProtocol, SpaceServiceProxyError>
func leaveSpace(spaceID: String) async -> Result<LeaveSpaceHandleProxy, SpaceServiceProxyError>
/// Returns all the parent spaces of a room that user has joined.
func joinedParents(roomID: String) async -> Result<[SpaceRoomProxyProtocol], SpaceServiceProxyError>
/// Returns all the parent spaces of a child that user has joined.
func joinedParents(childID: String) async -> Result<[SpaceRoomProxyProtocol], SpaceServiceProxyError>
}

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:16615769f99c92cccb78bd85195c8a853050b91051847432bab85218fae918a7
size 168851

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4f9c1a75e0d349da93fe984d753b7a5d7d87d7c1e569a472ef791b1cd2fe09c2
size 207133

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:daa486a48c54f6cb612065f63c8b020140374b0858b99dc4c174853d8c58ef50
size 116280

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2176626e57e5427a9328dee7e04bcb0c88435c67c6c4d78e9f27639b67d8faf0
size 169819

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c10a822751f52c6dfd8a5983af1bb880ab940335f3162790d15625c80b347f4f
size 200593

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8b22a70b9ae221e2d2f533cb487092b2de92ca7b697a9f040263da7867dfcd62
size 246336

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fc11a77156dd88cda02776fa819bc685d55ee9ed1c7139b9baedca9c5460ba3f
size 137487

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:12aa5240ae6480e73aa483eae15cd7b259b527bed7dd02e7101b7ab1e38be77c
size 165861

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2c8692d0ac775372370d78d5be13fd0d4f1c52abfd8b0f139743d57f40fdd9d1
size 155663

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2533b636d1d9bae4ed280b5d07bd3bb0222b0b6b0fca8a5c11c327dac93f37e0
size 186317

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:695aabf1d7b8ed63450e6b4bcc869e03b0e65db75b63dbb2da6f6a858b9e866f
size 102182

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:16dc1a670bb862ffb6f1707b6e95bf7109613a0a7d76b677329b389a6decceb3
size 144655

View File

@@ -6,6 +6,7 @@
// Please see LICENSE files in the repository root for full details.
//
import MatrixRustSDK
import XCTest
@testable import ElementX
@@ -13,8 +14,95 @@ import XCTest
@MainActor
class SecurityAndPrivacyScreenViewModelTests: XCTestCase {
var viewModel: SecurityAndPrivacyScreenViewModelProtocol!
var roomProxy: JoinedRoomProxyMock!
var context: SecurityAndPrivacyScreenViewModelType.Context {
viewModel.context
}
override func tearDown() {
viewModel = nil
roomProxy = nil
AppSettings.resetAllSettings()
}
func testSetSingleJoinedSpaceMembersAccess() async throws {
let singleRoom = [SpaceRoomProxyProtocol].mockSingleRoom
let space = singleRoom[0]
setupViewModel(isSpaceSettingsEnabled: true, joinedParentSpaces: singleRoom, joinRule: .public)
let deferred = deferFulfillment(context.$viewState) { $0.joinedParentSpaces.count == 1 }
try await deferred.fulfill()
XCTAssertEqual(context.viewState.currentSettings.accessType, .anyone)
XCTAssertTrue(context.viewState.isSaveDisabled)
XCTAssertTrue(context.viewState.isSpaceMembersOptionSelectable)
guard case .singleJoined = context.viewState.spaceSelection else {
XCTFail("Expected spaceSelection to be .singleSpace")
return
}
context.send(viewAction: .selectedSpaceMembersAccess)
XCTAssertEqual(context.desiredSettings.accessType, .spaceUsers(spaceIDs: [space.id]))
XCTAssertNil(context.viewState.accessSectionFooter)
XCTAssertFalse(context.viewState.isSaveDisabled)
let expectation = expectation(description: "Join rule has updated")
roomProxy.updateJoinRuleClosure = { value in
XCTAssertEqual(value, .restricted(rules: [.roomMembership(roomId: space.id)]))
expectation.fulfill()
return .success(())
}
context.send(viewAction: .save)
await fulfillment(of: [expectation])
}
func testSingleUnknownSpaceMembersAccessCanBeReselected() async throws {
let singleRoom = [SpaceRoomProxyProtocol].mockSingleRoom
let space = singleRoom[0]
setupViewModel(isSpaceSettingsEnabled: true, joinedParentSpaces: [], joinRule: .restricted(rules: [.roomMembership(roomId: space.id)]))
let deferred = deferFulfillment(context.$viewState) { $0.joinedParentSpaces.count == 0 }
try await deferred.fulfill()
XCTAssertEqual(context.viewState.currentSettings.accessType, .spaceUsers(spaceIDs: [space.id]))
XCTAssertEqual(context.desiredSettings, context.viewState.currentSettings)
XCTAssertTrue(context.viewState.isSpaceMembersOptionSelectable)
XCTAssertNil(context.viewState.accessSectionFooter)
XCTAssertTrue(context.viewState.isSaveDisabled)
guard case .singleUnknown = context.viewState.spaceSelection else {
XCTFail("Expected spaceSelection to be .singleSpace")
return
}
context.desiredSettings.accessType = .anyone
XCTAssertTrue(context.viewState.isSpaceMembersOptionSelectable)
XCTAssertFalse(context.viewState.isSaveDisabled)
context.send(viewAction: .selectedSpaceMembersAccess)
XCTAssertTrue(context.viewState.isSaveDisabled)
XCTAssertEqual(context.desiredSettings.accessType, .spaceUsers(spaceIDs: [space.id]))
guard case .singleUnknown = context.viewState.spaceSelection else {
XCTFail("Expected spaceSelection to be .singleSpace")
return
}
}
private func setupViewModel(isSpaceSettingsEnabled: Bool,
joinedParentSpaces: [SpaceRoomProxyProtocol],
joinRule: JoinRule) {
let appSettings = AppSettings()
appSettings.spaceSettingsEnabled = isSpaceSettingsEnabled
roomProxy = JoinedRoomProxyMock(.init(isEncrypted: false,
canonicalAlias: "#room:matrix.org",
members: .allMembersAsCreator,
joinRule: joinRule,
isVisibleInPublicDirectory: true))
viewModel = SecurityAndPrivacyScreenViewModel(roomProxy: roomProxy,
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org",
spaceServiceConfiguration: .init(joinedParentSpaces: joinedParentSpaces))),
userIndicatorController: UserIndicatorControllerMock(),
appSettings: appSettings)
}
}