2020-06-02 06:48:37 -04:00
< ? php
declare ( strict_types = 1 );
/**
2024-05-29 05:32:54 -04:00
* SPDX - FileCopyrightText : 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX - License - Identifier : AGPL - 3.0 - or - later
2020-06-02 06:48:37 -04:00
*/
namespace OCA\UserStatus\Tests\Service ;
use OCA\UserStatus\Db\UserStatus ;
use OCA\UserStatus\Db\UserStatusMapper ;
use OCA\UserStatus\Exception\InvalidClearAtException ;
use OCA\UserStatus\Exception\InvalidMessageIdException ;
use OCA\UserStatus\Exception\InvalidStatusIconException ;
use OCA\UserStatus\Exception\InvalidStatusTypeException ;
use OCA\UserStatus\Exception\StatusMessageTooLongException ;
use OCA\UserStatus\Service\PredefinedStatusService ;
use OCA\UserStatus\Service\StatusService ;
use OCP\AppFramework\Db\DoesNotExistException ;
use OCP\AppFramework\Utility\ITimeFactory ;
2022-02-15 08:55:40 -05:00
use OCP\DB\Exception ;
2021-07-08 12:26:27 -04:00
use OCP\IConfig ;
2022-03-24 10:57:17 -04:00
use OCP\IEmojiHelper ;
2023-09-25 08:47:02 -04:00
use OCP\IUserManager ;
2021-06-04 06:03:16 -04:00
use OCP\UserStatus\IUserStatus ;
2023-09-25 08:47:02 -04:00
use PHPUnit\Framework\MockObject\MockObject ;
2024-06-24 10:28:43 -04:00
use Psr\Log\LoggerInterface ;
2020-06-02 06:48:37 -04:00
use Test\TestCase ;
class StatusServiceTest extends TestCase {
2025-05-13 16:23:39 -04:00
private UserStatusMapper & MockObject $mapper ;
private ITimeFactory & MockObject $timeFactory ;
private PredefinedStatusService & MockObject $predefinedStatusService ;
private IEmojiHelper & MockObject $emojiHelper ;
private IConfig & MockObject $config ;
private IUserManager & MockObject $userManager ;
private LoggerInterface & MockObject $logger ;
2024-06-24 10:28:43 -04:00
2023-09-25 08:47:02 -04:00
private StatusService $service ;
2020-06-02 06:48:37 -04:00
protected function setUp () : void {
parent :: setUp ();
$this -> mapper = $this -> createMock ( UserStatusMapper :: class );
$this -> timeFactory = $this -> createMock ( ITimeFactory :: class );
$this -> predefinedStatusService = $this -> createMock ( PredefinedStatusService :: class );
2022-03-24 10:57:17 -04:00
$this -> emojiHelper = $this -> createMock ( IEmojiHelper :: class );
2023-09-25 08:47:02 -04:00
$this -> userManager = $this -> createMock ( IUserManager :: class );
2021-07-08 12:26:27 -04:00
$this -> config = $this -> createMock ( IConfig :: class );
2024-06-24 10:28:43 -04:00
$this -> logger = $this -> createMock ( LoggerInterface :: class );
2021-07-08 12:26:27 -04:00
$this -> config -> method ( 'getAppValue' )
-> willReturnMap ([
[ 'core' , 'shareapi_allow_share_dialog_user_enumeration' , 'yes' , 'yes' ],
[ 'core' , 'shareapi_restrict_user_enumeration_to_group' , 'no' , 'no' ]
]);
2020-06-02 06:48:37 -04:00
$this -> service = new StatusService ( $this -> mapper ,
$this -> timeFactory ,
$this -> predefinedStatusService ,
2022-03-24 10:57:17 -04:00
$this -> emojiHelper ,
2023-09-25 08:47:02 -04:00
$this -> config ,
2024-06-24 10:28:43 -04:00
$this -> userManager ,
$this -> logger ,
2023-09-25 08:47:02 -04:00
);
2020-06-02 06:48:37 -04:00
}
public function testFindAll () : void {
$status1 = $this -> createMock ( UserStatus :: class );
$status2 = $this -> createMock ( UserStatus :: class );
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findAll' )
-> with ( 20 , 50 )
-> willReturn ([ $status1 , $status2 ]);
$this -> assertEquals ([
$status1 ,
$status2 ,
], $this -> service -> findAll ( 20 , 50 ));
}
2020-08-18 04:54:46 -04:00
public function testFindAllRecentStatusChanges () : void {
$status1 = $this -> createMock ( UserStatus :: class );
$status2 = $this -> createMock ( UserStatus :: class );
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findAllRecent' )
-> with ( 20 , 50 )
-> willReturn ([ $status1 , $status2 ]);
$this -> assertEquals ([
$status1 ,
$status2 ,
], $this -> service -> findAllRecentStatusChanges ( 20 , 50 ));
}
2021-07-08 12:26:27 -04:00
public function testFindAllRecentStatusChangesNoEnumeration () : void {
$status1 = $this -> createMock ( UserStatus :: class );
$status2 = $this -> createMock ( UserStatus :: class );
$this -> mapper -> method ( 'findAllRecent' )
-> with ( 20 , 50 )
-> willReturn ([ $status1 , $status2 ]);
// Rebuild $this->service with user enumeration turned off
$this -> config = $this -> createMock ( IConfig :: class );
$this -> config -> method ( 'getAppValue' )
-> willReturnMap ([
[ 'core' , 'shareapi_allow_share_dialog_user_enumeration' , 'yes' , 'no' ],
[ 'core' , 'shareapi_restrict_user_enumeration_to_group' , 'no' , 'no' ]
]);
$this -> service = new StatusService ( $this -> mapper ,
$this -> timeFactory ,
$this -> predefinedStatusService ,
2022-03-24 10:57:17 -04:00
$this -> emojiHelper ,
2023-09-25 08:47:02 -04:00
$this -> config ,
2024-06-24 10:28:43 -04:00
$this -> userManager ,
$this -> logger ,
2023-09-25 08:47:02 -04:00
);
2021-07-08 12:26:27 -04:00
$this -> assertEquals ([], $this -> service -> findAllRecentStatusChanges ( 20 , 50 ));
// Rebuild $this->service with user enumeration limited to common groups
$this -> config = $this -> createMock ( IConfig :: class );
$this -> config -> method ( 'getAppValue' )
-> willReturnMap ([
[ 'core' , 'shareapi_allow_share_dialog_user_enumeration' , 'yes' , 'yes' ],
[ 'core' , 'shareapi_restrict_user_enumeration_to_group' , 'no' , 'yes' ]
]);
$this -> service = new StatusService ( $this -> mapper ,
$this -> timeFactory ,
$this -> predefinedStatusService ,
2022-03-24 10:57:17 -04:00
$this -> emojiHelper ,
2023-09-25 08:47:02 -04:00
$this -> config ,
2024-06-24 10:28:43 -04:00
$this -> userManager ,
$this -> logger ,
2023-09-25 08:47:02 -04:00
);
2021-07-08 12:26:27 -04:00
$this -> assertEquals ([], $this -> service -> findAllRecentStatusChanges ( 20 , 50 ));
}
2020-06-02 06:48:37 -04:00
public function testFindByUserIdDoesNotExist () : void {
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( 'john.doe' )
-> willThrowException ( new DoesNotExistException ( '' ));
$this -> expectException ( DoesNotExistException :: class );
$this -> service -> findByUserId ( 'john.doe' );
}
public function testFindAllAddDefaultMessage () : void {
$status = new UserStatus ();
$status -> setMessageId ( 'commuting' );
$this -> predefinedStatusService -> expects ( $this -> once ())
-> method ( 'getDefaultStatusById' )
-> with ( 'commuting' )
-> willReturn ([
'id' => 'commuting' ,
'icon' => '🚌' ,
'message' => 'Commuting' ,
'clearAt' => [
'type' => 'period' ,
'time' => 1800 ,
],
]);
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( 'john.doe' )
-> willReturn ( $status );
$this -> assertEquals ( $status , $this -> service -> findByUserId ( 'john.doe' ));
$this -> assertEquals ( '🚌' , $status -> getCustomIcon ());
$this -> assertEquals ( 'Commuting' , $status -> getCustomMessage ());
}
public function testFindAllClearStatus () : void {
2020-09-02 06:25:02 -04:00
$status = new UserStatus ();
$status -> setStatus ( 'online' );
$status -> setStatusTimestamp ( 1000 );
$status -> setIsUserDefined ( true );
$this -> timeFactory -> method ( 'getTime' )
2020-09-30 10:17:18 -04:00
-> willReturn ( 2600 );
2020-09-02 06:25:02 -04:00
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( 'john.doe' )
-> willReturn ( $status );
$this -> assertEquals ( $status , $this -> service -> findByUserId ( 'john.doe' ));
$this -> assertEquals ( 'offline' , $status -> getStatus ());
2020-09-30 10:17:18 -04:00
$this -> assertEquals ( 2600 , $status -> getStatusTimestamp ());
2020-09-02 06:25:02 -04:00
$this -> assertFalse ( $status -> getIsUserDefined ());
}
public function testFindAllClearMessage () : void {
2020-06-02 06:48:37 -04:00
$status = new UserStatus ();
$status -> setClearAt ( 50 );
$status -> setMessageId ( 'commuting' );
2020-09-02 06:25:02 -04:00
$status -> setStatusTimestamp ( 60 );
2020-06-02 06:48:37 -04:00
2020-09-02 06:25:02 -04:00
$this -> timeFactory -> method ( 'getTime' )
2020-06-02 06:48:37 -04:00
-> willReturn ( 60 );
$this -> predefinedStatusService -> expects ( $this -> never ())
-> method ( 'getDefaultStatusById' );
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( 'john.doe' )
-> willReturn ( $status );
$this -> assertEquals ( $status , $this -> service -> findByUserId ( 'john.doe' ));
$this -> assertNull ( $status -> getClearAt ());
$this -> assertNull ( $status -> getMessageId ());
}
2025-06-30 10:56:59 -04:00
#[\PHPUnit\Framework\Attributes\DataProvider('setStatusDataProvider')]
2025-05-13 16:23:39 -04:00
public function testSetStatus (
string $userId ,
2023-11-23 04:22:34 -05:00
string $status ,
? int $statusTimestamp ,
bool $isUserDefined ,
bool $expectExisting ,
bool $expectSuccess ,
bool $expectTimeFactory ,
bool $expectException ,
? string $expectedExceptionClass ,
2025-05-13 16:23:39 -04:00
? string $expectedExceptionMessage ,
) : void {
2020-06-02 06:48:37 -04:00
$userStatus = new UserStatus ();
if ( $expectExisting ) {
$userStatus -> setId ( 42 );
$userStatus -> setUserId ( $userId );
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( $userId )
-> willReturn ( $userStatus );
} else {
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( $userId )
-> willThrowException ( new DoesNotExistException ( '' ));
}
if ( $expectTimeFactory ) {
$this -> timeFactory
-> method ( 'getTime' )
-> willReturn ( 40 );
}
if ( $expectException ) {
$this -> expectException ( $expectedExceptionClass );
$this -> expectExceptionMessage ( $expectedExceptionMessage );
$this -> service -> setStatus ( $userId , $status , $statusTimestamp , $isUserDefined );
}
if ( $expectSuccess ) {
if ( $expectExisting ) {
$this -> mapper -> expects ( $this -> once ())
-> method ( 'update' )
-> willReturnArgument ( 0 );
} else {
$this -> mapper -> expects ( $this -> once ())
-> method ( 'insert' )
-> willReturnArgument ( 0 );
}
$actual = $this -> service -> setStatus ( $userId , $status , $statusTimestamp , $isUserDefined );
$this -> assertEquals ( 'john.doe' , $actual -> getUserId ());
$this -> assertEquals ( $status , $actual -> getStatus ());
$this -> assertEquals ( $statusTimestamp ? ? 40 , $actual -> getStatusTimestamp ());
$this -> assertEquals ( $isUserDefined , $actual -> getIsUserDefined ());
}
}
2025-05-13 16:23:39 -04:00
public static function setStatusDataProvider () : array {
2020-06-02 06:48:37 -04:00
return [
[ 'john.doe' , 'online' , 50 , true , true , true , false , false , null , null ],
[ 'john.doe' , 'online' , 50 , true , false , true , false , false , null , null ],
[ 'john.doe' , 'online' , 50 , false , true , true , false , false , null , null ],
[ 'john.doe' , 'online' , 50 , false , false , true , false , false , null , null ],
[ 'john.doe' , 'online' , null , true , true , true , true , false , null , null ],
[ 'john.doe' , 'online' , null , true , false , true , true , false , null , null ],
[ 'john.doe' , 'online' , null , false , true , true , true , false , null , null ],
[ 'john.doe' , 'online' , null , false , false , true , true , false , null , null ],
[ 'john.doe' , 'away' , 50 , true , true , true , false , false , null , null ],
[ 'john.doe' , 'away' , 50 , true , false , true , false , false , null , null ],
[ 'john.doe' , 'away' , 50 , false , true , true , false , false , null , null ],
[ 'john.doe' , 'away' , 50 , false , false , true , false , false , null , null ],
[ 'john.doe' , 'away' , null , true , true , true , true , false , null , null ],
[ 'john.doe' , 'away' , null , true , false , true , true , false , null , null ],
[ 'john.doe' , 'away' , null , false , true , true , true , false , null , null ],
[ 'john.doe' , 'away' , null , false , false , true , true , false , null , null ],
[ 'john.doe' , 'dnd' , 50 , true , true , true , false , false , null , null ],
[ 'john.doe' , 'dnd' , 50 , true , false , true , false , false , null , null ],
[ 'john.doe' , 'dnd' , 50 , false , true , true , false , false , null , null ],
[ 'john.doe' , 'dnd' , 50 , false , false , true , false , false , null , null ],
[ 'john.doe' , 'dnd' , null , true , true , true , true , false , null , null ],
[ 'john.doe' , 'dnd' , null , true , false , true , true , false , null , null ],
[ 'john.doe' , 'dnd' , null , false , true , true , true , false , null , null ],
[ 'john.doe' , 'dnd' , null , false , false , true , true , false , null , null ],
[ 'john.doe' , 'invisible' , 50 , true , true , true , false , false , null , null ],
[ 'john.doe' , 'invisible' , 50 , true , false , true , false , false , null , null ],
[ 'john.doe' , 'invisible' , 50 , false , true , true , false , false , null , null ],
[ 'john.doe' , 'invisible' , 50 , false , false , true , false , false , null , null ],
[ 'john.doe' , 'invisible' , null , true , true , true , true , false , null , null ],
[ 'john.doe' , 'invisible' , null , true , false , true , true , false , null , null ],
[ 'john.doe' , 'invisible' , null , false , true , true , true , false , null , null ],
[ 'john.doe' , 'invisible' , null , false , false , true , true , false , null , null ],
[ 'john.doe' , 'offline' , 50 , true , true , true , false , false , null , null ],
[ 'john.doe' , 'offline' , 50 , true , false , true , false , false , null , null ],
[ 'john.doe' , 'offline' , 50 , false , true , true , false , false , null , null ],
[ 'john.doe' , 'offline' , 50 , false , false , true , false , false , null , null ],
[ 'john.doe' , 'offline' , null , true , true , true , true , false , null , null ],
[ 'john.doe' , 'offline' , null , true , false , true , true , false , null , null ],
[ 'john.doe' , 'offline' , null , false , true , true , true , false , null , null ],
[ 'john.doe' , 'offline' , null , false , false , true , true , false , null , null ],
[ 'john.doe' , 'illegal-status' , 50 , true , true , false , false , true , InvalidStatusTypeException :: class , 'Status-type "illegal-status" is not supported' ],
[ 'john.doe' , 'illegal-status' , 50 , true , false , false , false , true , InvalidStatusTypeException :: class , 'Status-type "illegal-status" is not supported' ],
[ 'john.doe' , 'illegal-status' , 50 , false , true , false , false , true , InvalidStatusTypeException :: class , 'Status-type "illegal-status" is not supported' ],
[ 'john.doe' , 'illegal-status' , 50 , false , false , false , false , true , InvalidStatusTypeException :: class , 'Status-type "illegal-status" is not supported' ],
[ 'john.doe' , 'illegal-status' , null , true , true , false , true , true , InvalidStatusTypeException :: class , 'Status-type "illegal-status" is not supported' ],
[ 'john.doe' , 'illegal-status' , null , true , false , false , true , true , InvalidStatusTypeException :: class , 'Status-type "illegal-status" is not supported' ],
[ 'john.doe' , 'illegal-status' , null , false , true , false , true , true , InvalidStatusTypeException :: class , 'Status-type "illegal-status" is not supported' ],
[ 'john.doe' , 'illegal-status' , null , false , false , false , true , true , InvalidStatusTypeException :: class , 'Status-type "illegal-status" is not supported' ],
];
}
2025-06-30 10:56:59 -04:00
#[\PHPUnit\Framework\Attributes\DataProvider('setPredefinedMessageDataProvider')]
2025-05-13 16:23:39 -04:00
public function testSetPredefinedMessage (
string $userId ,
2023-11-23 04:22:34 -05:00
string $messageId ,
bool $isValidMessageId ,
? int $clearAt ,
bool $expectExisting ,
bool $expectSuccess ,
bool $expectException ,
? string $expectedExceptionClass ,
2025-05-13 16:23:39 -04:00
? string $expectedExceptionMessage ,
) : void {
2020-06-02 06:48:37 -04:00
$userStatus = new UserStatus ();
if ( $expectExisting ) {
$userStatus -> setId ( 42 );
$userStatus -> setUserId ( $userId );
$userStatus -> setStatus ( 'offline' );
$userStatus -> setStatusTimestamp ( 0 );
$userStatus -> setIsUserDefined ( false );
$userStatus -> setCustomIcon ( '😀' );
$userStatus -> setCustomMessage ( 'Foo' );
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( $userId )
-> willReturn ( $userStatus );
} else {
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( $userId )
-> willThrowException ( new DoesNotExistException ( '' ));
}
$this -> predefinedStatusService -> expects ( $this -> once ())
-> method ( 'isValidId' )
-> with ( $messageId )
-> willReturn ( $isValidMessageId );
$this -> timeFactory
-> method ( 'getTime' )
-> willReturn ( 40 );
if ( $expectException ) {
$this -> expectException ( $expectedExceptionClass );
$this -> expectExceptionMessage ( $expectedExceptionMessage );
$this -> service -> setPredefinedMessage ( $userId , $messageId , $clearAt );
}
if ( $expectSuccess ) {
if ( $expectExisting ) {
$this -> mapper -> expects ( $this -> once ())
-> method ( 'update' )
-> willReturnArgument ( 0 );
} else {
$this -> mapper -> expects ( $this -> once ())
-> method ( 'insert' )
-> willReturnArgument ( 0 );
}
$actual = $this -> service -> setPredefinedMessage ( $userId , $messageId , $clearAt );
$this -> assertEquals ( 'john.doe' , $actual -> getUserId ());
$this -> assertEquals ( 'offline' , $actual -> getStatus ());
$this -> assertEquals ( 0 , $actual -> getStatusTimestamp ());
$this -> assertEquals ( false , $actual -> getIsUserDefined ());
$this -> assertEquals ( $messageId , $actual -> getMessageId ());
$this -> assertNull ( $actual -> getCustomIcon ());
$this -> assertNull ( $actual -> getCustomMessage ());
$this -> assertEquals ( $clearAt , $actual -> getClearAt ());
}
}
2025-05-13 16:23:39 -04:00
public static function setPredefinedMessageDataProvider () : array {
2020-06-02 06:48:37 -04:00
return [
[ 'john.doe' , 'sick-leave' , true , null , true , true , false , null , null ],
[ 'john.doe' , 'sick-leave' , true , null , false , true , false , null , null ],
[ 'john.doe' , 'sick-leave' , true , 20 , true , false , true , InvalidClearAtException :: class , 'ClearAt is in the past' ],
[ 'john.doe' , 'sick-leave' , true , 20 , false , false , true , InvalidClearAtException :: class , 'ClearAt is in the past' ],
[ 'john.doe' , 'sick-leave' , true , 60 , true , true , false , null , null ],
[ 'john.doe' , 'sick-leave' , true , 60 , false , true , false , null , null ],
[ 'john.doe' , 'illegal-message-id' , false , null , true , false , true , InvalidMessageIdException :: class , 'Message-Id "illegal-message-id" is not supported' ],
[ 'john.doe' , 'illegal-message-id' , false , null , false , false , true , InvalidMessageIdException :: class , 'Message-Id "illegal-message-id" is not supported' ],
];
}
2025-06-30 10:56:59 -04:00
#[\PHPUnit\Framework\Attributes\DataProvider('setCustomMessageDataProvider')]
2025-05-13 16:23:39 -04:00
public function testSetCustomMessage (
string $userId ,
2023-11-23 04:22:34 -05:00
? string $statusIcon ,
bool $supportsEmoji ,
string $message ,
? int $clearAt ,
bool $expectExisting ,
bool $expectSuccess ,
bool $expectException ,
? string $expectedExceptionClass ,
2025-05-13 16:23:39 -04:00
? string $expectedExceptionMessage ,
) : void {
2020-06-02 06:48:37 -04:00
$userStatus = new UserStatus ();
if ( $expectExisting ) {
$userStatus -> setId ( 42 );
$userStatus -> setUserId ( $userId );
$userStatus -> setStatus ( 'offline' );
$userStatus -> setStatusTimestamp ( 0 );
$userStatus -> setIsUserDefined ( false );
$userStatus -> setMessageId ( 'messageId-42' );
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( $userId )
-> willReturn ( $userStatus );
} else {
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( $userId )
-> willThrowException ( new DoesNotExistException ( '' ));
}
2022-03-24 10:57:17 -04:00
$this -> emojiHelper -> method ( 'isValidSingleEmoji' )
2020-06-02 06:48:37 -04:00
-> with ( $statusIcon )
-> willReturn ( $supportsEmoji );
$this -> timeFactory
-> method ( 'getTime' )
-> willReturn ( 40 );
if ( $expectException ) {
$this -> expectException ( $expectedExceptionClass );
$this -> expectExceptionMessage ( $expectedExceptionMessage );
$this -> service -> setCustomMessage ( $userId , $statusIcon , $message , $clearAt );
}
if ( $expectSuccess ) {
if ( $expectExisting ) {
$this -> mapper -> expects ( $this -> once ())
-> method ( 'update' )
-> willReturnArgument ( 0 );
} else {
$this -> mapper -> expects ( $this -> once ())
-> method ( 'insert' )
-> willReturnArgument ( 0 );
}
$actual = $this -> service -> setCustomMessage ( $userId , $statusIcon , $message , $clearAt );
$this -> assertEquals ( 'john.doe' , $actual -> getUserId ());
$this -> assertEquals ( 'offline' , $actual -> getStatus ());
$this -> assertEquals ( 0 , $actual -> getStatusTimestamp ());
$this -> assertEquals ( false , $actual -> getIsUserDefined ());
$this -> assertNull ( $actual -> getMessageId ());
$this -> assertEquals ( $statusIcon , $actual -> getCustomIcon ());
$this -> assertEquals ( $message , $actual -> getCustomMessage ());
$this -> assertEquals ( $clearAt , $actual -> getClearAt ());
}
}
2025-05-13 16:23:39 -04:00
public static function setCustomMessageDataProvider () : array {
2020-06-02 06:48:37 -04:00
return [
[ 'john.doe' , '😁' , true , 'Custom message' , null , true , true , false , null , null ],
[ 'john.doe' , '😁' , true , 'Custom message' , null , false , true , false , null , null ],
[ 'john.doe' , null , false , 'Custom message' , null , true , true , false , null , null ],
[ 'john.doe' , null , false , 'Custom message' , null , false , true , false , null , null ],
[ 'john.doe' , '😁' , false , 'Custom message' , null , true , false , true , InvalidStatusIconException :: class , 'Status-Icon is longer than one character' ],
[ 'john.doe' , '😁' , false , 'Custom message' , null , false , false , true , InvalidStatusIconException :: class , 'Status-Icon is longer than one character' ],
[ 'john.doe' , null , false , 'Custom message that is way too long and violates the maximum length and hence should be rejected' , null , true , false , true , StatusMessageTooLongException :: class , 'Message is longer than supported length of 80 characters' ],
[ 'john.doe' , null , false , 'Custom message that is way too long and violates the maximum length and hence should be rejected' , null , false , false , true , StatusMessageTooLongException :: class , 'Message is longer than supported length of 80 characters' ],
[ 'john.doe' , '😁' , true , 'Custom message' , 80 , true , true , false , null , null ],
[ 'john.doe' , '😁' , true , 'Custom message' , 80 , false , true , false , null , null ],
[ 'john.doe' , '😁' , true , 'Custom message' , 20 , true , false , true , InvalidClearAtException :: class , 'ClearAt is in the past' ],
[ 'john.doe' , '😁' , true , 'Custom message' , 20 , false , false , true , InvalidClearAtException :: class , 'ClearAt is in the past' ],
];
}
public function testClearStatus () : void {
$status = new UserStatus ();
$status -> setId ( 1 );
$status -> setUserId ( 'john.doe' );
$status -> setStatus ( 'dnd' );
$status -> setStatusTimestamp ( 1337 );
$status -> setIsUserDefined ( true );
$status -> setMessageId ( 'messageId-42' );
$status -> setCustomIcon ( '🙊' );
$status -> setCustomMessage ( 'My custom status message' );
$status -> setClearAt ( 42 );
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( 'john.doe' )
-> willReturn ( $status );
$this -> mapper -> expects ( $this -> once ())
-> method ( 'update' )
-> with ( $status );
$actual = $this -> service -> clearStatus ( 'john.doe' );
$this -> assertTrue ( $actual );
$this -> assertEquals ( 'offline' , $status -> getStatus ());
$this -> assertEquals ( 0 , $status -> getStatusTimestamp ());
$this -> assertFalse ( $status -> getIsUserDefined ());
}
public function testClearStatusDoesNotExist () : void {
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( 'john.doe' )
-> willThrowException ( new DoesNotExistException ( '' ));
$this -> mapper -> expects ( $this -> never ())
-> method ( 'update' );
$actual = $this -> service -> clearStatus ( 'john.doe' );
$this -> assertFalse ( $actual );
}
public function testClearMessage () : void {
$status = new UserStatus ();
$status -> setId ( 1 );
$status -> setUserId ( 'john.doe' );
$status -> setStatus ( 'dnd' );
$status -> setStatusTimestamp ( 1337 );
$status -> setIsUserDefined ( true );
$status -> setMessageId ( 'messageId-42' );
$status -> setCustomIcon ( '🙊' );
$status -> setCustomMessage ( 'My custom status message' );
$status -> setClearAt ( 42 );
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( 'john.doe' )
-> willReturn ( $status );
$this -> mapper -> expects ( $this -> once ())
-> method ( 'update' )
-> with ( $status );
$actual = $this -> service -> clearMessage ( 'john.doe' );
$this -> assertTrue ( $actual );
$this -> assertNull ( $status -> getMessageId ());
$this -> assertNull ( $status -> getCustomMessage ());
$this -> assertNull ( $status -> getCustomIcon ());
$this -> assertNull ( $status -> getClearAt ());
}
public function testClearMessageDoesNotExist () : void {
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( 'john.doe' )
-> willThrowException ( new DoesNotExistException ( '' ));
$this -> mapper -> expects ( $this -> never ())
-> method ( 'update' );
$actual = $this -> service -> clearMessage ( 'john.doe' );
$this -> assertFalse ( $actual );
}
public function testRemoveUserStatus () : void {
$status = $this -> createMock ( UserStatus :: class );
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( 'john.doe' )
-> willReturn ( $status );
$this -> mapper -> expects ( $this -> once ())
-> method ( 'delete' )
-> with ( $status );
$actual = $this -> service -> removeUserStatus ( 'john.doe' );
$this -> assertTrue ( $actual );
}
public function testRemoveUserStatusDoesNotExist () : void {
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( 'john.doe' )
-> willThrowException ( new DoesNotExistException ( '' ));
$this -> mapper -> expects ( $this -> never ())
-> method ( 'delete' );
$actual = $this -> service -> removeUserStatus ( 'john.doe' );
$this -> assertFalse ( $actual );
}
2021-06-04 06:03:16 -04:00
public function testCleanStatusAutomaticOnline () : void {
$status = new UserStatus ();
$status -> setStatus ( IUserStatus :: ONLINE );
$status -> setStatusTimestamp ( 1337 );
$status -> setIsUserDefined ( false );
$this -> mapper -> expects ( self :: once ())
-> method ( 'update' )
-> with ( $status );
parent :: invokePrivate ( $this -> service , 'cleanStatus' , [ $status ]);
}
public function testCleanStatusCustomOffline () : void {
$status = new UserStatus ();
$status -> setStatus ( IUserStatus :: OFFLINE );
$status -> setStatusTimestamp ( 1337 );
$status -> setIsUserDefined ( true );
$this -> mapper -> expects ( self :: once ())
-> method ( 'update' )
-> with ( $status );
parent :: invokePrivate ( $this -> service , 'cleanStatus' , [ $status ]);
}
public function testCleanStatusCleanedAlready () : void {
$status = new UserStatus ();
$status -> setStatus ( IUserStatus :: OFFLINE );
$status -> setStatusTimestamp ( 1337 );
$status -> setIsUserDefined ( false );
// Don't update the status again and again when no value changed
$this -> mapper -> expects ( self :: never ())
-> method ( 'update' )
-> with ( $status );
parent :: invokePrivate ( $this -> service , 'cleanStatus' , [ $status ]);
}
2021-08-11 04:36:24 -04:00
2022-02-15 08:55:40 -05:00
public function testBackupWorkingHasBackupAlready () : void {
2025-09-12 11:17:17 -04:00
$e = $this -> createMock ( Exception :: class );
$e -> method ( 'getReason' ) -> willReturn ( Exception :: REASON_UNIQUE_CONSTRAINT_VIOLATION );
2021-08-11 04:36:24 -04:00
$this -> mapper -> expects ( $this -> once ())
2022-02-15 08:55:40 -05:00
-> method ( 'createBackupStatus' )
-> with ( 'john' )
-> willThrowException ( $e );
2021-08-11 04:36:24 -04:00
2022-02-15 08:55:40 -05:00
$this -> assertFalse ( $this -> service -> backupCurrentStatus ( 'john' ));
2021-08-11 04:36:24 -04:00
}
2022-02-15 08:55:40 -05:00
public function testBackupThrowsOther () : void {
$e = new Exception ( '' , Exception :: REASON_CONNECTION_LOST );
$this -> mapper -> expects ( $this -> once ())
-> method ( 'createBackupStatus' )
-> with ( 'john' )
-> willThrowException ( $e );
2021-08-11 04:36:24 -04:00
2022-02-15 08:55:40 -05:00
$this -> expectException ( Exception :: class );
$this -> service -> backupCurrentStatus ( 'john' );
}
2021-08-11 04:36:24 -04:00
2022-02-15 08:55:40 -05:00
public function testBackup () : void {
2021-08-11 04:36:24 -04:00
$this -> mapper -> expects ( $this -> once ())
2022-02-15 08:55:40 -05:00
-> method ( 'createBackupStatus' )
-> with ( 'john' )
-> willReturn ( true );
2021-08-11 04:36:24 -04:00
2022-02-15 08:55:40 -05:00
$this -> assertTrue ( $this -> service -> backupCurrentStatus ( 'john' ));
2021-08-11 04:36:24 -04:00
}
2022-02-10 11:28:05 -05:00
public function testRevertMultipleUserStatus () : void {
$john = new UserStatus ();
$john -> setId ( 1 );
$john -> setStatus ( IUserStatus :: AWAY );
$john -> setStatusTimestamp ( 1337 );
$john -> setIsUserDefined ( false );
$john -> setMessageId ( 'call' );
$john -> setUserId ( 'john' );
$john -> setIsBackup ( false );
$johnBackup = new UserStatus ();
$johnBackup -> setId ( 2 );
$johnBackup -> setStatus ( IUserStatus :: ONLINE );
$johnBackup -> setStatusTimestamp ( 1337 );
$johnBackup -> setIsUserDefined ( true );
$johnBackup -> setMessageId ( 'hello' );
$johnBackup -> setUserId ( '_john' );
$johnBackup -> setIsBackup ( true );
$noBackup = new UserStatus ();
$noBackup -> setId ( 3 );
$noBackup -> setStatus ( IUserStatus :: AWAY );
$noBackup -> setStatusTimestamp ( 1337 );
$noBackup -> setIsUserDefined ( false );
$noBackup -> setMessageId ( 'call' );
$noBackup -> setUserId ( 'nobackup' );
$noBackup -> setIsBackup ( false );
$backupOnly = new UserStatus ();
$backupOnly -> setId ( 4 );
$backupOnly -> setStatus ( IUserStatus :: ONLINE );
$backupOnly -> setStatusTimestamp ( 1337 );
$backupOnly -> setIsUserDefined ( true );
$backupOnly -> setMessageId ( 'hello' );
$backupOnly -> setUserId ( '_backuponly' );
$backupOnly -> setIsBackup ( true );
2022-07-22 05:02:37 -04:00
$noBackupDND = new UserStatus ();
$noBackupDND -> setId ( 5 );
$noBackupDND -> setStatus ( IUserStatus :: DND );
$noBackupDND -> setStatusTimestamp ( 1337 );
$noBackupDND -> setIsUserDefined ( false );
$noBackupDND -> setMessageId ( 'call' );
$noBackupDND -> setUserId ( 'nobackupanddnd' );
$noBackupDND -> setIsBackup ( false );
2022-02-10 11:28:05 -05:00
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserIds' )
2022-07-22 05:02:37 -04:00
-> with ([ 'john' , 'nobackup' , 'backuponly' , 'nobackupanddnd' , '_john' , '_nobackup' , '_backuponly' , '_nobackupanddnd' ])
2022-02-10 11:28:05 -05:00
-> willReturn ([
$john ,
$johnBackup ,
$noBackup ,
$backupOnly ,
2022-07-22 05:02:37 -04:00
$noBackupDND ,
2022-02-10 11:28:05 -05:00
]);
$this -> mapper -> expects ( $this -> once ())
-> method ( 'deleteByIds' )
2022-07-22 05:02:37 -04:00
-> with ([ 1 , 3 , 5 ]);
2022-02-10 11:28:05 -05:00
$this -> mapper -> expects ( $this -> once ())
-> method ( 'restoreBackupStatuses' )
-> with ([ 2 ]);
2022-07-22 05:02:37 -04:00
$this -> service -> revertMultipleUserStatus ([ 'john' , 'nobackup' , 'backuponly' , 'nobackupanddnd' ], 'call' );
2022-02-10 11:28:05 -05:00
}
2024-06-24 10:28:43 -04:00
2025-05-13 16:23:39 -04:00
public static function dataSetUserStatus () : array {
2024-06-24 10:28:43 -04:00
return [
[ IUserStatus :: MESSAGE_CALENDAR_BUSY , '' , false ],
// Call > Meeting
[ IUserStatus :: MESSAGE_CALENDAR_BUSY , IUserStatus :: MESSAGE_CALL , false ],
[ IUserStatus :: MESSAGE_CALL , IUserStatus :: MESSAGE_CALENDAR_BUSY , true ],
// Availability > Call&Meeting
[ IUserStatus :: MESSAGE_CALENDAR_BUSY , IUserStatus :: MESSAGE_AVAILABILITY , false ],
[ IUserStatus :: MESSAGE_CALL , IUserStatus :: MESSAGE_AVAILABILITY , false ],
[ IUserStatus :: MESSAGE_AVAILABILITY , IUserStatus :: MESSAGE_CALENDAR_BUSY , true ],
[ IUserStatus :: MESSAGE_AVAILABILITY , IUserStatus :: MESSAGE_CALL , true ],
// Out-of-office > Availability&Call&Meeting
[ IUserStatus :: MESSAGE_AVAILABILITY , IUserStatus :: MESSAGE_OUT_OF_OFFICE , false ],
[ IUserStatus :: MESSAGE_CALENDAR_BUSY , IUserStatus :: MESSAGE_OUT_OF_OFFICE , false ],
[ IUserStatus :: MESSAGE_CALL , IUserStatus :: MESSAGE_OUT_OF_OFFICE , false ],
[ IUserStatus :: MESSAGE_OUT_OF_OFFICE , IUserStatus :: MESSAGE_AVAILABILITY , true ],
[ IUserStatus :: MESSAGE_OUT_OF_OFFICE , IUserStatus :: MESSAGE_CALENDAR_BUSY , true ],
[ IUserStatus :: MESSAGE_OUT_OF_OFFICE , IUserStatus :: MESSAGE_CALL , true ],
];
}
2025-06-30 10:56:59 -04:00
#[\PHPUnit\Framework\Attributes\DataProvider('dataSetUserStatus')]
2024-06-24 10:28:43 -04:00
public function testSetUserStatus ( string $messageId , string $oldMessageId , bool $expectedUpdateShortcut ) : void {
$previous = new UserStatus ();
$previous -> setId ( 1 );
$previous -> setStatus ( IUserStatus :: AWAY );
$previous -> setStatusTimestamp ( 1337 );
$previous -> setIsUserDefined ( false );
$previous -> setMessageId ( $oldMessageId );
$previous -> setUserId ( 'john' );
$previous -> setIsBackup ( false );
$this -> mapper -> expects ( $this -> once ())
-> method ( 'findByUserId' )
-> with ( 'john' )
-> willReturn ( $previous );
2025-09-12 11:17:17 -04:00
/** @var MockObject&Exception $exception */
$exception = $this -> createMock ( Exception :: class );
$exception -> method ( 'getReason' ) -> willReturn ( Exception :: REASON_UNIQUE_CONSTRAINT_VIOLATION );
2024-06-24 10:28:43 -04:00
$this -> mapper -> expects ( $expectedUpdateShortcut ? $this -> never () : $this -> once ())
-> method ( 'createBackupStatus' )
2025-09-12 11:17:17 -04:00
-> willThrowException ( $exception );
2024-06-24 10:28:43 -04:00
$this -> mapper -> expects ( $this -> any ())
-> method ( 'update' )
-> willReturnArgument ( 0 );
$this -> predefinedStatusService -> expects ( $this -> once ())
-> method ( 'isValidId' )
-> with ( $messageId )
-> willReturn ( true );
$this -> service -> setUserStatus ( 'john' , IUserStatus :: DND , $messageId , true );
}
2020-06-02 06:48:37 -04:00
}