123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- <?php
- /**
- * @copyright Copyright (c) 2020, Daniel Calviño Sánchez (danxuliu@gmail.com)
- *
- * @author Daniel Calviño Sánchez <danxuliu@gmail.com>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- use Behat\Gherkin\Node\TableNode;
- use PHPUnit\Framework\Assert;
- require __DIR__ . '/../../vendor/autoload.php';
- trait Avatar {
- /** @var string **/
- private $lastAvatar;
- /** @AfterScenario **/
- public function cleanupLastAvatar() {
- $this->lastAvatar = null;
- }
- private function getLastAvatar() {
- $this->lastAvatar = '';
- $body = $this->response->getBody();
- while (!$body->eof()) {
- $this->lastAvatar .= $body->read(8192);
- }
- $body->close();
- }
- /**
- * @When user :user gets avatar for user :userAvatar
- *
- * @param string $user
- * @param string $userAvatar
- */
- public function userGetsAvatarForUser(string $user, string $userAvatar) {
- $this->userGetsAvatarForUserWithSize($user, $userAvatar, '128');
- }
- /**
- * @When user :user gets avatar for user :userAvatar with size :size
- *
- * @param string $user
- * @param string $userAvatar
- * @param string $size
- */
- public function userGetsAvatarForUserWithSize(string $user, string $userAvatar, string $size) {
- $this->asAn($user);
- $this->sendingToDirectUrl('GET', '/index.php/avatar/' . $userAvatar . '/' . $size);
- $this->theHTTPStatusCodeShouldBe('200');
- $this->getLastAvatar();
- }
- /**
- * @When user :user gets avatar for guest :guestAvatar
- *
- * @param string $user
- * @param string $guestAvatar
- */
- public function userGetsAvatarForGuest(string $user, string $guestAvatar) {
- $this->asAn($user);
- $this->sendingToDirectUrl('GET', '/index.php/avatar/guest/' . $guestAvatar . '/128');
- $this->theHTTPStatusCodeShouldBe('201');
- $this->getLastAvatar();
- }
- /**
- * @When logged in user gets temporary avatar
- */
- public function loggedInUserGetsTemporaryAvatar() {
- $this->loggedInUserGetsTemporaryAvatarWith('200');
- }
- /**
- * @When logged in user gets temporary avatar with :statusCode
- *
- * @param string $statusCode
- */
- public function loggedInUserGetsTemporaryAvatarWith(string $statusCode) {
- $this->sendingAToWithRequesttoken('GET', '/index.php/avatar/tmp');
- $this->theHTTPStatusCodeShouldBe($statusCode);
- $this->getLastAvatar();
- }
- /**
- * @When logged in user posts temporary avatar from file :source
- *
- * @param string $source
- */
- public function loggedInUserPostsTemporaryAvatarFromFile(string $source) {
- $file = \GuzzleHttp\Psr7\Utils::streamFor(fopen($source, 'r'));
- $this->sendingAToWithRequesttoken('POST', '/index.php/avatar',
- [
- 'multipart' => [
- [
- 'name' => 'files[]',
- 'contents' => $file
- ]
- ]
- ]);
- $this->theHTTPStatusCodeShouldBe('200');
- }
- /**
- * @When logged in user posts temporary avatar from internal path :path
- *
- * @param string $path
- */
- public function loggedInUserPostsTemporaryAvatarFromInternalPath(string $path) {
- $this->sendingAToWithRequesttoken('POST', '/index.php/avatar?path=' . $path);
- $this->theHTTPStatusCodeShouldBe('200');
- }
- /**
- * @When logged in user crops temporary avatar
- *
- * @param TableNode $crop
- */
- public function loggedInUserCropsTemporaryAvatar(TableNode $crop) {
- $this->loggedInUserCropsTemporaryAvatarWith('200', $crop);
- }
- /**
- * @When logged in user crops temporary avatar with :statusCode
- *
- * @param string $statusCode
- * @param TableNode $crop
- */
- public function loggedInUserCropsTemporaryAvatarWith(string $statusCode, TableNode $crop) {
- $parameters = [];
- foreach ($crop->getRowsHash() as $key => $value) {
- $parameters[] = 'crop[' . $key . ']=' . $value;
- }
- $this->sendingAToWithRequesttoken('POST', '/index.php/avatar/cropped?' . implode('&', $parameters));
- $this->theHTTPStatusCodeShouldBe($statusCode);
- }
- /**
- * @When logged in user deletes the user avatar
- */
- public function loggedInUserDeletesTheUserAvatar() {
- $this->sendingAToWithRequesttoken('DELETE', '/index.php/avatar');
- $this->theHTTPStatusCodeShouldBe('200');
- }
- /**
- * @Then last avatar is a square of size :size
- *
- * @param string size
- */
- public function lastAvatarIsASquareOfSize(string $size) {
- [$width, $height] = getimagesizefromstring($this->lastAvatar);
- Assert::assertEquals($width, $height, 'Expected avatar to be a square');
- Assert::assertEquals($size, $width);
- }
- /**
- * @Then last avatar is not a square
- */
- public function lastAvatarIsNotASquare() {
- [$width, $height] = getimagesizefromstring($this->lastAvatar);
- Assert::assertNotEquals($width, $height, 'Expected avatar to not be a square');
- }
- /**
- * @Then last avatar is not a single color
- */
- public function lastAvatarIsNotASingleColor() {
- Assert::assertEquals(null, $this->getColorFromLastAvatar());
- }
- /**
- * @Then last avatar is a single :color color
- *
- * @param string $color
- * @param string $size
- */
- public function lastAvatarIsASingleColor(string $color) {
- $expectedColor = $this->hexStringToRgbColor($color);
- $colorFromLastAvatar = $this->getColorFromLastAvatar();
- Assert::assertTrue($this->isSameColor($expectedColor, $colorFromLastAvatar),
- $this->rgbColorToHexString($colorFromLastAvatar) . ' does not match expected ' . $color);
- }
- private function hexStringToRgbColor($hexString) {
- // Strip initial "#"
- $hexString = substr($hexString, 1);
- $rgbColorInt = hexdec($hexString);
- // RGBA hex strings are not supported; the given string is assumed to be
- // an RGB hex string.
- return [
- 'red' => ($rgbColorInt >> 16) & 0xFF,
- 'green' => ($rgbColorInt >> 8) & 0xFF,
- 'blue' => $rgbColorInt & 0xFF,
- 'alpha' => 0
- ];
- }
- private function rgbColorToHexString($rgbColor) {
- $rgbColorInt = ($rgbColor['red'] << 16) + ($rgbColor['green'] << 8) + ($rgbColor['blue']);
- return '#' . str_pad(strtoupper(dechex($rgbColorInt)), 6, '0', STR_PAD_LEFT);
- }
- private function getColorFromLastAvatar() {
- $image = imagecreatefromstring($this->lastAvatar);
- $firstPixelColorIndex = imagecolorat($image, 0, 0);
- $firstPixelColor = imagecolorsforindex($image, $firstPixelColorIndex);
- for ($i = 0; $i < imagesx($image); $i++) {
- for ($j = 0; $j < imagesx($image); $j++) {
- $currentPixelColorIndex = imagecolorat($image, $i, $j);
- $currentPixelColor = imagecolorsforindex($image, $currentPixelColorIndex);
- // The colors are compared with a small allowed delta, as even
- // on solid color images the resizing can cause some small
- // artifacts that slightly modify the color of certain pixels.
- if (!$this->isSameColor($firstPixelColor, $currentPixelColor)) {
- imagedestroy($image);
- return null;
- }
- }
- }
- imagedestroy($image);
- return $firstPixelColor;
- }
- private function isSameColor(array $firstColor, array $secondColor, int $allowedDelta = 1) {
- if ($this->isSameColorComponent($firstColor['red'], $secondColor['red'], $allowedDelta) &&
- $this->isSameColorComponent($firstColor['green'], $secondColor['green'], $allowedDelta) &&
- $this->isSameColorComponent($firstColor['blue'], $secondColor['blue'], $allowedDelta) &&
- $this->isSameColorComponent($firstColor['alpha'], $secondColor['alpha'], $allowedDelta)) {
- return true;
- }
- return false;
- }
- private function isSameColorComponent(int $firstColorComponent, int $secondColorComponent, int $allowedDelta) {
- if ($firstColorComponent >= ($secondColorComponent - $allowedDelta) &&
- $firstColorComponent <= ($secondColorComponent + $allowedDelta)) {
- return true;
- }
- return false;
- }
- }
|