Compare commits

..

2 Commits

Author SHA1 Message Date
Alex 3810f340e9 Added getAdmins & deleteAdmins & getMembers & removeMember 2025-07-30 08:51:31 +03:00
Alex 46e7c2ef0a Added pinMessage & getMessages & deleteMessage & getMessageById 2025-07-29 19:09:33 +03:00
7 changed files with 812 additions and 10 deletions
+9 -9
View File
@@ -37,16 +37,16 @@
- [x] `DELETE /chats/{chatId}` (`deleteChat`) — *Удаление чата.*
- [x] `POST /chats/{chatId}/actions` (`sendAction`) — *Отправка действия в чат (например, "печатает...").*
- [x] `GET /chats/{chatId}/pin` (`getPinnedMessage`) — *Получение закрепленного сообщения.*
- [ ] `PUT /chats/{chatId}/pin` (`pinMessage`) — *Закрепление сообщения.*
- [x] `PUT /chats/{chatId}/pin` (`pinMessage`) — *Закрепление сообщения.*
- [x] `DELETE /chats/{chatId}/pin` (`unpinMessage`) — *Открепление сообщения.*
- [x] `GET /chats/{chatId}/members/me` (`getMembership`) — *Получение информации о членстве бота в чате.*
- [x] `DELETE /chats/{chatId}/members/me` (`leaveChat`) — *Выход бота из чата.*
- [ ] `GET /chats/{chatId}/members/admins` (`getAdmins`) — *Получение администраторов чата.*
- [x] `GET /chats/{chatId}/members/admins` (`getAdmins`) — *Получение администраторов чата.*
- [ ] `POST /chats/{chatId}/members/admins` (`postAdmins`) — *Назначение администраторов чата.*
- [ ] `DELETE /chats/{chatId}/members/admins/{userId}` (`deleteAdmins`) — *Снятие прав администратора.*
- [ ] `GET /chats/{chatId}/members` (`getMembers`) — *Получение участников чата.*
- [x] `DELETE /chats/{chatId}/members/admins/{userId}` (`deleteAdmins`) — *Снятие прав администратора.*
- [x] `GET /chats/{chatId}/members` (`getMembers`) — *Получение участников чата.*
- [ ] `POST /chats/{chatId}/members` (`addMembers`) — *Добавление участников в чат.*
- [ ] `DELETE /chats/{chatId}/members` (`removeMember`) — *Удаление участника из чата.*
- [x] `DELETE /chats/{chatId}/members` (`removeMember`) — *Удаление участника из чата.*
#### Subscriptions
@@ -61,14 +61,14 @@
#### Messages
- [ ] `GET /messages` (`getMessages`) — *Получение списка сообщений из чата.*
- [x] `GET /messages` (`getMessages`) — *Получение списка сообщений из чата.*
- [x] `POST /messages` (`sendMessage`) — *Отправка сообщения.*
- [ ] `PUT /messages` (`editMessage`) — *Редактирование сообщения.*
- [ ] `DELETE /messages` (`deleteMessage`) — *Удаление сообщения.*
- [ ] `GET /messages/{messageId}` (`getMessageById`) — *Получение сообщения по ID.*
- [x] `DELETE /messages` (`deleteMessage`) — *Удаление сообщения.*
- [x] `GET /messages/{messageId}` (`getMessageById`) — *Получение сообщения по ID.*
- [ ] `GET /videos/{videoToken}` (`getVideoAttachmentDetails`) — *Получение детальной информации о видео.*
- [ ] `POST /answers` (`answerOnCallback`) — *Ответ на нажатие callback-кнопки.*
## Лицензия
Данная библиотека распространяется по лицензии MIT - подробности см. в файле [LICENSE](LICENSE).
Данная библиотека распространяется под лицензией MIT - подробности см. в файле [LICENSE](LICENSE).
+223 -1
View File
@@ -22,6 +22,7 @@ use BushlanovDev\MaxMessengerBot\Models\BotInfo;
use BushlanovDev\MaxMessengerBot\Models\Chat;
use BushlanovDev\MaxMessengerBot\Models\ChatList;
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
use BushlanovDev\MaxMessengerBot\Models\ChatMembersList;
use BushlanovDev\MaxMessengerBot\Models\Message;
use BushlanovDev\MaxMessengerBot\Models\MessageLink;
use BushlanovDev\MaxMessengerBot\Models\Result;
@@ -50,6 +51,7 @@ class Api
private const string METHOD_POST = 'POST';
private const string METHOD_DELETE = 'DELETE';
// private const string METHOD_PATCH = 'PATCH';
private const string METHOD_PUT = 'PUT';
private const string ACTION_ME = '/me';
private const string ACTION_SUBSCRIPTIONS = '/subscriptions';
@@ -59,6 +61,9 @@ class Api
private const string ACTION_CHATS_ACTIONS = '/chats/%d/actions';
private const string ACTION_CHATS_PIN = '/chats/%d/pin';
private const string ACTION_CHATS_MEMBERS_ME = '/chats/%d/members/me';
private const string ACTION_CHATS_MEMBERS_ADMINS = '/chats/%d/members/admins';
private const string ACTION_CHATS_MEMBERS_ADMINS_ID = '/chats/%d/members/admins/%d';
private const string ACTION_CHATS_MEMBERS = '/chats/%d/members';
private const string ACTION_UPDATES = '/updates';
private readonly ClientApiInterface $client;
@@ -653,7 +658,7 @@ class Api
*
* @param int $chatId Chat identifier to leave from.
*
* @return Result A simple success/fail result.
* @return Result
* @throws ClientApiException
* @throws NetworkException
* @throws ReflectionException
@@ -668,4 +673,221 @@ class Api
)
);
}
/**
* Returns messages in a chat. Messages are traversed in reverse chronological order.
*
* @param int $chatId Identifier of the chat to get messages from.
* @param string[]|null $messageIds A comma-separated list of message IDs to retrieve.
* @param int|null $from Start time (Unix timestamp in ms) for the requested messages.
* @param int|null $to End time (Unix timestamp in ms) for the requested messages.
* @param int|null $count Maximum amount of messages in the response (1-100, default 50).
*
* @return Message[]
* @throws ClientApiException
* @throws NetworkException
* @throws ReflectionException
* @throws SerializationException
*/
public function getMessages(
int $chatId,
?array $messageIds = null,
?int $from = null,
?int $to = null,
?int $count = null,
): array {
$query = [
'chat_id' => $chatId,
'message_ids' => $messageIds !== null ? implode(',', $messageIds) : null,
'from' => $from,
'to' => $to,
'count' => $count,
];
$response = $this->client->request(
self::METHOD_GET,
self::ACTION_MESSAGES,
array_filter($query, fn($value) => $value !== null),
);
return $this->modelFactory->createMessages($response);
}
/**
* Deletes a message in a dialog or in a chat if the bot has permission to delete messages.
*
* @param string $messageId Identifier of the message to be deleted.
*
* @return Result
* @throws ClientApiException
* @throws NetworkException
* @throws ReflectionException
* @throws SerializationException
*/
public function deleteMessage(string $messageId): Result
{
return $this->modelFactory->createResult(
$this->client->request(
self::METHOD_DELETE,
self::ACTION_MESSAGES,
['message_id' => $messageId],
)
);
}
/**
* Returns a single message by its identifier.
*
* @param string $messageId Message identifier (`mid`) to get.
*
* @return Message
* @throws ClientApiException
* @throws NetworkException
* @throws ReflectionException
* @throws SerializationException
*/
public function getMessageById(string $messageId): Message
{
return $this->modelFactory->createMessage(
$this->client->request(
self::METHOD_GET,
self::ACTION_MESSAGES . '/' . $messageId,
)
);
}
/**
* Pins a message in a chat or channel.
*
* @param int $chatId Chat identifier where the message should be pinned.
* @param string $messageId Identifier of the message to pin.
* @param bool $notify If true, participants will be notified with a system message.
*
* @return Result
* @throws ClientApiException
* @throws NetworkException
* @throws ReflectionException
* @throws SerializationException
*/
public function pinMessage(int $chatId, string $messageId, bool $notify = true): Result
{
return $this->modelFactory->createResult(
$this->client->request(
self::METHOD_PUT,
sprintf(self::ACTION_CHATS_PIN, $chatId),
[],
[
'message_id' => $messageId,
'notify' => $notify,
]
)
);
}
/**
* Returns all chat administrators. The bot must be an administrator in the requested chat.
*
* @param int $chatId Chat identifier.
*
* @return ChatMembersList
* @throws ClientApiException
* @throws NetworkException
* @throws ReflectionException
* @throws SerializationException
*/
public function getAdmins(int $chatId): ChatMembersList
{
return $this->modelFactory->createChatMembersList(
$this->client->request(
self::METHOD_GET,
sprintf(self::ACTION_CHATS_MEMBERS_ADMINS, $chatId),
)
);
}
/**
* Returns a paginated list of users who are participating in a chat.
*
* @param int $chatId The identifier of the chat.
* @param int[]|null $userIds A list of user identifiers to get their specific membership.
* When this parameter is passed, `count` and `marker` are ignored.
* @param int|null $marker The pagination marker to get the next page of members.
* @param int|null $count The number of members to return (1-100, default is 20).
*
* @return ChatMembersList
* @throws ClientApiException
* @throws NetworkException
* @throws ReflectionException
* @throws SerializationException
*/
public function getMembers(
int $chatId,
?array $userIds = null,
?int $marker = null,
?int $count = null
): ChatMembersList {
$query = [
'user_ids' => $userIds !== null ? implode(',', $userIds) : null,
'marker' => $marker,
'count' => $count,
];
return $this->modelFactory->createChatMembersList(
$this->client->request(
self::METHOD_GET,
sprintf(self::ACTION_CHATS_MEMBERS, $chatId),
array_filter($query, fn($value) => $value !== null),
)
);
}
/**
* Revokes admin rights from a user in the chat.
*
* @param int $chatId The identifier of the chat.
* @param int $userId The identifier of the user to revoke admin rights from.
*
* @return Result
* @throws ClientApiException
* @throws NetworkException
* @throws ReflectionException
* @throws SerializationException
*/
public function deleteAdmins(int $chatId, int $userId): Result
{
return $this->modelFactory->createResult(
$this->client->request(
self::METHOD_DELETE,
sprintf(self::ACTION_CHATS_MEMBERS_ADMINS_ID, $chatId, $userId),
)
);
}
/**
* Removes a member from a chat. The bot may require additional permissions.
*
* @param int $chatId The identifier of the chat.
* @param int $userId The identifier of the user to remove.
* @param bool $block Set to true if the user should also be blocked in the chat.
* Applicable only for chats with a public or private link.
*
* @return Result
* @throws ClientApiException
* @throws NetworkException
* @throws ReflectionException
* @throws SerializationException
*/
public function removeMember(int $chatId, int $userId, bool $block = false): Result
{
return $this->modelFactory->createResult(
$this->client->request(
self::METHOD_DELETE,
sprintf(self::ACTION_CHATS_MEMBERS, $chatId),
[
'user_id' => $userId,
'block' => $block,
],
)
);
}
}
+28
View File
@@ -9,6 +9,7 @@ use BushlanovDev\MaxMessengerBot\Models\BotInfo;
use BushlanovDev\MaxMessengerBot\Models\Chat;
use BushlanovDev\MaxMessengerBot\Models\ChatList;
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
use BushlanovDev\MaxMessengerBot\Models\ChatMembersList;
use BushlanovDev\MaxMessengerBot\Models\Message;
use BushlanovDev\MaxMessengerBot\Models\Result;
use BushlanovDev\MaxMessengerBot\Models\Subscription;
@@ -101,6 +102,20 @@ class ModelFactory
return Message::fromArray($data);
}
/**
* List of messages.
*
* @param array<string, mixed> $data
*
* @return Message[]
*/
public function createMessages(array $data): array
{
return isset($data['messages']) && is_array($data['messages'])
? array_map([$this, 'createMessage'], $data['messages'])
: [];
}
/**
* Endpoint you should upload to your binaries.
*
@@ -206,4 +221,17 @@ class ModelFactory
{
return ChatMember::fromArray($data);
}
/**
* Creates a ChatMembersList object from raw API data.
*
* @param array<string, mixed> $data
*
* @return ChatMembersList
* @throws ReflectionException
*/
public function createChatMembersList(array $data): ChatMembersList
{
return ChatMembersList::fromArray($data);
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace BushlanovDev\MaxMessengerBot\Models;
use BushlanovDev\MaxMessengerBot\Attributes\ArrayOf;
/**
* Represents a paginated list of chat members.
*/
final readonly class ChatMembersList extends AbstractModel
{
/**
* @param ChatMember[] $members A list of chat members.
* @param int|null $marker A pointer to the next page of data. Null if this is the last page.
*/
public function __construct(
#[ArrayOf(ChatMember::class)]
public array $members,
public ?int $marker,
) {
}
}
+376
View File
@@ -38,6 +38,7 @@ use BushlanovDev\MaxMessengerBot\Models\BotInfo;
use BushlanovDev\MaxMessengerBot\Models\Chat;
use BushlanovDev\MaxMessengerBot\Models\ChatList;
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
use BushlanovDev\MaxMessengerBot\Models\ChatMembersList;
use BushlanovDev\MaxMessengerBot\Models\Message;
use BushlanovDev\MaxMessengerBot\Models\MessageBody;
use BushlanovDev\MaxMessengerBot\Models\Recipient;
@@ -105,6 +106,7 @@ use RuntimeException;
#[UsesClass(ChatList::class)]
#[UsesClass(ChatMember::class)]
#[UsesClass(ArrayOf::class)]
#[UsesClass(ChatMembersList::class)]
final class ApiTest extends TestCase
{
use PHPMock;
@@ -1500,4 +1502,378 @@ final class ApiTest extends TestCase
$this->assertSame($expectedResult, $result);
}
#[Test]
public function getMessagesCallsClientWithAllParameters(): void
{
$chatId = 12345;
$messageIds = ['mid.1', 'mid.2'];
$from = 1678880000;
$to = 1678886400;
$count = 10;
$expectedQuery = [
'chat_id' => $chatId,
'message_ids' => 'mid.1,mid.2',
'from' => $from,
'to' => $to,
'count' => $count,
];
$messageData = [
'timestamp' => 1,
'body' => ['mid' => 'mid.1', 'seq' => 1],
'recipient' => ['chat_type' => 'chat', 'chat_id' => $chatId],
];
$rawResponse = ['messages' => [$messageData]];
$expectedMessages = [Message::fromArray($messageData)];
$this->clientMock->expects($this->once())
->method('request')
->with('GET', '/messages', $expectedQuery)
->willReturn($rawResponse);
$this->modelFactoryMock->expects($this->once())
->method('createMessages')
->with($rawResponse)
->willReturn($expectedMessages);
$result = $this->api->getMessages($chatId, $messageIds, $from, $to, $count);
$this->assertIsArray($result);
$this->assertSame($expectedMessages, $result);
}
#[Test]
public function getMessagesReturnsEmptyArrayForEmptyResponse(): void
{
$chatId = 54321;
$rawResponse = ['messages' => []];
$this->clientMock->expects($this->once())
->method('request')
->with('GET', '/messages', ['chat_id' => $chatId])
->willReturn($rawResponse);
$this->modelFactoryMock->expects($this->once())
->method('createMessages')
->with($rawResponse)
->willReturn([]);
$result = $this->api->getMessages($chatId);
$this->assertIsArray($result);
$this->assertEmpty($result);
}
#[Test]
public function deleteMessageCallsClientCorrectly(): void
{
$messageId = 'mid.12345.abcdef';
$expectedQuery = ['message_id' => $messageId];
$rawResponse = ['success' => true];
$expectedResult = new Result(true, null);
$this->clientMock
->expects($this->once())
->method('request')
->with(
self::equalTo('DELETE'),
self::equalTo('/messages'),
self::equalTo($expectedQuery),
)
->willReturn($rawResponse);
$this->modelFactoryMock
->expects($this->once())
->method('createResult')
->with($rawResponse)
->willReturn($expectedResult);
$result = $this->api->deleteMessage($messageId);
$this->assertSame($expectedResult, $result);
}
#[Test]
public function getMessageByIdCallsClientAndFactoryCorrectly(): void
{
$messageId = 'mid.abcdef.123456';
$uri = sprintf('/messages/%s', $messageId);
$rawResponse = [
'timestamp' => 1679000000,
'body' => ['mid' => $messageId, 'seq' => 123, 'text' => 'This is a specific message.'],
'recipient' => ['chat_type' => 'dialog', 'user_id' => 101],
];
$expectedMessage = Message::fromArray($rawResponse);
$this->clientMock
->expects($this->once())
->method('request')
->with(self::equalTo('GET'), self::equalTo($uri))
->willReturn($rawResponse);
$this->modelFactoryMock
->expects($this->once())
->method('createMessage')
->with($rawResponse)
->willReturn($expectedMessage);
$result = $this->api->getMessageById($messageId);
$this->assertSame($expectedMessage, $result);
}
#[Test]
public function pinMessageCallsClientWithCorrectBody(): void
{
$chatId = 12345;
$messageId = 'mid.to.pin';
$notify = false;
$uri = sprintf('/chats/%d/pin', $chatId);
$expectedBody = ['message_id' => $messageId, 'notify' => $notify];
$rawResponse = ['success' => true];
$expectedResult = new Result(true, null);
$this->clientMock
->expects($this->once())
->method('request')
->with(
self::equalTo('PUT'),
self::equalTo($uri),
self::equalTo([]),
self::equalTo($expectedBody),
)
->willReturn($rawResponse);
$this->modelFactoryMock
->expects($this->once())
->method('createResult')
->with($rawResponse)
->willReturn($expectedResult);
$result = $this->api->pinMessage($chatId, $messageId, $notify);
$this->assertSame($expectedResult, $result);
}
#[Test]
public function pinMessageUsesDefaultNotificationValue(): void
{
$chatId = 54321;
$messageId = 'mid.another.pin';
$uri = sprintf('/chats/%d/pin', $chatId);
$expectedBody = ['message_id' => $messageId, 'notify' => true];
$rawResponse = ['success' => true];
$expectedResult = new Result(true, null);
$this->clientMock
->expects($this->once())
->method('request')
->with('PUT', $uri, [], $expectedBody)
->willReturn($rawResponse);
$this->modelFactoryMock
->method('createResult')
->willReturn($expectedResult);
$this->api->pinMessage($chatId, $messageId);
}
#[Test]
public function getAdminsReturnsChatMembersList(): void
{
$chatId = 98765;
$uri = sprintf('/chats/%d/members/admins', $chatId);
$rawResponse = [
'members' => [
[
'user_id' => 1,
'first_name' => 'AdminBot',
'is_bot' => true,
'last_activity_time' => 1,
'last_access_time' => 2,
'is_owner' => false,
'is_admin' => true,
'join_time' => 0
]
],
'marker' => null
];
$expectedList = ChatMembersList::fromArray($rawResponse);
$this->clientMock
->expects($this->once())
->method('request')
->with('GET', $uri)
->willReturn($rawResponse);
$this->modelFactoryMock
->expects($this->once())
->method('createChatMembersList')
->with($rawResponse)
->willReturn($expectedList);
$result = $this->api->getAdmins($chatId);
$this->assertSame($expectedList, $result);
$this->assertCount(1, $result->members);
$this->assertTrue($result->members[0]->isAdmin);
}
#[Test]
public function getMembersWithPaginationCallsClientCorrectly(): void
{
$chatId = 12345;
$count = 50;
$marker = 98765;
$uri = sprintf('/chats/%d/members', $chatId);
$expectedQuery = ['count' => $count, 'marker' => $marker];
$rawResponse = ['members' => [], 'marker' => 123];
$expectedList = new ChatMembersList([], 123);
$this->clientMock
->expects($this->once())
->method('request')
->with('GET', $uri, $expectedQuery)
->willReturn($rawResponse);
$this->modelFactoryMock
->expects($this->once())
->method('createChatMembersList')
->with($rawResponse)
->willReturn($expectedList);
$result = $this->api->getMembers($chatId, null, $marker, $count);
$this->assertSame($expectedList, $result);
}
#[Test]
public function getMembersWithUserIdsCallsClientCorrectly(): void
{
$chatId = 54321;
$userIds = [101, 202, 303];
$uri = sprintf('/chats/%d/members', $chatId);
$expectedQuery = ['user_ids' => '101,202,303'];
$rawResponse = [
'members' => [
[
'user_id' => 101,
'first_name' => 'User1',
'is_bot' => false,
'last_activity_time' => 1,
'last_access_time' => 2,
'is_owner' => false,
'is_admin' => false,
'join_time' => 0,
]
],
'marker' => null,
];
$expectedList = ChatMembersList::fromArray($rawResponse);
$this->clientMock
->expects($this->once())
->method('request')
->with('GET', $uri, $expectedQuery)
->willReturn($rawResponse);
$this->modelFactoryMock
->expects($this->once())
->method('createChatMembersList')
->with($rawResponse)
->willReturn($expectedList);
$result = $this->api->getMembers($chatId, $userIds);
$this->assertSame($expectedList, $result);
}
#[Test]
public function deleteAdminsCallsClientCorrectly(): void
{
$chatId = 12345;
$userId = 987;
$uri = sprintf('/chats/%d/members/admins/%d', $chatId, $userId);
$rawResponse = ['success' => true];
$expectedResult = new Result(true, null);
$this->clientMock
->expects($this->once())
->method('request')
->with(self::equalTo('DELETE'), self::equalTo($uri))
->willReturn($rawResponse);
$this->modelFactoryMock
->expects($this->once())
->method('createResult')
->with($rawResponse)
->willReturn($expectedResult);
$result = $this->api->deleteAdmins($chatId, $userId);
$this->assertSame($expectedResult, $result);
}
#[Test]
public function removeMemberCallsClientWithDefaultBlockValue(): void
{
$chatId = 12345;
$userId = 678;
$uri = sprintf('/chats/%d/members', $chatId);
$expectedQuery = ['user_id' => $userId];
$rawResponse = ['success' => true];
$expectedResult = new Result(true, null);
$this->clientMock
->expects($this->once())
->method('request')
->with('DELETE', $uri, $expectedQuery)
->willReturn($rawResponse);
$this->modelFactoryMock
->expects($this->once())
->method('createResult')
->with($rawResponse)
->willReturn($expectedResult);
$result = $this->api->removeMember($chatId, $userId);
$this->assertSame($expectedResult, $result);
}
#[Test]
public function removeMemberCallsClientWithBlockTrue(): void
{
$chatId = 54321;
$userId = 910;
$uri = sprintf('/chats/%d/members', $chatId);
$expectedQuery = ['user_id' => $userId, 'block' => true];
$rawResponse = ['success' => true];
$expectedResult = new Result(true, null);
$this->clientMock
->expects($this->once())
->method('request')
->with('DELETE', $uri, $expectedQuery)
->willReturn($rawResponse);
$this->modelFactoryMock
->expects($this->once())
->method('createResult')
->with($rawResponse)
->willReturn($expectedResult);
$result = $this->api->removeMember($chatId, $userId, true);
$this->assertSame($expectedResult, $result);
}
}
+94
View File
@@ -13,6 +13,7 @@ use BushlanovDev\MaxMessengerBot\Models\BotInfo;
use BushlanovDev\MaxMessengerBot\Models\Chat;
use BushlanovDev\MaxMessengerBot\Models\ChatList;
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
use BushlanovDev\MaxMessengerBot\Models\ChatMembersList;
use BushlanovDev\MaxMessengerBot\Models\Image;
use BushlanovDev\MaxMessengerBot\Models\Message;
use BushlanovDev\MaxMessengerBot\Models\MessageBody;
@@ -53,6 +54,7 @@ use PHPUnit\Framework\TestCase;
#[UsesClass(MessageChatCreatedUpdate::class)]
#[UsesClass(ChatList::class)]
#[UsesClass(ChatMember::class)]
#[UsesClass(ChatMembersList::class)]
final class ModelFactoryTest extends TestCase
{
private ModelFactory $factory;
@@ -386,4 +388,96 @@ final class ModelFactoryTest extends TestCase
$this->assertSame(ChatAdminPermission::Write, $chatMember->permissions[1]);
$this->assertEquals($rawData, $chatMember->toArray());
}
#[Test]
public function createMessagesReturnsArrayOfMessageObjects(): void
{
$data = [
'messages' => [
[
'timestamp' => 1,
'body' => ['mid' => 'mid.1', 'seq' => 1],
'recipient' => ['chat_type' => 'chat', 'chat_id' => 123],
],
[
'timestamp' => 2,
'body' => ['mid' => 'mid.2', 'seq' => 2],
'recipient' => ['chat_type' => 'chat', 'chat_id' => 123],
],
],
];
$messages = $this->factory->createMessages($data);
$this->assertIsArray($messages);
$this->assertCount(2, $messages);
$this->assertInstanceOf(Message::class, $messages[0]);
$this->assertSame('mid.1', $messages[0]->body->mid);
}
#[Test]
public function createMessagesHandlesEmptyOrMissingKey(): void
{
$this->assertEmpty($this->factory->createMessages(['messages' => []]));
$this->assertEmpty($this->factory->createMessages([]));
}
#[Test]
public function createChatMembersListSuccessfully(): void
{
$rawData = [
'members' => [
[
'user_id' => 101,
'first_name' => 'Admin1',
'is_bot' => false,
'last_activity_time' => 1,
'last_access_time' => 2,
'is_owner' => true,
'is_admin' => true,
'join_time' => 0,
],
[
'user_id' => 102,
'first_name' => 'Admin2',
'is_bot' => true,
'last_activity_time' => 3,
'last_access_time' => 4,
'is_owner' => false,
'is_admin' => true,
'join_time' => 5,
],
],
'marker' => 98765,
];
$list = $this->factory->createChatMembersList($rawData);
$this->assertInstanceOf(ChatMembersList::class, $list);
$this->assertCount(2, $list->members);
$this->assertSame(98765, $list->marker);
$this->assertInstanceOf(ChatMember::class, $list->members[0]);
$this->assertSame(101, $list->members[0]->userId);
$this->assertTrue($list->members[0]->isOwner);
$this->assertInstanceOf(ChatMember::class, $list->members[1]);
$this->assertSame(102, $list->members[1]->userId);
$this->assertTrue($list->members[1]->isBot);
}
#[Test]
public function createChatMembersListHandlesEmptyResponse(): void
{
$rawData = [
'members' => [],
'marker' => null,
];
$list = $this->factory->createChatMembersList($rawData);
$this->assertInstanceOf(ChatMembersList::class, $list);
$this->assertEmpty($list->members);
$this->assertNull($list->marker);
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace BushlanovDev\MaxMessengerBot\Tests\Models;
use BushlanovDev\MaxMessengerBot\Attributes\ArrayOf;
use BushlanovDev\MaxMessengerBot\Models\ChatMember;
use BushlanovDev\MaxMessengerBot\Models\ChatMembersList;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\UsesClass;
use PHPUnit\Framework\TestCase;
#[CoversClass(ChatMembersList::class)]
#[UsesClass(ChatMember::class)]
#[UsesClass(ArrayOf::class)]
final class ChatMembersListTest extends TestCase
{
#[Test]
public function canBeCreatedWithData(): void
{
$data = [
'members' => [
[
'user_id' => 101,
'first_name' => 'Admin1',
'is_bot' => false,
'last_activity_time' => 1,
'last_access_time' => 2,
'is_owner' => true,
'is_admin' => true,
'join_time' => 0,
],
],
'marker' => 12345,
];
$list = ChatMembersList::fromArray($data);
$this->assertInstanceOf(ChatMembersList::class, $list);
$this->assertCount(1, $list->members);
$this->assertInstanceOf(ChatMember::class, $list->members[0]);
$this->assertSame(101, $list->members[0]->userId);
$this->assertSame(12345, $list->marker);
}
#[Test]
public function canBeCreatedWithEmptyMembersAndNullMarker(): void
{
$data = ['members' => [], 'marker' => null];
$list = ChatMembersList::fromArray($data);
$this->assertIsArray($list->members);
$this->assertEmpty($list->members);
$this->assertNull($list->marker);
}
}