7, 'name' => 'Alice Example', 'email' => 'alice@example.test', 'role_name' => 'Accounts', 'role_id' => 2, 'is_active' => true], ['id' => 8, 'name' => 'Bob Example', 'email' => 'bob@example.test', 'role_name' => 'Technician', 'role_id' => 3, 'is_active' => false], ]; $edited = $users->validateForEdit(7, [ 'name' => ' Alice Updated ', 'email' => ' ALICE.UPDATED@EXAMPLE.TEST ', 'role_id' => '3', 'is_active' => 'yes', ], $existing); user_admin_assert_same(true, $edited['valid'], 'A valid user edit should pass.'); user_admin_assert_same('alice.updated@example.test', $edited['email'], 'User edit email should be normalized.'); user_admin_assert_same(7, $edited['id'], 'User edit should retain the explicit ID.'); $duplicate = $users->validateForEdit(7, [ 'name' => 'Alice Updated', 'email' => ' bob@example.test ', 'role_id' => 2, 'is_active' => true, ], $existing); user_admin_assert_same(false, $duplicate['valid'], 'A duplicate user email should fail edit validation.'); if (!isset($duplicate['errors']['email'])) throw new RuntimeException('Duplicate user email should produce an email error.'); user_admin_assert_same( ['valid' => true, 'id' => 7, 'is_active' => false, 'errors' => []], $users->validateDeactivate($existing[0]), 'Active users should be deactivatable.' ); user_admin_assert_same( ['valid' => true, 'id' => 8, 'is_active' => true, 'errors' => []], $users->validateReactivate($existing[1]), 'Inactive users should be reactivatable.' ); $protected = ['id' => 1, 'name' => 'Root', 'email' => 'root@example.test', 'role_name' => ' Administrator ', 'role_id' => 1, 'is_active' => true]; $protectedResult = $users->validateDeactivate($protected); user_admin_assert_same(false, $protectedResult['valid'], 'The Administrator account must not be deactivated.'); if (!isset($protectedResult['errors']['role'])) throw new RuntimeException('Protected Administrator deactivation should produce a role error.'); $reset = $users->validatePasswordReset($existing[0], 'Unique&Secure123'); user_admin_assert_same(true, $reset['valid'], 'A strong password reset should pass.'); if (array_key_exists('password', $reset)) throw new RuntimeException('Password reset validation must not return plaintext passwords.'); $weakReset = $users->validatePasswordReset($existing[0], 'Password123!'); user_admin_assert_same(false, $weakReset['valid'], 'Weak password reset input should fail.'); if (!isset($weakReset['errors']['password'])) throw new RuntimeException('Weak password reset should produce a password error.'); $payloadReset = $users->validateReset(['password' => 'Unique&Secure123']); user_admin_assert_same(true, $payloadReset['valid'], 'Password-only reset payloads should be supported.'); $roles = new RolePermissionService(); $available = ['clients.view', 'clients.manage', 'reports.view']; $assignment = $roles->validateAssignment(['id' => 4, 'name' => 'Support'], [' CLIENTS.VIEW ', 'reports.view', 'clients.view'], $available); user_admin_assert_same(true, $assignment['valid'], 'Known permissions should be assignable to a custom role.'); user_admin_assert_same(['clients.view', 'reports.view'], $assignment['permissions'], 'Permission assignments should be canonical and de-duplicated.'); $unknown = $roles->validateAssignment(['id' => 4, 'name' => 'Support'], ['clients.view', 'users.delete'], $available); user_admin_assert_same(false, $unknown['valid'], 'Unknown permissions must not be assignable.'); if (!isset($unknown['errors']['permissions'])) throw new RuntimeException('Unknown permission should produce a permissions error.'); $protectedRole = $roles->validateAssignment(['id' => 1, 'name' => 'Administrator'], ['clients.view'], $available); user_admin_assert_same(false, $protectedRole['valid'], 'Administrator permissions must be protected.'); if (!isset($protectedRole['errors']['role'])) throw new RuntimeException('Administrator permission changes should produce a role error.'); printf("User administration service tests: 8 passed\n");