, * Michael Stilkerich * * This file is part of RCMCardDAV. * * RCMCardDAV is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * RCMCardDAV 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with RCMCardDAV. If not, see . */ declare(strict_types=1); namespace MStilkerich\Tests\RCMCardDAV\Unit; use PHasher; use PHPUnit\Framework\TestCase; use Sabre\VObject\Component\VCard; use MStilkerich\RCMCardDAV\DataConversion; use MStilkerich\RCMCardDAV\DelayedPhotoLoader; use MStilkerich\Tests\RCMCardDAV\TestInfrastructure; /** * @psalm-import-type SaveData from DataConversion */ class Utils { /** * Can be used as emulation of WebDavResource::downloadResource in stubs. * @return array{body: string} */ public static function downloadResource(string $uri): array { if (preg_match(',^http://localhost/(.+),', $uri, $matches) && isset($matches[1])) { $filename = "tests/Unit/data/srv/$matches[1]"; TestCase::assertFileIsReadable($filename); return [ 'body' => file_get_contents($filename) ]; } throw new \Exception("URI $uri not known to stub"); } /** * @return SaveData */ public static function readSaveDataFromJson(string $jsonFile): array { /** @var SaveData Assume our test samples are valid */ $phpArray = TestInfrastructure::readJsonArray($jsonFile); // special handling for photo as we cannot encode binary data in json if (isset($phpArray['photo'])) { TestCase::assertIsString($phpArray['photo']); $photoFile = $phpArray['photo']; if (!empty($photoFile) && $photoFile[0] == '@') { $photoFile = substr($photoFile, 1); $phpArray['photo'] = TestInfrastructure::readFileRelative($photoFile, $jsonFile); } } /** @psalm-var SaveData $phpArray XXX temporary workaround because of vimeo/psalm#8980 */ return $phpArray; } /** * Compares two roundcube save data arrays with special handling of photo. */ public static function compareSaveData(array $saveDataExp, array $saveDataRc, string $msg): void { TestCase::assertSame(isset($saveDataExp['photo']), isset($saveDataRc['photo']), $msg); if (isset($saveDataExp['photo'])) { TestCase::assertIsString($saveDataExp["photo"]); // Check that save data contains a pristine photo loader TestCase::assertInstanceOf(DelayedPhotoLoader::class, $saveDataRc["photo"]); TestCase::assertTrue($saveDataRc["photo"]->pristine(), "Photo loader not pristine"); self::comparePhoto($saveDataExp['photo'], (string) $saveDataRc['photo']); unset($saveDataExp['photo']); unset($saveDataRc['photo']); } if (isset($saveDataRc["vcard"])) { TestCase::assertIsString($saveDataRc["vcard"]); unset($saveDataRc["vcard"]); } if (isset($saveDataRc["_carddav_vcard"])) { TestCase::assertInstanceOf(VCard::class, $saveDataRc["_carddav_vcard"]); unset($saveDataRc["_carddav_vcard"]); } ksort($saveDataExp); ksort($saveDataRc); TestCase::assertSame($saveDataExp, $saveDataRc, $msg); } /** * Compares two photos given as binary strings. * * @param string $pExpStr The expected photo data * @param string $pRcStr The photo data produced by the test object */ public static function comparePhoto(string $pExpStr, string $pRcStr): void { TestCase::assertTrue(function_exists('gd_info'), "php-gd required"); // shortcut that also covers URI - if identical strings, save the comparison if ( empty($pExpStr) || empty($pRcStr) || strpos($pExpStr, "http") !== false || strpos($pExpStr, "data:") !== false ) { TestCase::assertSame($pExpStr, $pRcStr, "PHOTO comparison on URI value failed"); return; } // dimensions must be the same /** @psalm-var false|array{int,int,int} */ $pExp = getimagesizefromstring($pExpStr); TestCase::assertNotFalse($pExp, "Exp Image could not be identified"); /** @psalm-var false|array{int,int,int} */ $pRc = getimagesizefromstring($pRcStr); TestCase::assertNotFalse($pRc, "RC Image could not be identified"); TestCase::assertSame($pExp[0], $pRc[0], "X dimension of PHOTO differs"); TestCase::assertSame($pExp[1], $pRc[1], "Y dimension of PHOTO differs"); TestCase::assertSame($pExp[2], $pRc[2], "Image type of PHOTO differs"); // store to temporary files for comparison $expFile = tempnam("testreports", "imgcomp_") . image_type_to_extension($pExp[2]); $rcFile = tempnam("testreports", "imgcomp_") . image_type_to_extension($pRc[2]); TestCase::assertNotFalse(file_put_contents($expFile, $pExpStr), "Cannot write $expFile"); TestCase::assertNotFalse(file_put_contents($rcFile, $pRcStr), "Cannot write $rcFile"); // compare /** @psalm-var PHasher $phasher */ $phasher = PHasher::Instance(); // similarity is returned as percentage $compResult = intval($phasher->Compare($expFile, $rcFile)); TestCase::assertSame(100, $compResult, "Image comparison returned too little similarity $compResult%"); } /** * Delete temporary files from image comparison */ public static function cleanupTempImages(): void { $tmpimgs = glob("testreports/imgcomp_*"); if (is_array($tmpimgs) && (count($tmpimgs) > 0)) { foreach ($tmpimgs as $tmpimg) { unlink($tmpimg); } } } } // vim: ts=4:sw=4:expandtab:fenc=utf8:ff=unix:tw=120:ft=php