From f575f6c94cb78847aa849829530bdaafb2021af3 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 1 Nov 2024 21:45:45 +0000 Subject: [PATCH 1/9] require php-mock/php-mock-phpunit for mocking php builtin functions --- composer.json | 7 +- composer.lock | 209 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 212 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 21df229eaa..0280409716 100644 --- a/composer.json +++ b/composer.json @@ -148,10 +148,11 @@ ] }, "require-dev": { - "mockery/mockery": "^1.3", + "dms/phpunit-arraysubset-asserts": "^0.3.1", "mikey179/vfsstream": "^1.6", - "phpunit/phpunit": "^9", - "dms/phpunit-arraysubset-asserts": "^0.3.1" + "mockery/mockery": "^1.3", + "php-mock/php-mock-phpunit": "^2.10", + "phpunit/phpunit": "^9" }, "scripts": { "test": "phpunit", diff --git a/composer.lock b/composer.lock index 53a632fcc5..fae42ffe16 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4385276f5e7c27e2ceb7b16531dbc33a", + "content-hash": "d51158b9593011921144e90af146a86a", "packages": [ { "name": "asika/simple-console", @@ -4625,6 +4625,213 @@ "description": "Library for handling version information and constraints", "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "php-mock/php-mock", + "version": "2.5.0", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock.git", + "reference": "fff1a621ebe54100fa3bd852e7be57773a0c0127" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock/zipball/fff1a621ebe54100fa3bd852e7be57773a0c0127", + "reference": "fff1a621ebe54100fa3bd852e7be57773a0c0127", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0", + "phpunit/php-text-template": "^1 || ^2 || ^3 || ^4" + }, + "replace": { + "malkusch/php-mock": "*" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.0 || ^9.0 || ^10.0 || ^11.0", + "squizlabs/php_codesniffer": "^3.8" + }, + "suggest": { + "php-mock/php-mock-phpunit": "Allows integration into PHPUnit testcase with the trait PHPMock." + }, + "type": "library", + "autoload": { + "files": [ + "autoload.php" + ], + "psr-4": { + "phpmock\\": [ + "classes/", + "tests/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "PHP-Mock can mock built-in PHP functions (e.g. time()). PHP-Mock relies on PHP's namespace fallback policy. No further extension is needed.", + "homepage": "https://github.com/php-mock/php-mock", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "issues": "https://github.com/php-mock/php-mock/issues", + "source": "https://github.com/php-mock/php-mock/tree/2.5.0" + }, + "funding": [ + { + "url": "https://github.com/michalbundyra", + "type": "github" + } + ], + "time": "2024-02-10T21:07:01+00:00" + }, + { + "name": "php-mock/php-mock-integration", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock-integration.git", + "reference": "ec6a00a8129d50ed0f07907c91e3274ca4ade877" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock-integration/zipball/ec6a00a8129d50ed0f07907c91e3274ca4ade877", + "reference": "ec6a00a8129d50ed0f07907c91e3274ca4ade877", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "php-mock/php-mock": "^2.5", + "phpunit/php-text-template": "^1 || ^2 || ^3 || ^4" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.27 || ^6 || ^7 || ^8 || ^9 || ^10 || ^11" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpmock\\integration\\": "classes/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "Integration package for PHP-Mock", + "homepage": "https://github.com/php-mock/php-mock-integration", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "stub", + "test", + "test double" + ], + "support": { + "issues": "https://github.com/php-mock/php-mock-integration/issues", + "source": "https://github.com/php-mock/php-mock-integration/tree/2.3.0" + }, + "funding": [ + { + "url": "https://github.com/michalbundyra", + "type": "github" + } + ], + "time": "2024-02-10T21:37:25+00:00" + }, + { + "name": "php-mock/php-mock-phpunit", + "version": "2.10.0", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock-phpunit.git", + "reference": "e1f7e795990b00937376e345883ea68ca3bda7e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock-phpunit/zipball/e1f7e795990b00937376e345883ea68ca3bda7e0", + "reference": "e1f7e795990b00937376e345883ea68ca3bda7e0", + "shasum": "" + }, + "require": { + "php": ">=7", + "php-mock/php-mock-integration": "^2.3", + "phpunit/phpunit": "^6 || ^7 || ^8 || ^9 || ^10.0.17 || ^11" + }, + "require-dev": { + "mockery/mockery": "^1.3.6" + }, + "type": "library", + "autoload": { + "files": [ + "autoload.php" + ], + "psr-4": { + "phpmock\\phpunit\\": "classes/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "Mock built-in PHP functions (e.g. time()) with PHPUnit. This package relies on PHP's namespace fallback policy. No further extension is needed.", + "homepage": "https://github.com/php-mock/php-mock-phpunit", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "phpunit", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "issues": "https://github.com/php-mock/php-mock-phpunit/issues", + "source": "https://github.com/php-mock/php-mock-phpunit/tree/2.10.0" + }, + "funding": [ + { + "url": "https://github.com/michalbundyra", + "type": "github" + } + ], + "time": "2024-02-11T07:24:16+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.31", From 7de3b16dc364a33688fd07bacd281f6136e56ab4 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 1 Nov 2024 21:46:09 +0000 Subject: [PATCH 2/9] Fix namespace for CryptoTest --- tests/src/Util/CryptoTest.php | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/tests/src/Util/CryptoTest.php b/tests/src/Util/CryptoTest.php index 7fd5befce5..eeb99b1bb9 100644 --- a/tests/src/Util/CryptoTest.php +++ b/tests/src/Util/CryptoTest.php @@ -6,14 +6,16 @@ // SPDX-License-Identifier: AGPL-3.0-or-later /// @todo Use right namespace - needs alternative way of mocking random_int() -namespace Friendica\Util; +namespace Friendica\Test\src\Util; -use phpseclib\Crypt\RSA; -use phpseclib\Math\BigInteger; +use Friendica\Util\Crypto; +use phpmock\phpunit\PHPMock; use PHPUnit\Framework\TestCase; class CryptoTest extends TestCase { + use PHPMock; + public static function tearDownAfterClass(): void { // Reset mocking @@ -39,6 +41,14 @@ class CryptoTest extends TestCase public function testRandomDigitsRandomInt() { + $random_int = $this->getFunctionMock(__NAMESPACE__, 'random_int'); + $random_int->expects($this->any())->willReturnCallback(function($min, $max) { + global $phpMock; + if (isset($phpMock['random_int'])) { + return call_user_func_array($phpMock['random_int'], func_get_args()); + } + }); + self::assertRandomInt(0, 9); $test = Crypto::randomDigits(1); @@ -78,16 +88,3 @@ class CryptoTest extends TestCase ]; } } - -/** - * A workaround to replace the PHP native random_int() (>= 7.0) with a mocked function - * - * @return int - */ -function random_int($min, $max) -{ - global $phpMock; - if (isset($phpMock['random_int'])) { - return call_user_func_array($phpMock['random_int'], func_get_args()); - } -} From 5ecee2b9f7e1a84d5819d23978d322775b80a97d Mon Sep 17 00:00:00 2001 From: Art4 Date: Sat, 2 Nov 2024 17:43:43 +0100 Subject: [PATCH 3/9] Fix namespace in IntallerTest, mock function_exists() with PHPMock --- tests/src/Core/InstallerTest.php | 356 ++++++++++++++++++++++--------- tests/src/Util/CryptoTest.php | 3 +- 2 files changed, 253 insertions(+), 106 deletions(-) diff --git a/tests/src/Core/InstallerTest.php b/tests/src/Core/InstallerTest.php index cd478a7204..f07ad602c5 100644 --- a/tests/src/Core/InstallerTest.php +++ b/tests/src/Core/InstallerTest.php @@ -5,12 +5,13 @@ // // SPDX-License-Identifier: AGPL-3.0-or-later -/// @todo this is in the same namespace as Install for mocking 'function_exists' -namespace Friendica\Core; +namespace Friendica\Test\src\Core; use Dice\Dice; use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; use Friendica\Core\Config\ValueObject\Cache; +use Friendica\Core\Installer; +use Friendica\Core\L10n; use Friendica\DI; use Friendica\Network\HTTPClient\Capability\ICanHandleHttpResponses; use Friendica\Network\HTTPClient\Capability\ICanSendHttpRequests; @@ -18,18 +19,20 @@ use Friendica\Test\MockedTest; use Friendica\Test\Util\VFSTrait; use Mockery; use Mockery\MockInterface; +use phpmock\phpunit\PHPMock; class InstallerTest extends MockedTest { use VFSTrait; use ArraySubsetAsserts; + use PHPMock; /** * @var L10n|MockInterface */ private $l10nMock; /** - * @var Dice|MockInterface + * @var Dice&MockInterface */ private $dice; @@ -41,7 +44,7 @@ class InstallerTest extends MockedTest $this->l10nMock = Mockery::mock(L10n::class); - /** @var Dice|MockInterface $dice */ + /** @var Dice&MockInterface $dice */ $this->dice = Mockery::mock(Dice::class)->makePartial(); $this->dice = $this->dice->addRules(include __DIR__ . '/../../../static/dependencies.config.php'); @@ -115,24 +118,6 @@ class InstallerTest extends MockedTest self::assertArraySubset($subSet, $assertionArray, false, "expected subset: " . PHP_EOL . print_r($subSet, true) . PHP_EOL . "current subset: " . print_r($assertionArray, true)); } - /** - * Replaces function_exists results with given mocks - * - * @param array $functions a list from function names and their result - */ - private function setFunctions(array $functions) - { - global $phpMock; - $phpMock['function_exists'] = function($function) use ($functions) { - foreach ($functions as $name => $value) { - if ($function == $name) { - return $value; - } - } - return '__phpunit_continue__'; - }; - } - /** * Replaces class_exist results with given mocks * @@ -151,29 +136,50 @@ class InstallerTest extends MockedTest }; } + public static function getCheckKeysData(): array + { + return [ + 'openssl_pkey_new does not exist' => ['openssl_pkey_new', false], + 'openssl_pkey_new does exists' => ['openssl_pkey_new', true], + ]; + } + /** * @small + * + * @dataProvider getCheckKeysData */ - public function testCheckKeys() + public function testCheckKeys($function, $expected) { + $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists->expects($this->any())->willReturnCallback(function($function_name) use ($function, $expected) { + if ($function_name === $function) { + return $expected; + } + return call_user_func_array('\function_exists', func_get_args()); + }); + $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; }); - $this->setFunctions(['openssl_pkey_new' => false]); $install = new Installer(); - self::assertFalse($install->checkKeys()); - - $this->setFunctions(['openssl_pkey_new' => true]); - $install = new Installer(); - self::assertTrue($install->checkKeys()); + self::assertSame($expected, $install->checkKeys()); } /** * @small */ - public function testCheckFunctions() + public function testCheckFunctionsWithoutIntlChar() { + $class_exists = $this->getFunctionMock(__NAMESPACE__, 'class_exists'); + $class_exists->expects($this->any())->willReturnCallback(function($class_name) { + if ($class_name === 'IntlChar') { + return false; + } + return call_user_func_array('\class_exists', func_get_args()); + }); + $this->mockFunctionL10TCalls(); - $this->setClasses(['IntlChar' => false]); + $install = new Installer(); self::assertFalse($install->checkFunctions()); self::assertCheckExist(2, @@ -182,9 +188,23 @@ class InstallerTest extends MockedTest false, true, $install->getChecks()); + } + + /** + * @small + */ + public function testCheckFunctionsWithoutCurlInit() + { + $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists->expects($this->any())->willReturnCallback(function($function_name) { + if ($function_name === 'curl_init') { + return false; + } + return call_user_func_array('\function_exists', func_get_args()); + }); + + $this->mockFunctionL10TCalls(true); - $this->mockFunctionL10TCalls(); - $this->setFunctions(['curl_init' => false, 'imagecreatefromjpeg' => true]); $install = new Installer(); self::assertFalse($install->checkFunctions()); self::assertCheckExist(4, @@ -193,9 +213,23 @@ class InstallerTest extends MockedTest false, true, $install->getChecks()); + } + + /** + * @small + */ + public function testCheckFunctionsWithoutImagecreateformjpeg() + { + $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists->expects($this->any())->willReturnCallback(function($function_name) { + if ($function_name === 'imagecreatefromjpeg') { + return false; + } + return call_user_func_array('\function_exists', func_get_args()); + }); + + $this->mockFunctionL10TCalls(true); - $this->mockFunctionL10TCalls(); - $this->setFunctions(['imagecreatefromjpeg' => false]); $install = new Installer(); self::assertFalse($install->checkFunctions()); self::assertCheckExist(5, @@ -204,9 +238,23 @@ class InstallerTest extends MockedTest false, true, $install->getChecks()); + } + + /** + * @small + */ + public function testCheckFunctionsWithoutOpensslpublicencrypt() + { + $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists->expects($this->any())->willReturnCallback(function($function_name) { + if ($function_name === 'openssl_public_encrypt') { + return false; + } + return call_user_func_array('\function_exists', func_get_args()); + }); + + $this->mockFunctionL10TCalls(true); - $this->mockFunctionL10TCalls(); - $this->setFunctions(['openssl_public_encrypt' => false]); $install = new Installer(); self::assertFalse($install->checkFunctions()); self::assertCheckExist(6, @@ -215,9 +263,23 @@ class InstallerTest extends MockedTest false, true, $install->getChecks()); + } + + /** + * @small + */ + public function testCheckFunctionsWithoutMbStrlen() + { + $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists->expects($this->any())->willReturnCallback(function($function_name) { + if ($function_name === 'mb_strlen') { + return false; + } + return call_user_func_array('\function_exists', func_get_args()); + }); + + $this->mockFunctionL10TCalls(true); - $this->mockFunctionL10TCalls(); - $this->setFunctions(['mb_strlen' => false]); $install = new Installer(); self::assertFalse($install->checkFunctions()); self::assertCheckExist(7, @@ -226,9 +288,23 @@ class InstallerTest extends MockedTest false, true, $install->getChecks()); + } + + /** + * @small + */ + public function testCheckFunctionsWithoutIconvStrlen() + { + $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists->expects($this->any())->willReturnCallback(function($function_name) { + if ($function_name === 'iconv_strlen') { + return false; + } + return call_user_func_array('\function_exists', func_get_args()); + }); + + $this->mockFunctionL10TCalls(true); - $this->mockFunctionL10TCalls(); - $this->setFunctions(['iconv_strlen' => false]); $install = new Installer(); self::assertFalse($install->checkFunctions()); self::assertCheckExist(8, @@ -237,9 +313,23 @@ class InstallerTest extends MockedTest false, true, $install->getChecks()); + } + + /** + * @small + */ + public function testCheckFunctionsWithoutPosixkill() + { + $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists->expects($this->any())->willReturnCallback(function($function_name) { + if ($function_name === 'posix_kill') { + return false; + } + return call_user_func_array('\function_exists', func_get_args()); + }); + + $this->mockFunctionL10TCalls(true); - $this->mockFunctionL10TCalls(); - $this->setFunctions(['posix_kill' => false]); $install = new Installer(); self::assertFalse($install->checkFunctions()); self::assertCheckExist(9, @@ -248,9 +338,23 @@ class InstallerTest extends MockedTest false, true, $install->getChecks()); + } + + /** + * @small + */ + public function testCheckFunctionsWithoutProcOpen() + { + $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists->expects($this->any())->willReturnCallback(function($function_name) { + if ($function_name === 'proc_open') { + return false; + } + return call_user_func_array('\function_exists', func_get_args()); + }); + + $this->mockFunctionL10TCalls(true); - $this->mockFunctionL10TCalls(); - $this->setFunctions(['proc_open' => false]); $install = new Installer(); self::assertFalse($install->checkFunctions()); self::assertCheckExist(10, @@ -259,8 +363,23 @@ class InstallerTest extends MockedTest false, true, $install->getChecks()); - $this->mockFunctionL10TCalls(); - $this->setFunctions(['json_encode' => false]); + } + + /** + * @small + */ + public function testCheckFunctionsWithoutJsonEncode() + { + $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists->expects($this->any())->willReturnCallback(function($function_name) { + if ($function_name === 'json_encode') { + return false; + } + return call_user_func_array('\function_exists', func_get_args()); + }); + + $this->mockFunctionL10TCalls(true); + $install = new Installer(); self::assertFalse($install->checkFunctions()); self::assertCheckExist(11, @@ -269,9 +388,23 @@ class InstallerTest extends MockedTest false, true, $install->getChecks()); + } + + /** + * @small + */ + public function testCheckFunctionsWithoutFinfoOpen() + { + $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists->expects($this->any())->willReturnCallback(function($function_name) { + if ($function_name === 'finfo_open') { + return false; + } + return call_user_func_array('\function_exists', func_get_args()); + }); + + $this->mockFunctionL10TCalls(true); - $this->mockFunctionL10TCalls(); - $this->setFunctions(['finfo_open' => false]); $install = new Installer(); self::assertFalse($install->checkFunctions()); self::assertCheckExist(12, @@ -280,9 +413,23 @@ class InstallerTest extends MockedTest false, true, $install->getChecks()); + } + + /** + * @small + */ + public function testCheckFunctionsWithoutGmpStrval() + { + $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists->expects($this->any())->willReturnCallback(function($function_name) { + if ($function_name === 'gmp_strval') { + return false; + } + return call_user_func_array('\function_exists', func_get_args()); + }); + + $this->mockFunctionL10TCalls(true); - $this->mockFunctionL10TCalls(); - $this->setFunctions(['gmp_strval' => false]); $install = new Installer(); self::assertFalse($install->checkFunctions()); self::assertCheckExist(13, @@ -291,20 +438,36 @@ class InstallerTest extends MockedTest false, true, $install->getChecks()); + } + + /** + * @small + */ + public function testCheckFunctions() + { + $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists->expects($this->any())->willReturnCallback(function($function_name) { + if (in_array( + $function_name, + [ + 'curl_init', + 'imagecreatefromjpeg', + 'openssl_public_encrypt', + 'mb_strlen', + 'iconv_strlen', + 'posix_kill', + 'json_encode', + 'finfo_open', + 'gmp_strval', + ] + )) { + return true; + } + return call_user_func_array('\function_exists', func_get_args()); + }); $this->mockFunctionL10TCalls(true); - $this->setFunctions([ - 'curl_init' => true, - 'imagecreatefromjpeg' => true, - 'openssl_public_encrypt' => true, - 'mb_strlen' => true, - 'iconv_strlen' => true, - 'posix_kill' => true, - 'json_encode' => true, - 'finfo_open' => true, - 'gmp_strval' => true, - ]); - $this->setClasses(['IntlChar' => true]); + $install = new Installer(); self::assertTrue($install->checkFunctions()); } @@ -336,6 +499,15 @@ class InstallerTest extends MockedTest */ public function testCheckHtAccessFail() { + // Mocking that we can use CURL + $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists->expects($this->any())->willReturnCallback(function($function_name) { + if ($function_name === 'curl_init') { + return true; + } + return call_user_func_array('\function_exists', func_get_args()); + }); + $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; }); // Mocking the CURL Response @@ -367,9 +539,6 @@ class InstallerTest extends MockedTest DI::init($this->dice, true); - // Mocking that we can use CURL - $this->setFunctions(['curl_init' => true]); - $install = new Installer(); self::assertFalse($install->checkHtAccess('https://test')); @@ -383,6 +552,15 @@ class InstallerTest extends MockedTest */ public function testCheckHtAccessWork() { + // Mocking that we can use CURL + $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists->expects($this->any())->willReturnCallback(function($function_name) { + if ($function_name === 'curl_init') { + return true; + } + return call_user_func_array('\function_exists', func_get_args()); + }); + $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; }); // Mocking the failed CURL Response @@ -414,9 +592,6 @@ class InstallerTest extends MockedTest DI::init($this->dice, true); - // Mocking that we can use CURL - $this->setFunctions(['curl_init' => true]); - $install = new Installer(); self::assertTrue($install->checkHtAccess('https://test')); @@ -427,14 +602,18 @@ class InstallerTest extends MockedTest * @runInSeparateProcess * @preserveGlobalState disabled */ - public function testImagick() + public function testCheckImagickWithImagick() { - static::markTestIncomplete('needs adapted class_exists() mock'); + $class_exists = $this->getFunctionMock(__NAMESPACE__, 'class_exists'); + $class_exists->expects($this->any())->willReturnCallback(function($class_name) { + if ($class_name === 'Imagick') { + return true; + } + return call_user_func_array('\class_exists', func_get_args()); + }); $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; }); - $this->setClasses(['Imagick' => true]); - $install = new Installer(); // even there is no supported type, Imagick should return true (because it is not required) @@ -506,34 +685,3 @@ class InstallerTest extends MockedTest $install->setUpCache($configCache, '/test/'); } } - -/** - * A workaround to replace the PHP native function_exists with a mocked function - * - * @param string $function_name the Name of the function - * - * @return bool true or false - */ -function function_exists(string $function_name) -{ - global $phpMock; - if (isset($phpMock['function_exists'])) { - $result = call_user_func_array($phpMock['function_exists'], func_get_args()); - if ($result !== '__phpunit_continue__') { - return $result; - } - } - return call_user_func_array('\function_exists', func_get_args()); -} - -function class_exists($class_name) -{ - global $phpMock; - if (isset($phpMock['class_exists'])) { - $result = call_user_func_array($phpMock['class_exists'], func_get_args()); - if ($result !== '__phpunit_continue__') { - return $result; - } - } - return call_user_func_array('\class_exists', func_get_args()); -} diff --git a/tests/src/Util/CryptoTest.php b/tests/src/Util/CryptoTest.php index eeb99b1bb9..f27a8ddf9d 100644 --- a/tests/src/Util/CryptoTest.php +++ b/tests/src/Util/CryptoTest.php @@ -5,7 +5,6 @@ // // SPDX-License-Identifier: AGPL-3.0-or-later -/// @todo Use right namespace - needs alternative way of mocking random_int() namespace Friendica\Test\src\Util; use Friendica\Util\Crypto; @@ -42,7 +41,7 @@ class CryptoTest extends TestCase public function testRandomDigitsRandomInt() { $random_int = $this->getFunctionMock(__NAMESPACE__, 'random_int'); - $random_int->expects($this->any())->willReturnCallback(function($min, $max) { + $random_int->expects($this->any())->willReturnCallback(function($min, $max) { global $phpMock; if (isset($phpMock['random_int'])) { return call_user_func_array($phpMock['random_int'], func_get_args()); From 04d4c6d8f0c2b48788906deb0fde54eb08aae40a Mon Sep 17 00:00:00 2001 From: Art4 Date: Sat, 2 Nov 2024 20:57:11 +0100 Subject: [PATCH 4/9] Fix mocking namespace --- src/Util/Crypto.php | 2 +- tests/src/Core/InstallerTest.php | 32 +++++++++++++++--------------- tests/src/Util/CryptoTest.php | 34 +++++--------------------------- 3 files changed, 22 insertions(+), 46 deletions(-) diff --git a/src/Util/Crypto.php b/src/Util/Crypto.php index 4bfa7fcddd..ba3c46bbc3 100644 --- a/src/Util/Crypto.php +++ b/src/Util/Crypto.php @@ -313,6 +313,6 @@ class Crypto $rn .= random_int(0, 9); } - return $rn; + return (int) $rn; } } diff --git a/tests/src/Core/InstallerTest.php b/tests/src/Core/InstallerTest.php index f07ad602c5..c6dbfd6be1 100644 --- a/tests/src/Core/InstallerTest.php +++ b/tests/src/Core/InstallerTest.php @@ -151,7 +151,7 @@ class InstallerTest extends MockedTest */ public function testCheckKeys($function, $expected) { - $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists = $this->getFunctionMock('Friendica\Core', 'function_exists'); $function_exists->expects($this->any())->willReturnCallback(function($function_name) use ($function, $expected) { if ($function_name === $function) { return $expected; @@ -170,7 +170,7 @@ class InstallerTest extends MockedTest */ public function testCheckFunctionsWithoutIntlChar() { - $class_exists = $this->getFunctionMock(__NAMESPACE__, 'class_exists'); + $class_exists = $this->getFunctionMock('Friendica\Core', 'class_exists'); $class_exists->expects($this->any())->willReturnCallback(function($class_name) { if ($class_name === 'IntlChar') { return false; @@ -195,7 +195,7 @@ class InstallerTest extends MockedTest */ public function testCheckFunctionsWithoutCurlInit() { - $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists = $this->getFunctionMock('Friendica\Core', 'function_exists'); $function_exists->expects($this->any())->willReturnCallback(function($function_name) { if ($function_name === 'curl_init') { return false; @@ -220,7 +220,7 @@ class InstallerTest extends MockedTest */ public function testCheckFunctionsWithoutImagecreateformjpeg() { - $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists = $this->getFunctionMock('Friendica\Core', 'function_exists'); $function_exists->expects($this->any())->willReturnCallback(function($function_name) { if ($function_name === 'imagecreatefromjpeg') { return false; @@ -245,7 +245,7 @@ class InstallerTest extends MockedTest */ public function testCheckFunctionsWithoutOpensslpublicencrypt() { - $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists = $this->getFunctionMock('Friendica\Core', 'function_exists'); $function_exists->expects($this->any())->willReturnCallback(function($function_name) { if ($function_name === 'openssl_public_encrypt') { return false; @@ -270,7 +270,7 @@ class InstallerTest extends MockedTest */ public function testCheckFunctionsWithoutMbStrlen() { - $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists = $this->getFunctionMock('Friendica\Core', 'function_exists'); $function_exists->expects($this->any())->willReturnCallback(function($function_name) { if ($function_name === 'mb_strlen') { return false; @@ -295,7 +295,7 @@ class InstallerTest extends MockedTest */ public function testCheckFunctionsWithoutIconvStrlen() { - $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists = $this->getFunctionMock('Friendica\Core', 'function_exists'); $function_exists->expects($this->any())->willReturnCallback(function($function_name) { if ($function_name === 'iconv_strlen') { return false; @@ -320,7 +320,7 @@ class InstallerTest extends MockedTest */ public function testCheckFunctionsWithoutPosixkill() { - $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists = $this->getFunctionMock('Friendica\Core', 'function_exists'); $function_exists->expects($this->any())->willReturnCallback(function($function_name) { if ($function_name === 'posix_kill') { return false; @@ -345,7 +345,7 @@ class InstallerTest extends MockedTest */ public function testCheckFunctionsWithoutProcOpen() { - $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists = $this->getFunctionMock('Friendica\Core', 'function_exists'); $function_exists->expects($this->any())->willReturnCallback(function($function_name) { if ($function_name === 'proc_open') { return false; @@ -370,7 +370,7 @@ class InstallerTest extends MockedTest */ public function testCheckFunctionsWithoutJsonEncode() { - $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists = $this->getFunctionMock('Friendica\Core', 'function_exists'); $function_exists->expects($this->any())->willReturnCallback(function($function_name) { if ($function_name === 'json_encode') { return false; @@ -395,7 +395,7 @@ class InstallerTest extends MockedTest */ public function testCheckFunctionsWithoutFinfoOpen() { - $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists = $this->getFunctionMock('Friendica\Core', 'function_exists'); $function_exists->expects($this->any())->willReturnCallback(function($function_name) { if ($function_name === 'finfo_open') { return false; @@ -420,7 +420,7 @@ class InstallerTest extends MockedTest */ public function testCheckFunctionsWithoutGmpStrval() { - $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists = $this->getFunctionMock('Friendica\Core', 'function_exists'); $function_exists->expects($this->any())->willReturnCallback(function($function_name) { if ($function_name === 'gmp_strval') { return false; @@ -445,7 +445,7 @@ class InstallerTest extends MockedTest */ public function testCheckFunctions() { - $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists = $this->getFunctionMock('Friendica\Core', 'function_exists'); $function_exists->expects($this->any())->willReturnCallback(function($function_name) { if (in_array( $function_name, @@ -500,7 +500,7 @@ class InstallerTest extends MockedTest public function testCheckHtAccessFail() { // Mocking that we can use CURL - $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists = $this->getFunctionMock('Friendica\Core', 'function_exists'); $function_exists->expects($this->any())->willReturnCallback(function($function_name) { if ($function_name === 'curl_init') { return true; @@ -553,7 +553,7 @@ class InstallerTest extends MockedTest public function testCheckHtAccessWork() { // Mocking that we can use CURL - $function_exists = $this->getFunctionMock(__NAMESPACE__, 'function_exists'); + $function_exists = $this->getFunctionMock('Friendica\Core', 'function_exists'); $function_exists->expects($this->any())->willReturnCallback(function($function_name) { if ($function_name === 'curl_init') { return true; @@ -604,7 +604,7 @@ class InstallerTest extends MockedTest */ public function testCheckImagickWithImagick() { - $class_exists = $this->getFunctionMock(__NAMESPACE__, 'class_exists'); + $class_exists = $this->getFunctionMock('Friendica\Core', 'class_exists'); $class_exists->expects($this->any())->willReturnCallback(function($class_name) { if ($class_name === 'Imagick') { return true; diff --git a/tests/src/Util/CryptoTest.php b/tests/src/Util/CryptoTest.php index f27a8ddf9d..544561bc3b 100644 --- a/tests/src/Util/CryptoTest.php +++ b/tests/src/Util/CryptoTest.php @@ -24,39 +24,15 @@ class CryptoTest extends TestCase parent::tearDownAfterClass(); } - /** - * Replaces random_int results with given mocks - * - */ - private function assertRandomInt($min, $max) - { - global $phpMock; - $phpMock['random_int'] = function ($mMin, $mMax) use ($min, $max) { - self::assertEquals($min, $mMin); - self::assertEquals($max, $mMax); - return 1; - }; - } - public function testRandomDigitsRandomInt() { - $random_int = $this->getFunctionMock(__NAMESPACE__, 'random_int'); + $random_int = $this->getFunctionMock('Friendica\Util', 'random_int'); $random_int->expects($this->any())->willReturnCallback(function($min, $max) { - global $phpMock; - if (isset($phpMock['random_int'])) { - return call_user_func_array($phpMock['random_int'], func_get_args()); - } + return 1; }); - self::assertRandomInt(0, 9); - - $test = Crypto::randomDigits(1); - self::assertEquals(1, strlen($test)); - self::assertEquals(1, $test); - - $test = Crypto::randomDigits(8); - self::assertEquals(8, strlen($test)); - self::assertEquals(11111111, $test); + self::assertSame(1, Crypto::randomDigits(1)); + self::assertSame(11111111, Crypto::randomDigits(8)); } public function dataRsa(): array @@ -74,7 +50,7 @@ class CryptoTest extends TestCase */ public function testPubRsaToMe(string $key, string $expected) { - self::assertEquals($expected, Crypto::rsaToPem(base64_decode($key))); + self::assertSame($expected, Crypto::rsaToPem(base64_decode($key))); } From cf92446cf361c1c047099fb70df7597c4336d206 Mon Sep 17 00:00:00 2001 From: Art4 Date: Sat, 2 Nov 2024 22:06:02 +0100 Subject: [PATCH 5/9] Fix tests --- tests/src/Core/InstallerTest.php | 75 +------------------------------- 1 file changed, 2 insertions(+), 73 deletions(-) diff --git a/tests/src/Core/InstallerTest.php b/tests/src/Core/InstallerTest.php index c6dbfd6be1..a97c7d36c9 100644 --- a/tests/src/Core/InstallerTest.php +++ b/tests/src/Core/InstallerTest.php @@ -118,24 +118,6 @@ class InstallerTest extends MockedTest self::assertArraySubset($subSet, $assertionArray, false, "expected subset: " . PHP_EOL . print_r($subSet, true) . PHP_EOL . "current subset: " . print_r($assertionArray, true)); } - /** - * Replaces class_exist results with given mocks - * - * @param array $classes a list from class names and their results - */ - private function setClasses(array $classes) - { - global $phpMock; - $phpMock['class_exists'] = function($class) use ($classes) { - foreach ($classes as $name => $value) { - if ($class == $name) { - return $value; - } - } - return '__phpunit_continue__'; - }; - } - public static function getCheckKeysData(): array { return [ @@ -494,8 +476,6 @@ class InstallerTest extends MockedTest /** * @small - * @runInSeparateProcess - * @preserveGlobalState disabled */ public function testCheckHtAccessFail() { @@ -547,8 +527,6 @@ class InstallerTest extends MockedTest /** * @small - * @runInSeparateProcess - * @preserveGlobalState disabled */ public function testCheckHtAccessWork() { @@ -597,64 +575,15 @@ class InstallerTest extends MockedTest self::assertTrue($install->checkHtAccess('https://test')); } - /** - * @small - * @runInSeparateProcess - * @preserveGlobalState disabled - */ - public function testCheckImagickWithImagick() + public function testImagickNotInstalled() { $class_exists = $this->getFunctionMock('Friendica\Core', 'class_exists'); $class_exists->expects($this->any())->willReturnCallback(function($class_name) { if ($class_name === 'Imagick') { - return true; + return false; } return call_user_func_array('\class_exists', func_get_args()); }); - - $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; }); - - $install = new Installer(); - - // even there is no supported type, Imagick should return true (because it is not required) - self::assertTrue($install->checkImagick()); - - self::assertCheckExist(1, - $this->l10nMock->t('ImageMagick supports GIF'), - '', - true, - false, - $install->getChecks()); - } - - /** - * @small - * @runInSeparateProcess - * @preserveGlobalState disabled - */ - public function testImagickNotFound() - { - static::markTestIncomplete('Disabled due not working/difficult mocking global functions - needs more care!'); - - $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; }); - - $this->setClasses(['Imagick' => true]); - - $install = new Installer(); - - // even there is no supported type, Imagick should return true (because it is not required) - self::assertTrue($install->checkImagick()); - self::assertCheckExist(1, - $this->l10nMock->t('ImageMagick supports GIF'), - '', - false, - false, - $install->getChecks()); - } - - public function testImagickNotInstalled() - { - $this->setClasses(['Imagick' => false]); $this->mockL10nT('ImageMagick PHP extension is not installed'); $install = new Installer(); From 940884e4bd0c1f68757e464f46b4e76c1f4da5b1 Mon Sep 17 00:00:00 2001 From: Art4 Date: Sat, 9 Nov 2024 23:18:13 +0000 Subject: [PATCH 6/9] Refactor Crypto::randomDigits() --- src/Util/Crypto.php | 9 +-------- tests/src/Util/CryptoTest.php | 5 ++--- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/Util/Crypto.php b/src/Util/Crypto.php index ba3c46bbc3..8113697639 100644 --- a/src/Util/Crypto.php +++ b/src/Util/Crypto.php @@ -306,13 +306,6 @@ class Crypto */ public static function randomDigits($digits) { - $rn = ''; - - // generating cryptographically secure pseudo-random integers - for ($i = 0; $i < $digits; $i++) { - $rn .= random_int(0, 9); - } - - return (int) $rn; + return random_int(0, 10 ** $digits - 1); } } diff --git a/tests/src/Util/CryptoTest.php b/tests/src/Util/CryptoTest.php index 544561bc3b..dae87865b9 100644 --- a/tests/src/Util/CryptoTest.php +++ b/tests/src/Util/CryptoTest.php @@ -28,11 +28,10 @@ class CryptoTest extends TestCase { $random_int = $this->getFunctionMock('Friendica\Util', 'random_int'); $random_int->expects($this->any())->willReturnCallback(function($min, $max) { - return 1; + return 12345678; }); - self::assertSame(1, Crypto::randomDigits(1)); - self::assertSame(11111111, Crypto::randomDigits(8)); + self::assertSame(12345678, Crypto::randomDigits(8)); } public function dataRsa(): array From 8b500926eef146dc6e2a6fdf94db887a71b408f5 Mon Sep 17 00:00:00 2001 From: Art4 Date: Sat, 9 Nov 2024 23:50:06 +0000 Subject: [PATCH 7/9] Refactor tests for Util\Crypto --- tests/Unit/Util/CryptoTest.php | 45 +++++++++++++ tests/datasets/crypto/rsa/diaspora-public-pem | 6 -- .../crypto/rsa/diaspora-public-rsa-base64 | 1 - tests/src/Util/CryptoTest.php | 64 ------------------- 4 files changed, 45 insertions(+), 71 deletions(-) create mode 100644 tests/Unit/Util/CryptoTest.php delete mode 100644 tests/datasets/crypto/rsa/diaspora-public-pem delete mode 100644 tests/datasets/crypto/rsa/diaspora-public-rsa-base64 delete mode 100644 tests/src/Util/CryptoTest.php diff --git a/tests/Unit/Util/CryptoTest.php b/tests/Unit/Util/CryptoTest.php new file mode 100644 index 0000000000..7f6f0fb656 --- /dev/null +++ b/tests/Unit/Util/CryptoTest.php @@ -0,0 +1,45 @@ +getFunctionMock('Friendica\Util', 'random_int'); + $random_int->expects($this->any())->willReturnCallback(function($min, $max) { + return 12345678; + }); + + self::assertSame(12345678, Crypto::randomDigits(8)); + } + + public function testDiasporaPubRsaToMe() + { + $key = 'LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tDQpNSUdKQW9HQkFORjVLTmJzN2k3aTByNVFZckNpRExEZ09pU1BWbmgvdlFnMXpnSk9VZVRheWVETk5yZTR6T1RVDQpSVDcyZGlLQ294OGpYOE5paElJTFJtcUtTOWxVYVNzd21QcVNFenVpdE5xeEhnQy8xS2ZuaXM1Qm96NnRwUUxjDQpsZDMwQjJSMWZIVWdFTHZWd0JkV29pRDhSRUt1dFNuRVBGd1RwVmV6aVlWYWtNY25pclRWQWdNQkFBRT0NCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0'; + + // TODO PHPUnit 10: Replace with assertStringEqualsStringIgnoringLineEndings() + self::assertSame( + str_replace("\n", "\r\n", <<< TXT + -----BEGIN PUBLIC KEY----- + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDReSjW7O4u4tK+UGKwogyw4Dok + j1Z4f70INc4CTlHk2sngzTa3uMzk1EU+9nYigqMfI1/DYoSCC0ZqikvZVGkrMJj6 + khM7orTasR4Av9Sn54rOQaM+raUC3JXd9AdkdXx1IBC71cAXVqIg/ERCrrUpxDxc + E6VXs4mFWpDHJ4q01QIDAQAB + -----END PUBLIC KEY----- + TXT), + Crypto::rsaToPem(base64_decode($key)) + ); + } +} diff --git a/tests/datasets/crypto/rsa/diaspora-public-pem b/tests/datasets/crypto/rsa/diaspora-public-pem deleted file mode 100644 index 09dd1640d3..0000000000 --- a/tests/datasets/crypto/rsa/diaspora-public-pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDReSjW7O4u4tK+UGKwogyw4Dok -j1Z4f70INc4CTlHk2sngzTa3uMzk1EU+9nYigqMfI1/DYoSCC0ZqikvZVGkrMJj6 -khM7orTasR4Av9Sn54rOQaM+raUC3JXd9AdkdXx1IBC71cAXVqIg/ERCrrUpxDxc -E6VXs4mFWpDHJ4q01QIDAQAB ------END PUBLIC KEY----- \ No newline at end of file diff --git a/tests/datasets/crypto/rsa/diaspora-public-rsa-base64 b/tests/datasets/crypto/rsa/diaspora-public-rsa-base64 deleted file mode 100644 index ba835a4711..0000000000 --- a/tests/datasets/crypto/rsa/diaspora-public-rsa-base64 +++ /dev/null @@ -1 +0,0 @@ -LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tDQpNSUdKQW9HQkFORjVLTmJzN2k3aTByNVFZckNpRExEZ09pU1BWbmgvdlFnMXpnSk9VZVRheWVETk5yZTR6T1RVDQpSVDcyZGlLQ294OGpYOE5paElJTFJtcUtTOWxVYVNzd21QcVNFenVpdE5xeEhnQy8xS2ZuaXM1Qm96NnRwUUxjDQpsZDMwQjJSMWZIVWdFTHZWd0JkV29pRDhSRUt1dFNuRVBGd1RwVmV6aVlWYWtNY25pclRWQWdNQkFBRT0NCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0 \ No newline at end of file diff --git a/tests/src/Util/CryptoTest.php b/tests/src/Util/CryptoTest.php deleted file mode 100644 index dae87865b9..0000000000 --- a/tests/src/Util/CryptoTest.php +++ /dev/null @@ -1,64 +0,0 @@ -getFunctionMock('Friendica\Util', 'random_int'); - $random_int->expects($this->any())->willReturnCallback(function($min, $max) { - return 12345678; - }); - - self::assertSame(12345678, Crypto::randomDigits(8)); - } - - public function dataRsa(): array - { - return [ - 'diaspora' => [ - 'key' => file_get_contents(__DIR__ . '/../../datasets/crypto/rsa/diaspora-public-rsa-base64'), - 'expected' => file_get_contents(__DIR__ . '/../../datasets/crypto/rsa/diaspora-public-pem'), - ], - ]; - } - - /** - * @dataProvider dataRsa - */ - public function testPubRsaToMe(string $key, string $expected) - { - self::assertSame($expected, Crypto::rsaToPem(base64_decode($key))); - } - - - public function dataPEM() - { - return [ - 'diaspora' => [ - 'key' => file_get_contents(__DIR__ . '/../../datasets/crypto/rsa/diaspora-public-pem'), - ], - ]; - } -} From bbf7e4a93649cc6b12b1e64868631c7eb2ae53a3 Mon Sep 17 00:00:00 2001 From: Art4 Date: Sat, 9 Nov 2024 23:56:59 +0000 Subject: [PATCH 8/9] Fix code style --- tests/Unit/Util/CryptoTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/Util/CryptoTest.php b/tests/Unit/Util/CryptoTest.php index 7f6f0fb656..1e728746f2 100644 --- a/tests/Unit/Util/CryptoTest.php +++ b/tests/Unit/Util/CryptoTest.php @@ -18,7 +18,7 @@ class CryptoTest extends TestCase public function testRandomDigitsRandomInt() { $random_int = $this->getFunctionMock('Friendica\Util', 'random_int'); - $random_int->expects($this->any())->willReturnCallback(function($min, $max) { + $random_int->expects($this->any())->willReturnCallback(function ($min, $max) { return 12345678; }); From 53052863128b464c4ef1f7aefd1c88f39e275eda Mon Sep 17 00:00:00 2001 From: Art4 Date: Sun, 10 Nov 2024 00:12:47 +0000 Subject: [PATCH 9/9] Improve phpunit testsuites, add script for unit tests --- composer.json | 1 + tests/phpunit.xml | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 0280409716..36905f81d1 100644 --- a/composer.json +++ b/composer.json @@ -156,6 +156,7 @@ }, "scripts": { "test": "phpunit", + "test:unit": "phpunit -c tests/phpunit.xml --testsuite unit", "lint": "find . -name \\*.php -not -path './vendor/*' -not -path './view/asset/*' -print0 | xargs -0 -n1 php -l", "docker:translate": "docker run --rm -v $PWD:/data -w /data friendicaci/transifex bin/run_xgettext.sh", "cs:install": "@composer install --working-dir=bin/dev/php-cs-fixer", diff --git a/tests/phpunit.xml b/tests/phpunit.xml index 6f16c7a73e..0e323813f8 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -7,10 +7,16 @@ timeoutForMediumTests="900" timeoutForLargeTests="900" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"> - - functional/ - src/ - + + + functional/ + src/ + Unit/ + + + Unit/ + +