From 7b8817ad0a18a8b23ef44cfa1f2a1650dca63f08 Mon Sep 17 00:00:00 2001 From: Doug Date: Fri, 1 Mar 2024 14:21:49 +0000 Subject: [PATCH] Add a defaultValue method and tests for RoomPermissions. --- ElementX.xcodeproj/project.pbxproj | 4 + .../RoomChangePermissionsScreenModels.swift | 24 ++--- .../Services/Room/RoomPermissions.swift | 58 ++++++++---- UnitTests/Sources/RoomPermissionsTests.swift | 91 +++++++++++++++++++ 4 files changed, 142 insertions(+), 35 deletions(-) create mode 100644 UnitTests/Sources/RoomPermissionsTests.swift diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 36d1a13d77..104e7cdebb 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -142,6 +142,7 @@ 21BF2B7CEDFE3CA67C5355AD /* test_image.png in Resources */ = {isa = PBXBuildFile; fileRef = C733D11B421CFE3A657EF230 /* test_image.png */; }; 21F29351EDD7B2A5534EE862 /* SecureBackupKeyBackupScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD558A898847C179E4B7A237 /* SecureBackupKeyBackupScreen.swift */; }; 22882C710BC99EC34A5024A0 /* UITestsScreenIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEBE5EA91E8691EDF364EC2 /* UITestsScreenIdentifier.swift */; }; + 2335D1AB954C151FD8779F45 /* RoomPermissionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0096BC5DA86AF6B6E5742AC /* RoomPermissionsTests.swift */; }; 234E2C782981003971ABE96E /* PermalinkBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F754E66A8970963B15B2A41E /* PermalinkBuilder.swift */; }; 23701DE32ACD6FD40AA992C3 /* MediaUploadingPreprocessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE203026B9AD3DB412439866 /* MediaUploadingPreprocessorTests.swift */; }; 237FC70AA257B935F53316BA /* SessionVerificationControllerProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D7E514F9DE4E3D72FDCAD /* SessionVerificationControllerProxy.swift */; }; @@ -2014,6 +2015,7 @@ EF98A02DED04075F7CF0C721 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/Localizable.strings; sourceTree = ""; }; EFF7BF82A950B91BC5469E91 /* ViewFrameReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewFrameReader.swift; sourceTree = ""; }; EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportServiceTests.swift; sourceTree = ""; }; + F0096BC5DA86AF6B6E5742AC /* RoomPermissionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPermissionsTests.swift; sourceTree = ""; }; F012CB5EE3F2B67359F6CC52 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = ""; }; F0205C03F98BE861EDABCB0D /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/Localizable.strings; sourceTree = ""; }; F08776C48FFB47CACF64ED10 /* ServerConfirmationScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreenViewModelTests.swift; sourceTree = ""; }; @@ -3443,6 +3445,7 @@ EC589E641AE46EFB2962534D /* RoomMemberDetailsViewModelTests.swift */, 69B63F817FE305548DB4B512 /* RoomMembersListViewModelTests.swift */, 58D295F0081084F38DB20893 /* RoomNotificationSettingsScreenViewModelTests.swift */, + F0096BC5DA86AF6B6E5742AC /* RoomPermissionsTests.swift */, B40233F2989AD49906BB310D /* RoomPollsHistoryScreenViewModelTests.swift */, 48FEFF746DB341CDB18D7AAA /* RoomRolesAndPermissionsScreenViewModelTests.swift */, 93CF7B19FFCF8EFBE0A8696A /* RoomScreenViewModelTests.swift */, @@ -5523,6 +5526,7 @@ 6B31508C6334C617360C2EAB /* RoomMemberDetailsViewModelTests.swift in Sources */, CAF8755E152204F55F8D6B5B /* RoomMembersListViewModelTests.swift in Sources */, E49F74BD93230BDEFFE5EA51 /* RoomNotificationSettingsScreenViewModelTests.swift in Sources */, + 2335D1AB954C151FD8779F45 /* RoomPermissionsTests.swift in Sources */, 7B1605C6FFD4D195F264A684 /* RoomPollsHistoryScreenViewModelTests.swift in Sources */, 84C631E734FD2555B39B681C /* RoomRolesAndPermissionsScreenViewModelTests.swift in Sources */, 46562110EE202E580A5FFD9C /* RoomScreenViewModelTests.swift in Sources */, diff --git a/ElementX/Sources/Screens/RoomChangePermissionsScreen/RoomChangePermissionsScreenModels.swift b/ElementX/Sources/Screens/RoomChangePermissionsScreen/RoomChangePermissionsScreenModels.swift index b57a12b360..dbcc546669 100644 --- a/ElementX/Sources/Screens/RoomChangePermissionsScreen/RoomChangePermissionsScreenModels.swift +++ b/ElementX/Sources/Screens/RoomChangePermissionsScreen/RoomChangePermissionsScreenModels.swift @@ -31,7 +31,7 @@ struct RoomChangePermissionsScreenViewState: BindableState { /// Whether or not there are and changes to be saved. var hasChanges: Bool { - bindings.settings.contains { currentPermissions[keyPath: $0.keyPath] ?? RoomPermissions.default[keyPath: $0.keyPath] != $0.value } + bindings.settings.contains { currentPermissions[keyPath: $0.keyPath] ?? RoomPermissions.defaultValue(for: $0.keyPath) != $0.value } } } @@ -60,50 +60,44 @@ extension RoomChangePermissionsScreenViewState { init(currentPermissions: RoomPermissions, group: RoomRolesAndPermissionsScreenPermissionsGroup) { switch group { case .roomDetails: - // swiftlint:disable force_unwrapping let settings = [ RoomPermissionsSetting(keyPath: \.roomName, - value: currentPermissions.roomName ?? RoomPermissions.default.roomName!, + value: currentPermissions.roomName ?? RoomPermissions.defaultValue(for: \.roomName), title: L10n.screenRoomChangePermissionsRoomName), RoomPermissionsSetting(keyPath: \.roomAvatar, - value: currentPermissions.roomAvatar ?? RoomPermissions.default.roomAvatar!, + value: currentPermissions.roomAvatar ?? RoomPermissions.defaultValue(for: \.roomAvatar), title: L10n.screenRoomChangePermissionsRoomAvatar), RoomPermissionsSetting(keyPath: \.roomTopic, - value: currentPermissions.roomTopic ?? RoomPermissions.default.roomTopic!, + value: currentPermissions.roomTopic ?? RoomPermissions.defaultValue(for: \.roomTopic), title: L10n.screenRoomChangePermissionsRoomTopic) ] - // swiftlint:enable force_unwrapping self.init(title: L10n.screenRoomChangePermissionsRoomDetails, currentPermissions: currentPermissions, bindings: .init(settings: settings)) case .messagesAndContent: - // swiftlint:disable force_unwrapping let settings = [ RoomPermissionsSetting(keyPath: \.eventsDefault, - value: currentPermissions.eventsDefault ?? RoomPermissions.default.eventsDefault!, + value: currentPermissions.eventsDefault ?? RoomPermissions.defaultValue(for: \.eventsDefault), title: L10n.screenRoomChangePermissionsSendMessages), RoomPermissionsSetting(keyPath: \.redact, - value: currentPermissions.redact ?? RoomPermissions.default.redact!, + value: currentPermissions.redact ?? RoomPermissions.defaultValue(for: \.redact), title: L10n.screenRoomChangePermissionsDeleteMessages) ] - // swiftlint:enable force_unwrapping self.init(title: L10n.screenRoomChangePermissionsMessagesAndContent, currentPermissions: currentPermissions, bindings: .init(settings: settings)) case .memberModeration: - // swiftlint:disable force_unwrapping let settings = [ RoomPermissionsSetting(keyPath: \.invite, - value: currentPermissions.invite ?? RoomPermissions.default.invite!, + value: currentPermissions.invite ?? RoomPermissions.defaultValue(for: \.invite), title: L10n.screenRoomChangePermissionsInvitePeople), RoomPermissionsSetting(keyPath: \.kick, - value: currentPermissions.kick ?? RoomPermissions.default.kick!, + value: currentPermissions.kick ?? RoomPermissions.defaultValue(for: \.kick), title: L10n.screenRoomChangePermissionsRemovePeople), RoomPermissionsSetting(keyPath: \.ban, - value: currentPermissions.ban ?? RoomPermissions.default.ban!, + value: currentPermissions.ban ?? RoomPermissions.defaultValue(for: \.ban), title: L10n.screenRoomChangePermissionsBanPeople) ] - // swiftlint:enable force_unwrapping self.init(title: L10n.screenRoomChangePermissionsMemberModeration, currentPermissions: currentPermissions, bindings: .init(settings: settings)) } diff --git a/ElementX/Sources/Services/Room/RoomPermissions.swift b/ElementX/Sources/Services/Room/RoomPermissions.swift index dce252e242..92a4333c10 100644 --- a/ElementX/Sources/Services/Room/RoomPermissions.swift +++ b/ElementX/Sources/Services/Room/RoomPermissions.swift @@ -34,40 +34,58 @@ struct RoomPermissionsSetting: Identifiable { } struct RoomPermissions { - // The level required to ban a user. + /// The level required to ban a user. var ban: RoomMemberDetails.Role? - // The level required to invite a user. + /// The level required to invite a user. var invite: RoomMemberDetails.Role? - // The level required to kick a user. + /// The level required to kick a user. var kick: RoomMemberDetails.Role? - // The level required to redact an event. + /// The level required to redact an event. var redact: RoomMemberDetails.Role? - // The default level required to send message events. + /// The default level required to send message events. var eventsDefault: RoomMemberDetails.Role? - // The default level required to send state events. + /// The default level required to send state events. var stateDefault: RoomMemberDetails.Role? - // The default power level for every user in the room. + /// The default power level for every user in the room. var usersDefault: RoomMemberDetails.Role? - // The level required to change the room's name. + /// The level required to change the room's name. var roomName: RoomMemberDetails.Role? - // The level required to change the room's avatar. + /// The level required to change the room's avatar. var roomAvatar: RoomMemberDetails.Role? - // The level required to change the room's topic. + /// The level required to change the room's topic. var roomTopic: RoomMemberDetails.Role? } extension RoomPermissions { + /// Returns the default value for a particular permission. + static func defaultValue(for keyPath: KeyPath) -> RoomMemberDetails.Role { + switch keyPath { + case \.ban: .moderator + case \.invite: .user + case \.kick: .moderator + case \.redact: .moderator + case \.eventsDefault: .user + case \.stateDefault: .moderator + case \.usersDefault: .user + case \.roomName: .moderator + case \.roomAvatar: .moderator + case \.roomTopic: .moderator + default: fatalError("Unexpected key path: \(keyPath)") + } + } + + /// Constructs a set of permissions using the default values. static var `default`: RoomPermissions { - RoomPermissions(ban: .moderator, - invite: .user, - kick: .moderator, - redact: .moderator, - eventsDefault: .user, - stateDefault: .moderator, - usersDefault: .user, - roomName: .moderator, - roomAvatar: .moderator, - roomTopic: .moderator) + RoomPermissions(ban: defaultValue(for: \.ban), + invite: defaultValue(for: \.invite), + kick: defaultValue(for: \.kick), + redact: defaultValue(for: \.redact), + eventsDefault: defaultValue(for: \.eventsDefault), + stateDefault: defaultValue(for: \.stateDefault), + usersDefault: defaultValue(for: \.usersDefault), + roomName: defaultValue(for: \.roomName), + roomAvatar: defaultValue(for: \.roomAvatar), + roomTopic: defaultValue(for: \.roomTopic)) } init(powerLevelChanges: RoomPowerLevelChanges) { diff --git a/UnitTests/Sources/RoomPermissionsTests.swift b/UnitTests/Sources/RoomPermissionsTests.swift new file mode 100644 index 0000000000..14936c525d --- /dev/null +++ b/UnitTests/Sources/RoomPermissionsTests.swift @@ -0,0 +1,91 @@ +// +// Copyright 2024 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import MatrixRustSDK +import XCTest + +@testable import ElementX + +class RoomPermissionsTests: XCTestCase { + func testEmptyFromRust() { + // Given an empty set of power level changes. + let powerLevelChanges = RoomPowerLevelChanges() + + // When creating room permissions from them. + let permissions = RoomPermissions(powerLevelChanges: powerLevelChanges) + + // Then none of the permissions should be set. + XCTAssertNil(permissions.ban) + XCTAssertNil(permissions.invite) + XCTAssertNil(permissions.kick) + XCTAssertNil(permissions.redact) + XCTAssertNil(permissions.eventsDefault) + XCTAssertNil(permissions.stateDefault) + XCTAssertNil(permissions.usersDefault) + XCTAssertNil(permissions.roomName) + XCTAssertNil(permissions.roomAvatar) + XCTAssertNil(permissions.roomTopic) + } + + func testCompleteFromRust() { + // Given a set of power level changes with all the values set to 100. + let powerLevelChanges = RoomPowerLevelChanges(ban: 100, + invite: 100, + kick: 100, + redact: 100, + eventsDefault: 100, + stateDefault: 100, + usersDefault: 100, + roomName: 100, + roomAvatar: 100, + roomTopic: 100) + + // When creating room permissions from them. + let permissions = RoomPermissions(powerLevelChanges: powerLevelChanges) + + // Then all of the permissions should be for an administrator. + XCTAssertEqual(permissions.ban, .administrator) + XCTAssertEqual(permissions.invite, .administrator) + XCTAssertEqual(permissions.kick, .administrator) + XCTAssertEqual(permissions.redact, .administrator) + XCTAssertEqual(permissions.eventsDefault, .administrator) + XCTAssertEqual(permissions.stateDefault, .administrator) + XCTAssertEqual(permissions.usersDefault, .administrator) + XCTAssertEqual(permissions.roomName, .administrator) + XCTAssertEqual(permissions.roomAvatar, .administrator) + XCTAssertEqual(permissions.roomTopic, .administrator) + } + + func testToRust() { + // Given a set of permissions where on some of the values have been set. + let permissions = RoomPermissions(roomName: .administrator, roomAvatar: .administrator, roomTopic: .administrator) + + // When creating power level changes from them. + let powerLevelChanges = permissions.makePowerLevelChanges() + + // Then only the permissions that were set should be included. + XCTAssertNil(powerLevelChanges.ban, "Unset values should be nil for Rust to merge with the current value.") + XCTAssertNil(powerLevelChanges.invite, "Unset values should be nil for Rust to merge with the current value.") + XCTAssertNil(powerLevelChanges.kick, "Unset values should be nil for Rust to merge with the current value.") + XCTAssertNil(powerLevelChanges.redact, "Unset values should be nil for Rust to merge with the current value.") + XCTAssertNil(powerLevelChanges.eventsDefault, "Unset values should be nil for Rust to merge with the current value.") + XCTAssertNil(powerLevelChanges.stateDefault, "Unset values should be nil for Rust to merge with the current value.") + XCTAssertNil(powerLevelChanges.usersDefault, "Unset values should be nil for Rust to merge with the current value.") + XCTAssertEqual(powerLevelChanges.roomName, 100) + XCTAssertEqual(powerLevelChanges.roomAvatar, 100) + XCTAssertEqual(powerLevelChanges.roomTopic, 100) + } +}