Initial commit - Last War messaging system

This commit is contained in:
2026-02-19 01:33:28 -06:00
commit 38a8447a64
2162 changed files with 216183 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
<?php
/*
* This file is a part of the DiscordPHP project.
*
* Copyright (c) 2015-present David Cole <david.cole1340@gmail.com>
*
* This file is subject to the MIT license that is bundled
* with this source code in the LICENSE.md file.
*/
use Discord\Discord;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
class DiscordSingleton
{
private static $discord;
/**
* @return Discord
*/
public static function get()
{
if (! self::$discord) {
self::new();
}
return self::$discord;
}
private static function new()
{
$logger = new Logger('DiscordPHP-UnitTests');
$handler = new StreamHandler(fopen(__DIR__.'/../phpunit.log', 'w'));
$formatter = new LineFormatter(null, null, true, true);
$handler->setFormatter($formatter);
$logger->pushHandler($handler);
$discord = new Discord([
'token' => getenv('DISCORD_TOKEN'),
'logger' => $logger,
]);
$e = null;
$timer = $discord->getLoop()->addTimer(10, function () use (&$e) {
$e = new Exception('Timed out trying to connect to Discord.');
});
$discord->on('ready', function (Discord $discord) use ($timer) {
$discord->getLoop()->cancelTimer($timer);
$discord->getLoop()->stop();
});
$discord->getLoop()->run();
if ($e !== null) {
throw $e;
}
self::$discord = $discord;
}
}

View File

@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
/*
* This file is a part of the DiscordPHP project.
*
* Copyright (c) 2015-present David Cole <david.cole1340@gmail.com>
*
* This file is subject to the MIT license that is bundled
* with this source code in the LICENSE.md file.
*/
use PHPUnit\Framework\TestCase;
final class DiscordTest extends TestCase
{
public function testCheckEnvVariablesPresent()
{
$this->assertNotFalse(getenv('DISCORD_TOKEN'), 'Discord token is missing');
$this->assertNotFalse(getenv('TEST_CHANNEL'), 'Test channel ID is missing');
$this->assertNotFalse(getenv('TEST_CHANNEL_NAME'), 'Test channel name is missing');
}
}

View File

@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
/*
* This file is a part of the DiscordPHP project.
*
* Copyright (c) 2015-present David Cole <david.cole1340@gmail.com>
*
* This file is subject to the MIT license that is bundled
* with this source code in the LICENSE.md file.
*/
use Discord\Discord;
use Discord\Parts\Channel\Channel;
use PHPUnit\Framework\TestCase;
class DiscordTestCase extends TestCase
{
protected static Channel $channel;
public static function setUpBeforeClass(): void
{
self::$channel = wait(function (Discord $discord, $resolve) {
$channel = $discord->getChannel(getenv('TEST_CHANNEL'));
$resolve($channel);
});
}
protected function channel()
{
return self::$channel;
}
}

View File

@@ -0,0 +1,72 @@
<?php
/*
* This file is a part of the DiscordPHP project.
*
* Copyright (c) 2015-present David Cole <david.cole1340@gmail.com>
*
* This file is subject to the MIT license that is bundled
* with this source code in the LICENSE.md file.
*/
use PHPUnit\Framework\TestCase;
use function Discord\contains;
use function Discord\getColor;
use function Discord\poly_strlen;
final class FunctionsTest extends TestCase
{
public function containsProvider()
{
return [
[true, 'hello, world!', ['hello']],
[true, 'phpunit tests', ['p', 'u']],
[false, 'phpunit tests', ['a']],
];
}
/**
* @dataProvider containsProvider
*/
public function testContains($expected, $needle, $haystack)
{
$this->assertEquals($expected, contains($needle, $haystack));
}
public function colorProvider()
{
return [
[0xcd5c5c, 'indianred'],
[0x00bfff, 'deepskyblue'],
[0x00bfff, 0x00bfff],
[0, 0],
[0x00bfff, '0x00bfff'],
];
}
/**
* @dataProvider colorProvider
*/
public function testGetColor($expected, $color)
{
$this->assertEquals($expected, getColor($color));
}
public function strlenProvider()
{
return [
[5, 'abcde'],
[0, ''],
[1, ' '],
];
}
/**
* @dataProvider strlenProvider
*/
public function testPolyStrlen($expected, $string)
{
$this->assertEquals($expected, poly_strlen($string));
}
}

View File

@@ -0,0 +1,280 @@
<?php
declare(strict_types=1);
/*
* This file is a part of the DiscordPHP project.
*
* Copyright (c) 2015-present David Cole <david.cole1340@gmail.com>
*
* This file is subject to the MIT license that is bundled
* with this source code in the LICENSE.md file.
*/
use Discord\Builders\MessageBuilder;
use Discord\Discord;
use Discord\Helpers\Collection;
use Discord\Parts\Channel\Channel;
use Discord\Parts\Channel\Message;
use Discord\Parts\Channel\Invite;
/**
* @covers \Discord\Parts\Channel\Channel
*/
final class ChannelTest extends DiscordTestCase
{
/**
* @covers \Discord\Parts\Channel\Channel::pinMessage
* @covers \Discord\Parts\Channel\Channel::getPinnedMessages
*/
public function testCanPinMessageAndGetPinnedMessage()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->sendMessage('testing pin message')
->then(function (Message $message) {
return $this->channel()->pinMessage($message)
->then(function () {
return $this->channel()->getPinnedMessages();
})
->then(function (Collection $messages) use ($message) {
$this->assertGreaterThan(0, $messages->count());
$this->assertContains($message->id, $messages->map(function ($message) {
return $message->id;
}));
});
})
->done($resolve, $resolve);
});
}
/**
* @covers \Discord\Parts\Channel\Channel::pinMessage
* @covers \Discord\Parts\Channel\Channel::unpinMessage
* @covers \Discord\Parts\Channel\Channel::getPinnedMessages
*/
public function testCanPinAndUnpinMessageAndCheckItIsUnpinned()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->sendMessage('testing pin message')
->then(function (Message $message) {
return $this->channel()->pinMessage($message)
->then(function () use ($message) {
return $this->channel()->unpinMessage($message);
})
->then(function () {
return $this->channel()->getPinnedMessages();
})
->then(function (Collection $messages) use ($message) {
$this->assertNotContains($message->id, $messages->map(function ($message) {
return $message->id;
}));
});
})
->done($resolve, $resolve);
});
}
/**
* @covers \Discord\Parts\Channel\Channel::getMessage
*/
public function testCanGetMessage()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->sendMessage('testing get message')
->then(function (Message $message) {
return $this->channel()->messages->fetch($message->id)
->then(function (Message $getMessage) use ($message) {
$this->assertEquals($getMessage->id, $message->id);
});
})
->done($resolve, $resolve);
});
}
/**
* @doesNotPerformAssertions
* @covers \Discord\Parts\Channel\Channel::createInvitek
*/
public function testCanCreateInvite()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->createInvite()
->done($resolve, $resolve);
});
}
/**
* @doesNotPerformAssertions
* @covers \Discord\Parts\Channel\Channel::deleteMessages
*/
public function testCanDeleteMessagesWithZeroMessages()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->deleteMessages([])
->done($resolve, $resolve);
});
}
/**
* @doesNotPerformAssertions
* @covers \Discord\Parts\Channel\Channel::deleteMessages
*/
public function testCanDeleteMessagesWithOneMessage()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->sendMessage('testing delete one message')
->then(function (Message $message) {
return $this->channel()->deleteMessages([$message]);
})
->done($resolve, $resolve);
});
}
/**
* @doesNotPerformAssertions
* @covers \Discord\Parts\Channel\Channel::deleteMessages
*/
public function testCanDeleteMessagesWithMultipleMessages()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->sendMessage('testing delete 1/2 message')
->then(function (Message $m1) {
return $this->channel()->sendMessage('testing delete 2/2 message')
->then(function (Message $m2) use ($m1) {
return $this->channel()->deleteMessages([$m1, $m2]);
});
})
->done($resolve, $resolve);
});
}
/**
* @doesNotPerformAssertions
* @covers \Discord\Parts\Channel\Channel::limitDelete
*/
public function testCanLimitDeleteMessages()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->limitDelete(5)
->done($resolve, $resolve);
});
}
/**
* @covers \Discord\Parts\Channel\Channel::getMessageHistory
*/
public function testCanGetMessageHistory()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->getMessageHistory([])
->then(function ($messages) {
$this->assertInstanceOf(Collection::class, $messages);
if ($messages->count() < 1) {
$this->markTestSkipped('no messages were present when gettign message history - could not check if collection contained message objects.');
return;
}
foreach ($messages as $message) {
$this->assertInstanceOf(Message::class, $message);
}
})
->done($resolve, $resolve);
});
}
/**
* @covers \Discord\Parts\Channel\Channel::getInvites
*/
public function testCanGetInvites()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->getInvites()
->then(function (Collection $invites) {
$this->assertInstanceOf(Collection::class, $invites);
if ($invites->count() < 1) {
$this->markTestSkipped('no invites were present when getting invites - could not check if collection contained invite objects.');
return;
}
foreach ($invites as $invite) {
$this->assertInstanceOf(Invite::class, $invite);
}
})
->done($resolve, $resolve);
});
}
/**
* @covers \Discord\Parts\Channel\Channel::editMessage
*/
public function testCanEditMessageThroughChannel()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->sendMessage('testing edit through channel')
->then(function (Message $message) {
return $message->edit(MessageBuilder::new()->setContent('new content'))
->then(function (Message $updatedMessage) use ($message) {
$this->assertEquals('new content', $updatedMessage->content);
$this->assertEquals($message->id, $updatedMessage->id);
});
})
->done($resolve, $resolve);
});
}
/**
* @covers \Discord\Parts\Channel\Channel::sendFile
*/
public function testCanSendFile()
{
return wait(function (Discord $discord, $resolve) {
// upload readme
$baseDir = dirname(dirname(dirname((new ReflectionClass(Discord::class))->getFileName())));
$this->channel()->sendMessage(MessageBuilder::new()->addFile($baseDir.DIRECTORY_SEPARATOR.'README.md'))
->then(function (Message $message) {
$this->assertEquals(1, count($message->attachments));
})
->done($resolve, $resolve);
});
}
/**
* @doesNotPerformAssertions
* @covers \Discord\Parts\Channel\Channel::broadcastTyping
*/
public function testCanBroadcastTyping()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->broadcastTyping()
->done($resolve, $resolve);
});
}
/**
* @covers \Discord\Parts\Channel\Channel::allowVoice
*/
public function testTextChannelDoesNotAllowVoice()
{
$this->assertFalse($this->channel()->allowVoice());
$this->assertTrue($this->channel()->allowText());
}
/**
* @covers \Discord\Parts\Channel\Channel::allowVoice
*/
public function testVoiceChannelAllowVoice()
{
/**
* @var Channel
*/
$vc = $this->channel()->guild->channels->filter(function ($channel) {
return $channel->type == Channel::TYPE_VOICE;
})->first();
$this->assertTrue($vc->allowVoice());
}
}

View File

@@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
/*
* This file is a part of the DiscordPHP project.
*
* Copyright (c) 2015-present David Cole <david.cole1340@gmail.com>
*
* This file is subject to the MIT license that is bundled
* with this source code in the LICENSE.md file.
*/
use Discord\Discord;
use Discord\Parts\Channel\Message;
use Discord\Parts\Embed\Author;
use Discord\Parts\Embed\Embed;
use Discord\Parts\Embed\Footer;
use function Discord\getColor;
final class EmbedMessageTest extends DiscordTestCase
{
/**
* @covers \Discord\Parts\Channel\Channel::sendEmbed
*/
public function testCanSendEmbed()
{
return wait(function (Discord $discord, $resolve) {
$embed = new Embed($discord);
$embed->setTitle('Testing Embed')
->setType(Embed::TYPE_RICH)
->setAuthor('DiscordPHP Bot')
->setDescription('Embed Description')
->setColor(getColor('lightblue'))
->addField([
'name' => 'Field 1',
'value' => 'Value 1',
'inline' => true,
])
->addField([
'name' => 'Field 2',
'value' => 'Value 2',
'inline' => false,
])
->setFooter('Footer Value');
$this->channel()->sendEmbed($embed)
->then(function (Message $message) use ($resolve) {
$this->assertEquals(1, $message->embeds->count());
/** @var Embed */
$embed = $message->embeds->first();
$this->assertEquals('Testing Embed', $embed->title);
$this->assertEquals(Embed::TYPE_RICH, $embed->type);
$this->assertEquals('Embed Description', $embed->description);
$this->assertEquals(getColor('lightblue'), $embed->color);
$this->assertInstanceOf(Author::class, $embed->author);
$this->assertEquals('DiscordPHP Bot', $embed->author->name);
$this->assertInstanceOf(Footer::class, $embed->footer);
$this->assertEquals('Footer Value', $embed->footer->text);
$this->assertEquals(2, $embed->fields->count());
$this->assertNotFalse(isset($embed->fields['Field 1']));
$this->assertNotFalse(isset($embed->fields['Field 2']));
$this->assertNotEquals(
(string) $embed->fields['Field 1'],
(string) $embed->fields['Field 2']
);
})
->done($resolve, $resolve);
}, 10);
}
}

View File

@@ -0,0 +1,258 @@
<?php
declare(strict_types=1);
/*
* This file is a part of the DiscordPHP project.
*
* Copyright (c) 2015-present David Cole <david.cole1340@gmail.com>
*
* This file is subject to the MIT license that is bundled
* with this source code in the LICENSE.md file.
*/
use Carbon\Carbon;
use Discord\Discord;
use Discord\Helpers\Collection;
use Discord\Parts\Channel\Channel;
use Discord\Parts\Channel\Message;
use Discord\Parts\Embed\Embed;
use Discord\Parts\User\User;
final class EmptyMessageTest extends DiscordTestCase
{
/**
* @covers \Discord\Parts\Channel\Channel::sendMessage
*/
public function testCanSendMessage()
{
return wait(function (Discord $discord, $resolve) {
$content = 'Hello, world! From PHPunit';
$this->channel()->sendMessage($content)
->then(function (Message $message) use ($content) {
$this->assertEquals($content, $message->content);
$this->assertInstanceOf(Carbon::class, $message->timestamp);
$this->assertNull($message->edited_timestamp);
return $message;
})
->done($resolve, $resolve);
});
}
/**
* @depends testCanSendMessage
* @covers \Discord\Parts\Channel\Message::reply
*/
public function testCanReplyToMessage(Message $message)
{
return wait(function (Discord $discord, $resolve) use ($message) {
$message->reply('replying to my message')
->then(function (Message $new_message) use ($message) {
$this->assertEquals('replying to my message', $new_message->content);
$this->assertInstanceOf(Message::class, $new_message->referenced_message);
$this->assertEquals($message->id, $new_message->referenced_message->id);
return $new_message;
})
->done($resolve, $resolve);
});
}
/**
* @covers \Discord\Repository\Channel\MessageRepository::save
*/
public function testCanEditMessage()
{
return wait(function (Discord $discord, $resolve) {
$content = 'Message edit with PHPunit';
$this->channel()->sendMessage('before edit')
->then(function (Message $message) use ($content) {
$message->content = $content;
return $message->channel->messages->save($message)->then(function (Message $message) use ($content) {
$this->assertEquals($content, $message->content);
$this->assertNotNull($message->edited_timestamp);
return $message;
});
})
->done($resolve, $resolve);
});
}
/**
* @depends testCanSendMessage
* @covers \Discord\Parts\Channel\Message::getCrosspostedAttribute
* @covers \Discord\Parts\Channel\Message::getIsCrosspostAttribute
* @covers \Discord\Parts\Channel\Message::getSuppressEmbedsAttribute
* @covers \Discord\Parts\Channel\Message::getSourceMessageDeletedAttribute
* @covers \Discord\Parts\Channel\Message::getUrgentAttribute
*/
public function testCheckMessageFlagsFalse(Message $message)
{
$this->assertFalse($message->crossposted);
$this->assertFalse($message->is_crosspost);
$this->assertFalse($message->suppress_embeds);
$this->assertFalse($message->source_message_deleted);
$this->assertFalse($message->urgent);
}
/**
* @depends testCanSendMessage
* @covers \Discord\Parts\Channel\Message::getChannelAttribute
*/
public function testChannelAttribute(Message $message)
{
$this->assertInstanceOf(Channel::class, $message->channel);
$this->assertEquals($message->channel_id, $message->channel->id);
}
/**
* @depends testCanSendMessage
* @covers \Discord\Parts\Channel\Message::getMentionsAttribute
* @covers \Discord\Parts\Channel\Message::getMentionRolesAttribute
* @covers \Discord\Parts\Channel\Message::getMentionChannelsAttribute
* @covers \Discord\Parts\Channel\Message::getEmbedsAttribute
*/
public function testCollectionsEmpty(Message $message)
{
$this->assertInstanceOf(Collection::class, $message->mentions);
$this->assertEquals(0, $message->mentions->count());
$this->assertInstanceOf(Collection::class, $message->mention_roles);
$this->assertEquals(0, $message->mention_roles->count());
$this->assertInstanceOf(Collection::class, $message->reactions);
$this->assertEquals(0, $message->reactions->count());
$this->assertInstanceOf(Collection::class, $message->mention_channels);
$this->assertEquals(0, $message->mention_channels->count());
$this->assertInstanceOf(Collection::class, $message->embeds);
$this->assertEquals(0, $message->embeds->count());
}
/**
* @depends testCanSendMessage
* @covers \Discord\Parts\Channel\Message::getAuthorAttribute
*/
public function testAuthorAttribute(Message $message)
{
$this->assertInstanceOf(User::class, $message->author);
$this->assertEquals($message->author->id, DiscordSingleton::get()->id);
}
/**
* @depends testCanEditMessage
* @covers \Discord\Parts\Channel\Message::getEditedTimestampAttribute
*/
public function testEditedTimestampAttribute(Message $message)
{
$this->assertInstanceOf(Carbon::class, $message->edited_timestamp);
}
/**
* @covers \Discord\Parts\Channel\Message::delayedReply
*/
public function testDelayedReply()
{
return wait(function (Discord $discord, $resolve) {
// Random delay between 0 and 5s.
$delay = (int) ((mt_rand() / mt_getrandmax()) * 5000);
$start = microtime(true);
$this->channel()->sendMessage('testing delayed reply')
->then(function (Message $message) use ($delay) {
return $message->delayedReply('delayed reply to message', $delay);
})
->then(function (Message $message) use ($delay, $start, $resolve) {
$stop = microtime(true);
$diff = $stop - $start;
$this->assertGreaterThanOrEqual($delay / 1000, $diff);
})
->done($resolve, $resolve);
}, 10);
}
/**
* @doesNotPerformAssertions
* @covers \Discord\Parts\Channel\Message::react
*/
public function testCanReactWithString()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->sendMessage('testing reactions')
->then(function (Message $message) {
return $message->react('😀');
})
->done($resolve, $resolve);
});
}
/**
* @depends testCanSendMessage
* @covers \Discord\Parts\Channel\Message::addEmbed
*/
public function testCanAddEmbed(Message $message)
{
return wait(function (Discord $discord, $resolve) use ($message) {
$this->channel()->sendMessage('testing adding embed')
->then(function (Message $message) use ($discord) {
$embed = new Embed($discord);
$embed->setTitle('Test embed')
->addFieldValues('Field name', 'Field value', true);
return $message->addEmbed($embed);
})
->then(function (Message $message) {
$this->assertEquals(1, $message->embeds->count());
/** @var Embed */
$embed = $message->embeds->first();
$this->assertEquals('Test embed', $embed->title);
$this->assertEquals(1, $embed->fields->count());
/** @var \Discord\Parts\Embed\Field */
$field = $embed->fields->first();
$this->assertEquals('Field name', $field->name);
$this->assertEquals('Field value', $field->value);
$this->assertEquals(true, $field->inline);
})
->done($resolve, $resolve);
});
}
/**
* @depends testCanSendMessage
* @covers \Discord\Repository\Channel\MessageRepository::delete
*/
public function testCanDeleteMessageThroughRepository(Message $message)
{
return wait(function (Discord $discord, $resolve) use ($message) {
$message->channel->messages->delete($message)
->then(function (Message $message) {
$this->assertFalse($message->created);
})
->done($resolve, $resolve);
});
}
/**
* @doesNotPerformAssertions
* @covers \Discord\Parts\Channel\Message::delete
*/
public function testCanDeleteMessageThroughPart()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->sendMessage('testing delete through part')
->then(function (Message $message) {
return $message->delete();
})
->done($resolve);
});
}
}

View File

@@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
/*
* This file is a part of the DiscordPHP project.
*
* Copyright (c) 2015-present David Cole <david.cole1340@gmail.com>
*
* This file is subject to the MIT license that is bundled
* with this source code in the LICENSE.md file.
*/
use Discord\Discord;
use Discord\Parts\Channel\Channel;
use Discord\Parts\Channel\Message;
final class MessageTest extends DiscordTestCase
{
/**
* @covers \Discord\Parts\Channel\Message::getMentionChannelsAttribute
*/
public function testCanMentionChannel()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->sendMessage('mention channel <#'.$this->channel()->id.'>')
->then(function (Message $message) {
$this->assertEquals(1, $message->mention_channels->count());
$this->assertInstanceOf(Channel::class, $message->mention_channels->first());
$this->assertEquals($this->channel()->id, $message->mention_channels->first()->id);
})
->done($resolve, $resolve);
});
}
/**
* @covers \Discord\Parts\Channel\Message::crosspost
*/
public function testCanCrosspostMessage()
{
return wait(function (Discord $discord, $resolve) {
$this->channel()->sendMessage('crossposting message')
->then(function (Message $message) {
return $message->crosspost();
})
->then(function ($message) {
$this->assertInstanceOf(Message::class, $message);
})
->done($resolve, $resolve);
}, 10, function () {
$this->markTestIncomplete('Crosspost has likely hit ratelimit.');
});
}
}

View File

@@ -0,0 +1,104 @@
<?php
declare(strict_types=1);
/*
* This file is a part of the DiscordPHP project.
*
* Copyright (c) 2015-present David Cole <david.cole1340@gmail.com>
*
* This file is subject to the MIT license that is bundled
* with this source code in the LICENSE.md file.
*/
use Discord\Discord;
use Discord\Parts\Channel\Message;
final class RemoveReactionTest extends DiscordTestCase
{
/**
* @doesNotPerformAssertions
* @covers \Discord\Parts\Channel\Message::deleteReaction
*/
public function testDeleteAllReactions()
{
return wait(function (Discord $discord, $resolve) {
$this
->channel()
->sendMessage('testing delete all reactions')
->then(function (Message $message) {
return \React\Promise\all($message->react('😝'), $message->react('🤪'))
->then(function () use ($message) {
return $message;
});
})
->then(function (Message $message) {
return $message->deleteReaction(Message::REACT_DELETE_ALL);
})
->done($resolve, $resolve);
});
}
/**
* @doesNotPerformAssertions
* @covers \Discord\Parts\Channel\Message::deleteReaction
*/
public function testDeleteSelfReaction()
{
return wait(function (Discord $discord, $resolve) {
$this
->channel()
->sendMessage('testing deleting self reaction')
->then(function (Message $message) {
return $message->react('🤪')->then(function () use ($message) {
return $message;
});
})->then(function (Message $message) {
return $message->deleteReaction(Message::REACT_DELETE_ME, '🤪');
})
->done($resolve, $resolve);
});
}
/**
* @doesNotPerformAssertions
* @covers \Discord\Parts\Channel\Message::deleteReaction
*/
public function testDeleteReactionOfUser()
{
return wait(function (Discord $discord, $resolve) {
$this
->channel()
->sendMessage('testing deleting reaction of user')
->then(function (Message $message) {
return $message->react('🤪')->then(function () use ($message) {
return $message;
});
})->then(function (Message $message) use ($discord) {
return $message->deleteReaction(Message::REACT_DELETE_ID, '🤪', $discord->id);
})
->done($resolve, $resolve);
});
}
/**
* @doesNotPerformAssertions
* @covers \Discord\Parts\Channel\Message::deleteReaction
*/
public function testDeleteAllReactionsForEmoji()
{
return wait(function (Discord $discord, $resolve) {
$this
->channel()
->sendMessage('testing deleting of single reaction')
->then(function (Message $message) {
return $message->react('🤪')->then(function () use ($message) {
return $message;
});
})->then(function (Message $message) use ($discord) {
return $message->deleteReaction(Message::REACT_DELETE_EMOJI, '🤪');
})
->done($resolve, $resolve);
});
}
}

View File

@@ -0,0 +1,72 @@
<?php
/*
* This file is a part of the DiscordPHP project.
*
* Copyright (c) 2015-present David Cole <david.cole1340@gmail.com>
*
* This file is subject to the MIT license that is bundled
* with this source code in the LICENSE.md file.
*/
use Discord\Discord;
use Discord\Parts\Channel\Message;
use Discord\Parts\Embed\Author;
use Discord\Parts\Embed\Embed;
use Discord\Parts\Embed\Image;
use Discord\Parts\Embed\Video;
use function Discord\contains;
final class EmbedTest extends DiscordTestCase
{
public function testCanGetVideoEmbed()
{
return wait(function (Discord $discord, $resolve) {
// kek
$url = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ';
$this->channel()->sendMessage($url)
->then(function (Message $message) {
// fetch message to ensure embed is present
return $this->channel()->messages->fetch($message->id);
})
->then(function (Message $message) use ($url) {
$this->assertEquals(1, $message->embeds->count());
/** @var \Discord\Parts\Embed\Embed */
$embed = $message->embeds->first();
$this->assertInstanceOf(Video::class, $embed->video);
$this->assertInstanceOf(Image::class, $embed->thumbnail);
$this->assertInstanceOf(Author::class, $embed->author);
$this->assertTrue(contains($embed->video->url, ['dQw4w9WgXcQ']));
$this->assertEquals($url, $embed->url);
$this->assertEquals(Embed::TYPE_VIDEO, $embed->type);
})
->done($resolve, $resolve);
}, 10);
}
public function testCanGetImageEmbed()
{
return wait(function (Discord $discord, $resolve) {
$url = 'https://discord.com/assets/94db9c3c1eba8a38a1fcf4f223294185.png';
$this->channel()->sendMessage($url)
->then(function (Message $message) {
// fetch message to ensure embed is present
return $this->channel()->messages->fetch($message->id);
})
->then(function (Message $message) use ($url) {
$this->assertEquals(1, $message->embeds->count());
/** @var \Discord\Parts\Embed\Embed */
$embed = $message->embeds->first();
$this->assertEquals($url, $embed->url);
$this->assertEquals(Embed::TYPE_IMAGE, $embed->type);
$this->assertInstanceOf(Image::class, $embed->thumbnail);
})
->done($resolve, $resolve);
}, 10);
}
}

View File

@@ -0,0 +1,15 @@
<?php
/*
* This file is a part of the DiscordPHP project.
*
* Copyright (c) 2015-present David Cole <david.cole1340@gmail.com>
*
* This file is subject to the MIT license that is bundled
* with this source code in the LICENSE.md file.
*/
include __DIR__.'/../vendor/autoload.php';
include __DIR__.'/functions.php';
include __DIR__.'/DiscordSingleton.php';
include __DIR__.'/DiscordTestCase.php';

View File

@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
/*
* This file is a part of the DiscordPHP project.
*
* Copyright (c) 2015-present David Cole <david.cole1340@gmail.com>
*
* This file is subject to the MIT license that is bundled
* with this source code in the LICENSE.md file.
*/
const TIMEOUT = 10;
function wait(callable $callback, float $timeout = TIMEOUT, callable $timeoutFn = null)
{
$discord = DiscordSingleton::get();
$result = null;
$finally = null;
$timedOut = false;
$discord->getLoop()->futureTick(function () use ($callback, $discord, &$result, &$finally) {
$resolve = function ($x = null) use ($discord, &$result) {
$result = $x;
$discord->getLoop()->stop();
};
try {
$finally = $callback($discord, $resolve);
} catch (\Throwable $e) {
$resolve($e);
}
});
$timeout = $discord->getLoop()->addTimer($timeout, function () use ($discord, &$timedOut) {
$timedOut = true;
$discord->getLoop()->stop();
});
$discord->getLoop()->run();
$discord->getLoop()->cancelTimer($timeout);
if ($result instanceof Exception) {
throw $result;
}
if (is_callable($finally)) {
$finally();
}
if ($timedOut) {
if ($timeoutFn != null) {
$timeoutFn();
} else {
throw new \Exception('Timed out');
}
}
return $result;
}