From 4f0609dd70033ee0ca4a47e1d085b58067693a38 Mon Sep 17 00:00:00 2001 From: David Dreschner Date: Tue, 27 Oct 2026 09:50:35 +0100 Subject: [PATCH] test(avatar): Check the guest avatar independent of the font renderer GuestAvatarTest::testGet() compared the generated PNG byte for byte with a stored image. The anti-aliasing of the letter depends on the GD and FreeType versions: the stored image matches Ubuntu 24.04 (libgd3 2.3.3-9ubuntu5, FreeType 2.13.2), while Ubuntu 26.04 (libgd3 2.3.3-13ubuntu2, FreeType 2.14.2) and the bundled GD of the official PHP images render a few edge pixels differently. The nodb jobs therefore fail whenever they run on a runner with the newer image. Check the PNG format, the image size and the guest background color in the light and the dark theme instead, and count the pixels in the letter color: the anti-aliased edges differ between renderers, the strokes of the letter don't. Also remove the SVG fixture, which has been unused since guest avatars switched to PNG. Assisted-by: ClaudeCode:claude-opus-5-5 Signed-off-by: David Dreschner --- tests/data/REUSE.toml | 2 +- tests/data/guest_avatar_einstein_32.png | Bin 272 -> 0 bytes tests/data/guest_avatar_einstein_32.svg | 5 --- tests/lib/Avatar/GuestAvatarTest.php | 43 +++++++++++++++++++----- 4 files changed, 35 insertions(+), 15 deletions(-) delete mode 100644 tests/data/guest_avatar_einstein_32.png delete mode 100644 tests/data/guest_avatar_einstein_32.svg diff --git a/tests/data/REUSE.toml b/tests/data/REUSE.toml index 79a71e8608502..a2111a539e8d3 100644 --- a/tests/data/REUSE.toml +++ b/tests/data/REUSE.toml @@ -100,7 +100,7 @@ SPDX-FileCopyrightText = "2018 Nextcloud GmbH and Nextcloud contributors" SPDX-License-Identifier = "AGPL-3.0-or-later" [[annotations]] -path = ["integritycheck/mimetypeListModified/core/js/mimetypelist.js", "integritycheck/mimetypeListModified/core/signature.json", "guest_avatar_einstein_32.png", "guest_avatar_einstein_32.svg", "test.pdf"] +path = ["integritycheck/mimetypeListModified/core/js/mimetypelist.js", "integritycheck/mimetypeListModified/core/signature.json", "test.pdf"] precedence = "aggregate" SPDX-FileCopyrightText = "2019 Nextcloud GmbH and Nextcloud contributors" SPDX-License-Identifier = "AGPL-3.0-or-later" diff --git a/tests/data/guest_avatar_einstein_32.png b/tests/data/guest_avatar_einstein_32.png deleted file mode 100644 index d03f0509bac3b028f15f29292a57ec8447c68966..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={WI14-?iy0XBj({-ZRBb+Kpx_}- z7sn8f&g7b(KdqT{8HIg)<+mnWVOqr?rgXLT@7L!)pUY=7Dc#9olF7NU@xhVD+e?41 zTf~_*OY``P)4|7?I5J8vP85I8R@`dIX)!;AJLSg?5!RiYtDTve)g~!E_`bh>|Nno@ z#gQ{PclVoc2bs-re5S|0b%OANMax)Q!&U|DnNzS%g5TOvcS&S|g5nCLGtQHyO$-ik zIMAt{FJJeA>$w*9XAKU46Jkpu4gOw - - - E - diff --git a/tests/lib/Avatar/GuestAvatarTest.php b/tests/lib/Avatar/GuestAvatarTest.php index eed41e8221e82..cf91454eaaf4e 100644 --- a/tests/lib/Avatar/GuestAvatarTest.php +++ b/tests/lib/Avatar/GuestAvatarTest.php @@ -12,6 +12,7 @@ use OC\Avatar\GuestAvatar; use OCP\Files\SimpleFS\InMemoryFile; use OCP\IConfig; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\Log\LoggerInterface; use Test\TestCase; @@ -37,19 +38,43 @@ public function setupGuestAvatar(): void { $this->guestAvatar = new GuestAvatar('einstein', $config, $logger); } + public static function themeProvider(): array { + return [ + 'light theme' => ['darkTheme' => false, 'backgroundColor' => 0xe9f3f7], + 'dark theme' => ['darkTheme' => true, 'backgroundColor' => 0x030e12], + ]; + } + /** - * Asserts that testGet() returns the expected avatar. + * Asserts that GuestAvatar::getFile() returns the expected avatar. * - * For the test a static name "einstein" is used and - * the generated image is compared with an expected one. + * For the test a static name "einstein" is used. */ - public function testGet(): void { - $avatar = $this->guestAvatar->getFile(32); + #[DataProvider('themeProvider')] + public function testGet(bool $darkTheme, int $backgroundColor): void { + $size = 32; + $avatar = $this->guestAvatar->getFile($size, $darkTheme); self::assertInstanceOf(InMemoryFile::class, $avatar); - $expectedFile = file_get_contents( - __DIR__ . '/../../data/guest_avatar_einstein_32.png' - ); - self::assertEquals(trim($expectedFile), trim($avatar->getContent())); + $content = $avatar->getContent(); + self::assertStringStartsWith("\x89PNG\r\n\x1a\n", $content, 'The avatar is not a PNG'); + + $image = imagecreatefromstring($content); + self::assertInstanceOf(\GdImage::class, $image); + self::assertSame($size, imagesx($image)); + self::assertSame($size, imagesy($image)); + self::assertSame($backgroundColor, imagecolorat($image, 0, 0), 'The background is not the guest color'); + + // The anti-aliased edges depend on the GD and FreeType versions, the strokes of the letter don't + $letterPixels = 0; + for ($y = 0; $y < $size; $y++) { + for ($x = 0; $x < $size; $x++) { + if (imagecolorat($image, $x, $y) === 0x248eb5) { + $letterPixels++; + } + } + } + // A Noto Sans "E" at 32 px has 27 fully covered pixels + self::assertSame(27, $letterPixels, 'The avatar does not show a Noto Sans "E" in the guest color'); } /**