diff --git a/composer.json b/composer.json index 393b71ad6..cf2966ad2 100644 --- a/composer.json +++ b/composer.json @@ -112,7 +112,8 @@ "@docs", "@docs-fix", "@cs-fix", - "@psalm" + "@psalm", + "@test-light" ], "test": [ "@paratest" diff --git a/src/TL/Conversion/BotAPI.php b/src/TL/Conversion/BotAPI.php index e57e48494..7da1588f6 100644 --- a/src/TL/Conversion/BotAPI.php +++ b/src/TL/Conversion/BotAPI.php @@ -223,71 +223,6 @@ trait BotAPI $newd = array_merge($newd, $this->MTProtoToBotAPI($data['media'])); } return $newd; - case 'messageEntityCustomEmoji': - $data['type'] = 'custom_emoji'; - $data['custom_emoji_id'] = $data['document_id']; - unset($data['_'], $data['document_id']); - return $data; - case 'messageEntityPhone': - unset($data['_']); - $data['type'] = 'phone_number'; - return $data; - case 'messageEntityBlockquote': - unset($data['_']); - $data['type'] = 'block_quote'; - return $data; - case 'messageEntityMention': - unset($data['_']); - $data['type'] = 'mention'; - return $data; - case 'messageEntityHashtag': - unset($data['_']); - $data['type'] = 'hashtag'; - return $data; - case 'messageEntityBotCommand': - unset($data['_']); - $data['type'] = 'bot_command'; - return $data; - case 'messageEntityUrl': - unset($data['_']); - $data['type'] = 'url'; - return $data; - case 'messageEntityEmail': - unset($data['_']); - $data['type'] = 'email'; - return $data; - case 'messageEntityBold': - unset($data['_']); - $data['type'] = 'bold'; - return $data; - case 'messageEntityStrike': - unset($data['_']); - $data['type'] = 'strikethrough'; - return $data; - case 'messageEntitySpoiler': - unset($data['_']); - $data['type'] = 'spoiler'; - return $data; - case 'messageEntityUnderline': - unset($data['_']); - $data['type'] = 'underline'; - return $data; - case 'messageEntityItalic': - unset($data['_']); - $data['type'] = 'italic'; - return $data; - case 'messageEntityCode': - unset($data['_']); - $data['type'] = 'code'; - return $data; - case 'messageEntityPre': - unset($data['_']); - $data['type'] = 'pre'; - return $data; - case 'messageEntityTextUrl': - unset($data['_']); - $data['type'] = 'text_url'; - return $data; case 'messageEntityMentionName': case 'inputMessageEntityMentionName': unset($data['_']); @@ -416,6 +351,81 @@ trait BotAPI 'mime_type' => 'application/octet-stream', ]; return ['encrypted' => $res]; + default: + return self::MTProtoEntityToBotAPI($data); + } + } + /** + * @internal + */ + public static function MTProtoEntityToBotAPI(array $data): array + { + switch ($data['_']) { + case 'messageEntityCustomEmoji': + $data['type'] = 'custom_emoji'; + $data['custom_emoji_id'] = $data['document_id']; + unset($data['_'], $data['document_id']); + return $data; + case 'messageEntityPhone': + unset($data['_']); + $data['type'] = 'phone_number'; + return $data; + case 'messageEntityBlockquote': + unset($data['_']); + $data['type'] = 'block_quote'; + return $data; + case 'messageEntityMention': + unset($data['_']); + $data['type'] = 'mention'; + return $data; + case 'messageEntityHashtag': + unset($data['_']); + $data['type'] = 'hashtag'; + return $data; + case 'messageEntityBotCommand': + unset($data['_']); + $data['type'] = 'bot_command'; + return $data; + case 'messageEntityUrl': + unset($data['_']); + $data['type'] = 'url'; + return $data; + case 'messageEntityEmail': + unset($data['_']); + $data['type'] = 'email'; + return $data; + case 'messageEntityBold': + unset($data['_']); + $data['type'] = 'bold'; + return $data; + case 'messageEntityStrike': + unset($data['_']); + $data['type'] = 'strikethrough'; + return $data; + case 'messageEntitySpoiler': + unset($data['_']); + $data['type'] = 'spoiler'; + return $data; + case 'messageEntityUnderline': + unset($data['_']); + $data['type'] = 'underline'; + return $data; + case 'messageEntityItalic': + unset($data['_']); + $data['type'] = 'italic'; + return $data; + case 'messageEntityCode': + unset($data['_']); + $data['type'] = 'code'; + return $data; + case 'messageEntityPre': + unset($data['_']); + $data['type'] = 'pre'; + return $data; + case 'messageEntityTextUrl': + unset($data['_']); + $data['type'] = 'text_url'; + return $data; default: throw new Exception(sprintf(Lang::$current_lang['botapi_conversion_error'], $data['_'])); } diff --git a/src/TL/Conversion/DOMEntities.php b/src/TL/Conversion/DOMEntities.php index 48a08eae6..39c46ca50 100644 --- a/src/TL/Conversion/DOMEntities.php +++ b/src/TL/Conversion/DOMEntities.php @@ -78,7 +78,9 @@ final class DOMEntities extends Entities 'i', 'em' => ['_' => 'messageEntityItalic'], 'code' => ['_' => 'messageEntityCode'], 'spoiler', 'tg-spoiler' => ['_' => 'messageEntitySpoiler'], - 'pre' => ['_' => 'messageEntityPre', 'language' => $node->getAttribute('language')], + 'pre' => $node->hasAttribute('language') + ? ['_' => 'messageEntityPre', 'language' => $node->getAttribute('language')] + : ['_' => 'messageEntityPre'], 'tg-emoji' => ['_' => 'messageEntityCustomEmoji', 'document_id' => (int) $node->getAttribute('emoji-id')], 'emoji' => ['_' => 'messageEntityCustomEmoji', 'document_id' => (int) $node->getAttribute('id')], 'a' => self::handleLink($node->getAttribute('href')), diff --git a/src/TL/Conversion/MarkdownEntities.php b/src/TL/Conversion/MarkdownEntities.php index 1afb7d078..755eadbbe 100644 --- a/src/TL/Conversion/MarkdownEntities.php +++ b/src/TL/Conversion/MarkdownEntities.php @@ -149,15 +149,19 @@ final class MarkdownEntities extends Entities $pieceLen--; } if ($pieceLen > 0) { - $entities []= [ + $tmp = [ '_' => match ($token) { '```' => 'messageEntityPre', '`' => 'messageEntityCode', }, - 'language' => $language, 'offset' => $start, 'length' => $pieceLen, ]; + if ($language !== null) { + $tmp['language'] = $language; + } + $entities []= $tmp; + unset($tmp); } $offset = $posClose+\strlen($token); diff --git a/tests/danog/MadelineProto/EntitiesTest.php b/tests/danog/MadelineProto/EntitiesTest.php index 1eaa951a4..7e0d49367 100644 --- a/tests/danog/MadelineProto/EntitiesTest.php +++ b/tests/danog/MadelineProto/EntitiesTest.php @@ -4,11 +4,15 @@ declare(strict_types=1); namespace danog\MadelineProto\Test; +use danog\MadelineProto\MTProto; use danog\MadelineProto\StrTools; +use danog\MadelineProto\TL\Conversion\DOMEntities; +use danog\MadelineProto\TL\Conversion\MarkdownEntities; use danog\MadelineProto\Tools; +use PHPUnit\Framework\TestCase; /** @internal */ -class EntitiesTest extends MadelineTestCase +class EntitiesTest extends TestCase { public function testMb(): void { @@ -27,40 +31,63 @@ class EntitiesTest extends MadelineTestCase $this->assertEquals(['aπŸ‘', 'aπŸ‘'], StrTools::mbStrSplit('aπŸ‘aπŸ‘', 3)); $this->assertEquals(['πŸ‡ΊπŸ‡¦', 'πŸ‡ΊπŸ‡¦'], StrTools::mbStrSplit('πŸ‡ΊπŸ‡¦πŸ‡ΊπŸ‡¦', 4)); } + private static function sendMessage(string $message, string $parse_mode): DOMEntities|MarkdownEntities + { + return match ($parse_mode) { + 'html' => (new DOMEntities($message)), + 'markdown' => (new MarkdownEntities($message)), + }; + } + private static function MTProtoToBotAPI(DOMEntities|MarkdownEntities $entities): array + { + $result = ['text' => $entities->message]; + $entities = $entities->entities; + foreach ($entities as &$entity) { + switch ($entity['_']) { + case 'messageEntityMentionName': + case 'inputMessageEntityMentionName': + unset($entity['_']); + $entity['type'] = 'text_mention'; + $entity['user'] = $entity['user_id']; + unset($entity['user_id']); + break; + default: + $entity = MTProto::MTProtoEntityToBotAPI($entity); + } + } + $result['entities'] = $entities; + return $result; + } /** * @dataProvider provideEntities */ public function testEntities(string $mode, string $html, string $bare, array $entities, ?string $htmlReverse = null): void { - $resultMTProto = self::$MadelineProto->messages->sendMessage(peer: getenv('DEST'), message: $html, parse_mode: $mode); - $resultMTProto = self::$MadelineProto->extractMessage($resultMTProto); - $result = self::$MadelineProto->MTProtoToBotAPI($resultMTProto); + $resultMTProto = self::sendMessage(message: $html, parse_mode: $mode); + $result = self::MTProtoToBotAPI($resultMTProto); $this->assertEquals($bare, $result['text']); $this->assertEquals($entities, $result['entities']); if (strtolower($mode) === 'html') { $this->assertEquals( str_replace(['
', ' ', 'mention:'], ['
', ' ', 'tg://user?id='], $htmlReverse ?? $html), StrTools::entitiesToHtml( - $resultMTProto['message'], - $resultMTProto['entities'], + $resultMTProto->message, + $resultMTProto->entities, true ), ); - $resultMTProto = self::$MadelineProto->messages->sendMessage(peer: getenv('DEST'), message: StrTools::htmlEscape($html), parse_mode: $mode); - $resultMTProto = self::$MadelineProto->extractMessage($resultMTProto); - $result = self::$MadelineProto->MTProtoToBotAPI($resultMTProto); + $resultMTProto = self::sendMessage(message: StrTools::htmlEscape($html), parse_mode: $mode); + $result = self::MTProtoToBotAPI($resultMTProto); $this->assertEquals($html, $result['text']); $this->assertNoRelevantEntities($result['entities']); } else { - $resultMTProto = self::$MadelineProto->messages->sendMessage(peer: getenv('DEST'), message: Tools::markdownEscape($html), parse_mode: $mode); - $resultMTProto = self::$MadelineProto->extractMessage($resultMTProto); - $result = self::$MadelineProto->MTProtoToBotAPI($resultMTProto); + $resultMTProto = self::sendMessage(message: Tools::markdownEscape($html), parse_mode: $mode); + $result = self::MTProtoToBotAPI($resultMTProto); $this->assertEquals($html, $result['text']); $this->assertNoRelevantEntities($result['entities']); - $resultMTProto = self::$MadelineProto->messages->sendMessage(peer: getenv('DEST'), message: "```\n".Tools::markdownCodeblockEscape($html)."\n```", parse_mode: $mode); - $resultMTProto = self::$MadelineProto->extractMessage($resultMTProto); - $result = self::$MadelineProto->MTProtoToBotAPI($resultMTProto); + $resultMTProto = self::sendMessage(message: "```\n".Tools::markdownCodeblockEscape($html)."\n```", parse_mode: $mode); + $result = self::MTProtoToBotAPI($resultMTProto); $this->assertEquals($html, rtrim($result['text'])); $result['entities'][0]['language'] = ''; // Telegram now has automatic language detection $this->assertEquals([['offset' => 0, 'length' => StrTools::mbStrlen($html), 'language' => '', 'type' => 'pre']], $result['entities']); @@ -79,7 +106,6 @@ class EntitiesTest extends MadelineTestCase public function provideEntities(): array { $this->setUpBeforeClass(); - $mention = self::$MadelineProto->getPwrChat(getenv('TEST_USERNAME'), false); return [ [ 'html', @@ -179,7 +205,7 @@ class EntitiesTest extends MadelineTestCase ], [ 'html', - 'test
test test
test
test strikethrough underline
blockquote
https://google.com daniil@daniil.it +39398172758722 @daniilgentili spoiler <b>not_bold</b>', + 'test
test test
test
test strikethrough underline
blockquote
https://google.com daniil@daniil.it +39398172758722 @daniilgentili spoiler <b>not_bold</b>', "test\ntest test test test strikethrough underline blockquote https://google.com daniil@daniil.it +39398172758722 @daniilgentili spoiler not_bold", [ [ @@ -224,49 +250,29 @@ class EntitiesTest extends MadelineTestCase 'length' => 10, 'type' => 'block_quote', ], - [ - 'offset' => 60, - 'length' => 18, - 'type' => 'url', - ], - [ - 'offset' => 79, - 'length' => 16, - 'type' => 'email', - ], - [ - 'offset' => 96, - 'length' => 15, - 'type' => 'phone_number', - ], - [ - 'offset' => 112, - 'length' => 14, - 'type' => 'mention', - ], [ 'offset' => 127, 'length' => 7, 'type' => 'spoiler', ], ], - 'test
test test
test
test strikethrough underline
blockquote
https://google.com daniil@daniil.it +39398172758722 @daniilgentili spoiler <b>not_bold</b>', + 'test
test test
test
test strikethrough underline
blockquote
https://google.com daniil@daniil.it +39398172758722 @daniilgentili spoiler <b>not_bold</b>', ], [ 'markdown', 'test *bold _bold and italic_ bold*', 'test bold bold and italic bold', [ - [ - 'offset' => 5, - 'length' => 25, - 'type' => 'bold', - ], [ 'offset' => 10, 'length' => 15, 'type' => 'italic', ], + [ + 'offset' => 5, + 'length' => 25, + 'type' => 'bold', + ], ], ], [ @@ -315,20 +321,20 @@ class EntitiesTest extends MadelineTestCase ], [ 'html', - 'mention1 mention2', + 'mention1 mention2', 'mention1 mention2', [ [ 'offset' => 0, 'length' => 8, 'type' => 'text_mention', - 'user' => $mention, + 'user' => 101374607, ], [ 'offset' => 9, 'length' => 8, 'type' => 'text_mention', - 'user' => $mention, + 'user' => 101374607, ], ], ],