[COMPONENT][Attachment][TESTS] Fix Entity/AttachmentThumbnailTest

This commit is contained in:
Diogo Peralta Cordeiro 2022-03-08 00:21:12 +00:00
parent 5c7b079df5
commit 28453c585f
Signed by: diogo
GPG Key ID: 18D2D35001FBFAB0
14 changed files with 93 additions and 41 deletions

View File

@ -224,8 +224,7 @@ class Attachment extends Entity
$this->setFilename(null); $this->setFilename(null);
$this->setSize(null); $this->setSize(null);
// Important not to null neither width nor height // Important not to null neither width nor height
DB::persist($this); DB::wrapInTransaction(fn () => DB::persist($this));
DB::flush();
} }
} else { } else {
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
@ -340,7 +339,11 @@ class Attachment extends Entity
*/ */
public function getThumbnails() public function getThumbnails()
{ {
return DB::findBy('attachment_thumbnail', ['attachment_id' => $this->id]); return DB::findBy(
AttachmentThumbnail::class,
['attachment_id' => $this->id],
order_by: ['size' => 'ASC', 'mimetype' => 'ASC'],
);
} }
public function getPath() public function getPath()
@ -378,7 +381,7 @@ class Attachment extends Entity
} }
} }
public function getThumbnailUrl(Note|int $note, ?string $size = null) public function getThumbnailUrl(Note|int $note, ?string $size = null): string
{ {
return Router::url('note_attachment_thumbnail', ['note_id' => \is_int($note) ? $note : $note->getId(), 'attachment_id' => $this->getId(), 'size' => $size ?? Common::config('thumbnail', 'default_size')]); return Router::url('note_attachment_thumbnail', ['note_id' => \is_int($note) ? $note : $note->getId(), 'attachment_id' => $this->getId(), 'size' => $size ?? Common::config('thumbnail', 'default_size')]);
} }

View File

@ -30,6 +30,7 @@ use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router; use App\Core\Router\Router;
use App\Entity\Note;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
use App\Util\Exception\NotFoundException; use App\Util\Exception\NotFoundException;
@ -179,7 +180,7 @@ class AttachmentThumbnail extends Entity
if (isset($this->attachment) && !\is_null($this->attachment)) { if (isset($this->attachment) && !\is_null($this->attachment)) {
return $this->attachment; return $this->attachment;
} else { } else {
return $this->attachment = DB::findOneBy('attachment', ['id' => $this->attachment_id]); return $this->attachment = DB::findOneBy(Attachment::class, ['id' => $this->attachment_id]);
} }
} }
@ -253,14 +254,14 @@ class AttachmentThumbnail extends Entity
} }
} }
public function getPath() public function getPath(): string
{ {
return Common::config('thumbnail', 'dir') . \DIRECTORY_SEPARATOR . $this->getFilename(); return Common::config('thumbnail', 'dir') . \DIRECTORY_SEPARATOR . $this->getFilename();
} }
public function getUrl() public function getUrl(Note|int $note): string
{ {
return Router::url('attachment_thumbnail', ['id' => $this->getAttachmentId(), 'size' => self::sizeIntToStr($this->getSize())]); return Router::url('note_attachment_thumbnail', ['note_id' => \is_int($note) ? $note : $note->getId(), 'attachment_id' => $this->getAttachmentId(), 'size' => self::sizeIntToStr($this->getSize())]);
} }
/** /**
@ -277,9 +278,10 @@ class AttachmentThumbnail extends Entity
} }
} }
Cache::delete(self::getCacheKey($this->getAttachmentId(), $this->getSize())); Cache::delete(self::getCacheKey($this->getAttachmentId(), $this->getSize()));
DB::remove($this);
if ($flush) { if ($flush) {
DB::flush(); DB::wrapInTransaction(fn () => DB::remove($this));
} else {
DB::remove($this);
} }
} }

View File

@ -19,12 +19,13 @@ declare(strict_types = 1);
// along with GNU social. If not, see <http://www.gnu.org/licenses/>. // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
// }}} // }}}
namespace App\Tests\Entity; namespace Component\Attachment\tests\Entity;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Core\Event; use App\Core\Event;
use App\Util\Exception\NotStoredLocallyException; use App\Util\Exception\NotStoredLocallyException;
use App\Util\GNUsocialTestCase; use App\Util\GNUsocialTestCase;
use Component\Attachment\Entity\Attachment;
use Component\Attachment\Entity\AttachmentThumbnail; use Component\Attachment\Entity\AttachmentThumbnail;
use Functional as F; use Functional as F;
use Jchook\AssertThrows\AssertThrows; use Jchook\AssertThrows\AssertThrows;
@ -42,9 +43,9 @@ class AttachmentThumbnailTest extends GNUsocialTestCase
$file = new SplFileInfo(INSTALLDIR . '/tests/sample-uploads/attachment-lifecycle-target.jpg'); $file = new SplFileInfo(INSTALLDIR . '/tests/sample-uploads/attachment-lifecycle-target.jpg');
$hash = null; $hash = null;
Event::handle('HashFile', [$file->getPathname(), &$hash]); Event::handle('HashFile', [$file->getPathname(), &$hash]);
$attachment = DB::findOneBy('attachment', ['filehash' => $hash]); $attachment = DB::findOneBy(Attachment::class, ['filehash' => $hash]);
$thumbs = [ $expected = [
AttachmentThumbnail::getOrCreate($attachment, 'small', crop: false), AttachmentThumbnail::getOrCreate($attachment, 'small', crop: false),
AttachmentThumbnail::getOrCreate($attachment, 'medium', crop: false), AttachmentThumbnail::getOrCreate($attachment, 'medium', crop: false),
$thumb = AttachmentThumbnail::getOrCreate($attachment, 'big', crop: false), $thumb = AttachmentThumbnail::getOrCreate($attachment, 'big', crop: false),
@ -54,21 +55,29 @@ class AttachmentThumbnailTest extends GNUsocialTestCase
$thumb->setAttachment(null); $thumb->setAttachment(null);
static::assertSame($attachment, $thumb->getAttachment()); static::assertSame($attachment, $thumb->getAttachment());
$sort = fn ($l, $r) => [$l->getWidth(), $l->getHeight()] <=> [$r->getWidth(), $r->getHeight()]; $actual = $attachment->getThumbnails();
$at_thumbs = F\sort($attachment->getThumbnails(), $sort); static::assertSame(\count($expected), \count($actual));
static::assertSame($thumbs, $at_thumbs); foreach ($expected as $e) {
array_pop($thumbs); $a = array_shift($actual);
$thumb->delete(flush: true); static::assertObjectEquals($e, $a);
$at_thumbs = F\sort($attachment->getThumbnails(), $sort); }
static::assertSame($thumbs, $at_thumbs);
array_pop($expected);
$thumb->delete();
$actual = $attachment->getThumbnails();
static::assertSame(\count($expected), \count($actual));
foreach ($expected as $e) {
$a = array_shift($actual);
static::assertObjectEquals($e, $a);
}
$attachment->deleteStorage(); $attachment->deleteStorage();
foreach (array_reverse($thumbs) as $t) { foreach (array_reverse($attachment->getThumbnails()) as $t) {
// Since we still have thumbnails, those will be used as the new thumbnail, even though we don't have the original // Since we still have thumbnails, those will be used as the new thumbnail, even though we don't have the original
$new = AttachmentThumbnail::getOrCreate($attachment, 'big', crop: false); $new = AttachmentThumbnail::getOrCreate($attachment, 'big', crop: false);
static::assertSame([$t->getFilename(), $t->getSize()], [$new->getFilename(), $new->getSize()]); static::assertSame([$t->getFilename(), $t->getSize()], [$new->getFilename(), $new->getSize()]);
$t->delete(flush: true); $t->delete();
} }
// Since the backed storage was deleted and we don't have any more previous thumnbs, we can't generate another thumbnail // Since the backed storage was deleted and we don't have any more previous thumnbs, we can't generate another thumbnail
@ -159,10 +168,10 @@ class AttachmentThumbnailTest extends GNUsocialTestCase
public function testGetUrl() public function testGetUrl()
{ {
parent::bootKernel(); parent::bootKernel();
$attachment = DB::findBy('attachment', ['mimetype' => 'image/png'], limit: 1)[0]; $attachment = DB::findBy(Attachment::class, ['mimetype' => 'image/png'], limit: 1)[0];
$thumb = AttachmentThumbnail::getOrCreate($attachment, 'big', crop: false); $thumb = AttachmentThumbnail::getOrCreate($attachment, 'big', crop: false);
$id = $attachment->getId(); $id = $attachment->getId();
$url = "/attachment/{$id}/thumbnail/big"; $expected = "/object/note/42/attachment/{$id}/thumbnail/big";
static::assertSame($url, $thumb->getUrl()); static::assertSame($expected, $thumb->getUrl(note: 42));
} }
} }

View File

@ -52,7 +52,7 @@ class AttachmentCollection extends Entity
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
// }}} Autocode // }}} Autocode
public static function schemaDef() public static function schemaDef(): array
{ {
return [ return [
'name' => 'attachment_collection', 'name' => 'attachment_collection',

View File

@ -63,7 +63,7 @@ class AttachmentCollectionEntry extends Entity
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
// }}} Autocode // }}} Autocode
public static function schemaDef() public static function schemaDef(): array
{ {
return [ return [
'name' => 'attachment_collection_entry', 'name' => 'attachment_collection_entry',

View File

@ -194,7 +194,7 @@ class AttachmentEmbed extends Entity
return $attr; return $attr;
} }
public static function schemaDef() public static function schemaDef(): array
{ {
return [ return [
'name' => 'attachment_embed', 'name' => 'attachment_embed',

View File

@ -142,7 +142,7 @@ class NoteFavourite extends Entity
return array_unique($target_ids); return array_unique($target_ids);
} }
public static function schemaDef() public static function schemaDef(): array
{ {
return [ return [
'name' => 'note_favourite', 'name' => 'note_favourite',

View File

@ -42,7 +42,7 @@ class PinnedNotes extends Entity
return $this; return $this;
} }
public static function schemaDef() public static function schemaDef(): array
{ {
return [ return [
'name' => 'pinned_notes', 'name' => 'pinned_notes',

View File

@ -51,7 +51,7 @@ class Wallet extends Entity
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
// }}} Autocode // }}} Autocode
public static function schemaDef() public static function schemaDef(): array
{ {
return [ return [
'name' => 'webmonetizationWallet', 'name' => 'webmonetizationWallet',

View File

@ -90,7 +90,7 @@ class WebMonetization extends Entity
return $target_ids; return $target_ids;
} }
public static function schemaDef() public static function schemaDef(): array
{ {
return [ return [
'name' => 'webmonetization', 'name' => 'webmonetization',

View File

@ -28,6 +28,7 @@ use App\Util\Exception\NotFoundException;
use App\Util\Formatting; use App\Util\Formatting;
use BadMethodCallException; use BadMethodCallException;
use DateTime; use DateTime;
use DateTimeInterface;
use Exception; use Exception;
use InvalidArgumentException; use InvalidArgumentException;
@ -48,6 +49,8 @@ abstract class Entity
throw new BadMethodCallException('Non existent method ' . static::class . "::{$name} called with arguments: " . print_r($arguments, true)); throw new BadMethodCallException('Non existent method ' . static::class . "::{$name} called with arguments: " . print_r($arguments, true));
} }
abstract public static function schemaDef(): array;
/** /**
* Create an instance of the called class or fill in the * Create an instance of the called class or fill in the
* properties of $obj with the associative array $args. Doesn't * properties of $obj with the associative array $args. Doesn't
@ -145,6 +148,32 @@ abstract class Entity
} }
} }
/**
* Tests that this object is equal to another one based on a custom object comparison
*
* @param self $other the value to test
*
* @return bool true if equals, false otherwise
*/
public function equals(self $other): bool
{
foreach (array_keys($this::schemaDef()['fields']) as $attribute) {
$getter = 'get' . Formatting::snakeCaseToPascalCase($attribute);
$current = $this->{$getter}();
$target = $other->{$getter}();
if ($current instanceof DateTimeInterface) {
if ($current->getTimestamp() !== $target->getTimestamp()) {
return false;
}
} else {
if ($current !== $target) {
return false;
}
}
}
return true;
}
/** /**
* Who should be notified about this object? * Who should be notified about this object?
* *

View File

@ -332,7 +332,7 @@ class Actor extends Entity
{ {
return Cache::getList( return Cache::getList(
self::cacheKeys($this->getId())['self-tags'], self::cacheKeys($this->getId())['self-tags'],
fn() => DB::findBy(ActorTag::class, ['tagger' => $this->getId(), 'tagged' => $this->getId()], order_by: ['modified' => 'DESC']), fn() => DB::findBy(ActorTag::class, ['tagger' => $this->getId(), 'tagged' => $this->getId()], order_by: ['modified' => 'DESC', 'tag' => 'ASC']),
); );
} }

View File

@ -153,6 +153,11 @@ abstract class Formatting
return implode('', F\map(preg_split('/[\b_]/', $str), F\ary('ucfirst', 1))); return implode('', F\map(preg_split('/[\b_]/', $str), F\ary('ucfirst', 1)));
} }
public static function snakeCaseToPascalCase(string $str): string
{
return ucfirst(self::snakeCaseToCamelCase($str));
}
/** /**
* Indent $in, a string or array, $level levels * Indent $in, a string or array, $level levels
* *

View File

@ -56,10 +56,9 @@ class ActorTest extends GNUsocialTestCase
])); ]));
DB::flush(); DB::flush();
Cache::delete(Actor::cacheKeys($actor->getId())['self-tags']); Cache::delete(Actor::cacheKeys($actor->getId())['self-tags']);
static::assertSame( $actual = $actor->getSelfTags();
expected: [$actor_tag_foo], static::assertCount(1, $actual);
actual: $actor->getSelfTags(), static::assertObjectEquals(expected: $actor_tag_foo, actual: $actual[0]);
);
// Add a second self-tag 'foo' // Add a second self-tag 'foo'
$tag = CompTag::sanitize('bar'); $tag = CompTag::sanitize('bar');
DB::persist($actor_tag_bar = ActorTag::create([ DB::persist($actor_tag_bar = ActorTag::create([
@ -69,9 +68,14 @@ class ActorTest extends GNUsocialTestCase
])); ]));
DB::flush(); DB::flush();
Cache::delete(Actor::cacheKeys($actor->getId())['self-tags']); Cache::delete(Actor::cacheKeys($actor->getId())['self-tags']);
static::assertSame( $actual = $actor->getSelfTags();
expected: [$actor_tag_bar, $actor_tag_foo], static::assertCount(2, $actual);
actual: $actor->getSelfTags(), foreach ([$actor_tag_bar, $actor_tag_foo] as $expected) {
); $a = array_shift($actual);
if ($expected->equals($a) !== true) {
dd($expected, $a);
}
static::assertObjectEquals($expected, $a);
}
} }
} }