From 90bc438caed743bab5b53b10a2c5a72494e2a1d6 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 1 Apr 2019 22:59:04 +0200 Subject: [PATCH 001/137] Composer > support/require PHP 7.2+ (instead of 5.6+) --- CHANGELOG.md | 4 ++++ VERSION | 2 +- composer.json | 2 +- docker/config/Dockerfile | 6 +++--- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 475b1be..0bd054b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Common and useful classes, methods, exceptions etc. +# 1.0.0 + +1. Composer > support/require PHP 7.2+ (instead of 5.6+) + # 0.1.8 1. Size, e.g. of image diff --git a/VERSION b/VERSION index 699c6c6..3eefcb9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.8 +1.0.0 diff --git a/composer.json b/composer.json index bf18bd2..3c424e4 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ "ext-fileinfo": "*", "ext-json": "*", "ext-simplexml": "*", - "php": ">=5.6", + "php": ">=7.2", "ext-intl": "*", "ext-pcre": "*", "doctrine/orm": "^2.5", diff --git a/docker/config/Dockerfile b/docker/config/Dockerfile index 277e672..5a7861b 100644 --- a/docker/config/Dockerfile +++ b/docker/config/Dockerfile @@ -1,4 +1,4 @@ -FROM php:5.6-cli +FROM php:7.2-cli MAINTAINER Meritoo # @@ -58,7 +58,7 @@ RUN docker-php-ext-install \ # - Xdebug # RUN pecl install \ - xdebug-2.5.5 \ + xdebug \ && docker-php-ext-enable \ xdebug @@ -98,7 +98,7 @@ ENV COMPOSER_ALLOW_SUPERUSER 1 # RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ && php -r "if (hash_file('SHA384', 'composer-setup.php') === \ - '93b54496392c062774670ac18b134c3b3a95e5a5e5c8f1a9f115f203b75bf9a129d5daa8ba6a13e2cc8a1da0806388a8') { echo \ + '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo \ 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \ && php composer-setup.php --install-dir=/usr/local/bin --filename=composer \ && php -r "unlink('composer-setup.php');" \ From e623c872682b236167768eb62ec58fa71e08e26c Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 08:24:40 +0200 Subject: [PATCH 002/137] Composer > bump versions of packages (available for PHP 7.2+) --- composer.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 3c424e4..3fc63ba 100644 --- a/composer.json +++ b/composer.json @@ -10,24 +10,24 @@ } ], "require": { + "php": ">=7.2", "ext-dom": "*", "ext-fileinfo": "*", - "ext-json": "*", - "ext-simplexml": "*", - "php": ">=7.2", "ext-intl": "*", + "ext-json": "*", "ext-pcre": "*", - "doctrine/orm": "^2.5", + "ext-simplexml": "*", + "doctrine/orm": "^2.6", "gedmo/doctrine-extensions": "^2.4" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.2", + "friendsofphp/php-cs-fixer": "^2.14", "pdepend/pdepend": "^2.5", - "phploc/phploc": "^2.1", + "phploc/phploc": "^5.0", "phpmd/phpmd": "^2.6", - "phpunit/phpunit": "^4.8", - "sebastian/phpcpd": "^2.0", - "squizlabs/php_codesniffer": "^2.9" + "phpunit/phpunit": "^8.0", + "sebastian/phpcpd": "^4.1", + "squizlabs/php_codesniffer": "^3.4" }, "autoload": { "psr-4": { From 8b5a530bbca5170808295c7272f5fc6bffacf082 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 08:27:20 +0200 Subject: [PATCH 003/137] Tests > setUp() and tearDown() methods > make compatible with PHPUnit 8.0 (and PHP 7.2+) --- tests/Collection/CollectionTest.php | 2 +- tests/Utilities/ArraysTest.php | 4 ++-- tests/Utilities/ComposerTest.php | 2 +- tests/Utilities/MiscellaneousTest.php | 4 ++-- tests/Utilities/RegexTest.php | 4 ++-- tests/Utilities/XmlTest.php | 4 ++-- tests/ValueObject/AddressTest.php | 2 +- tests/ValueObject/BankAccountTest.php | 2 +- tests/ValueObject/CompanyTest.php | 2 +- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/Collection/CollectionTest.php b/tests/Collection/CollectionTest.php index 37e9be2..092ef89 100644 --- a/tests/Collection/CollectionTest.php +++ b/tests/Collection/CollectionTest.php @@ -491,7 +491,7 @@ class CollectionTest extends BaseTestCase /** * {@inheritdoc} */ - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/tests/Utilities/ArraysTest.php b/tests/Utilities/ArraysTest.php index 168fac7..688edce 100644 --- a/tests/Utilities/ArraysTest.php +++ b/tests/Utilities/ArraysTest.php @@ -2683,7 +2683,7 @@ letsTest[2] = value_2;'; /** * {@inheritdoc} */ - protected function setUp() + protected function setUp(): void { parent::setUp(); @@ -2793,7 +2793,7 @@ letsTest[2] = value_2;'; /** * {@inheritdoc} */ - protected function tearDown() + protected function tearDown(): void { parent::tearDown(); diff --git a/tests/Utilities/ComposerTest.php b/tests/Utilities/ComposerTest.php index 10e4177..e8f8117 100644 --- a/tests/Utilities/ComposerTest.php +++ b/tests/Utilities/ComposerTest.php @@ -84,7 +84,7 @@ class ComposerTest extends BaseTestCase /** * {@inheritdoc} */ - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/tests/Utilities/MiscellaneousTest.php b/tests/Utilities/MiscellaneousTest.php index 70c36c7..86e7670 100644 --- a/tests/Utilities/MiscellaneousTest.php +++ b/tests/Utilities/MiscellaneousTest.php @@ -1470,7 +1470,7 @@ class MiscellaneousTest extends BaseTestCase /** * {@inheritdoc} */ - protected function setUp() + protected function setUp(): void { parent::setUp(); @@ -1483,7 +1483,7 @@ class MiscellaneousTest extends BaseTestCase /** * {@inheritdoc} */ - protected function tearDown() + protected function tearDown(): void { parent::tearDown(); unset($this->stringSmall, $this->stringCommaSeparated, $this->stringDotSeparated, $this->stringWithoutSpaces); diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index c1fb3bc..469bbb0 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -1998,7 +1998,7 @@ class RegexTest extends BaseTestCase /** * {@inheritdoc} */ - protected function setUp() + protected function setUp(): void { parent::setUp(); @@ -2010,7 +2010,7 @@ class RegexTest extends BaseTestCase /** * {@inheritdoc} */ - protected function tearDown() + protected function tearDown(): void { parent::tearDown(); unset($this->simpleText, $this->camelCaseText); diff --git a/tests/Utilities/XmlTest.php b/tests/Utilities/XmlTest.php index 494aabf..073c320 100644 --- a/tests/Utilities/XmlTest.php +++ b/tests/Utilities/XmlTest.php @@ -52,7 +52,7 @@ class XmlTest extends BaseTestCase /** * {@inheritdoc} */ - protected function setUp() + protected function setUp(): void { parent::setUp(); @@ -86,7 +86,7 @@ class XmlTest extends BaseTestCase /** * {@inheritdoc} */ - protected function tearDown() + protected function tearDown(): void { parent::tearDown(); diff --git a/tests/ValueObject/AddressTest.php b/tests/ValueObject/AddressTest.php index 5cd1899..63806e4 100644 --- a/tests/ValueObject/AddressTest.php +++ b/tests/ValueObject/AddressTest.php @@ -94,7 +94,7 @@ class AddressTest extends BaseTestCase static::assertSame('00111, Saint Louis', (string)$this->addressWithoutStreet); } - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/tests/ValueObject/BankAccountTest.php b/tests/ValueObject/BankAccountTest.php index ac38dbc..4b07705 100644 --- a/tests/ValueObject/BankAccountTest.php +++ b/tests/ValueObject/BankAccountTest.php @@ -61,7 +61,7 @@ class BankAccountTest extends BaseTestCase /** * {@inheritdoc} */ - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/tests/ValueObject/CompanyTest.php b/tests/ValueObject/CompanyTest.php index 383b012..6fcfd99 100644 --- a/tests/ValueObject/CompanyTest.php +++ b/tests/ValueObject/CompanyTest.php @@ -80,7 +80,7 @@ class CompanyTest extends BaseTestCase /** * {@inheritdoc} */ - protected function setUp() + protected function setUp(): void { parent::setUp(); From c89b6da0db3fb07885170355edb634f6f6dd653e Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 08:31:24 +0200 Subject: [PATCH 004/137] Tests > fix "Call to undefined method setExpectedException()" bug > make compatible with PHPUnit 8.0 (and PHP 7.2+) --- .../Exception/Base/UnknownTypeExceptionTest.php | 2 +- tests/Utilities/BundleTest.php | 8 ++++---- tests/Utilities/DateTest.php | 2 +- tests/Utilities/MiscellaneousTest.php | 4 ++-- tests/Utilities/ReflectionTest.php | 16 ++++++++-------- tests/Utilities/RegexTest.php | 6 +++--- tests/ValueObject/SizeTest.php | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/Exception/Base/UnknownTypeExceptionTest.php b/tests/Exception/Base/UnknownTypeExceptionTest.php index ce910d3..9dc6113 100644 --- a/tests/Exception/Base/UnknownTypeExceptionTest.php +++ b/tests/Exception/Base/UnknownTypeExceptionTest.php @@ -33,7 +33,7 @@ class UnknownTypeExceptionTest extends BaseTestCase public function testTheException() { - $this->setExpectedException(UnknownTestTypeException::class); + $this->expectException(UnknownTestTypeException::class); self::assertEmpty((new TestService())->getTranslatedType('test_3')); } } diff --git a/tests/Utilities/BundleTest.php b/tests/Utilities/BundleTest.php index 92dd655..03e9340 100644 --- a/tests/Utilities/BundleTest.php +++ b/tests/Utilities/BundleTest.php @@ -49,8 +49,8 @@ class BundleTest extends BaseTestCase $template = 'Name of bundle \'%s\' is incorrect. It should start with big letter and end with "Bundle". Is' . ' there everything ok?'; - $message = sprintf($template, $bundleName); - $this->setExpectedException(IncorrectBundleNameException::class, $message); + $this->expectException(IncorrectBundleNameException::class); + $this->expectExceptionMessage(sprintf($template, $bundleName)); Bundle::getBundleViewPath($viewPath, $bundleName); } @@ -90,7 +90,7 @@ class BundleTest extends BaseTestCase */ public function testGetShortBundleNameUsingEmptyValue($emptyValue) { - $this->setExpectedException(IncorrectBundleNameException::class); + $this->expectException(IncorrectBundleNameException::class); Bundle::getShortBundleName($emptyValue); } @@ -102,7 +102,7 @@ class BundleTest extends BaseTestCase */ public function testGetShortBundleNameUsingIncorrectBundleName($bundleName) { - $this->setExpectedException(IncorrectBundleNameException::class); + $this->expectException(IncorrectBundleNameException::class); Bundle::getShortBundleName($bundleName); } diff --git a/tests/Utilities/DateTest.php b/tests/Utilities/DateTest.php index 5fca3fe..1af25bd 100644 --- a/tests/Utilities/DateTest.php +++ b/tests/Utilities/DateTest.php @@ -224,7 +224,7 @@ class DateTest extends BaseTestCase */ public function testGetDayOfWeekIncorrectValues($year, $month, $day) { - $this->setExpectedException(UnknownDatePartTypeException::class); + $this->expectException(UnknownDatePartTypeException::class); self::assertEmpty(Date::getDayOfWeek($year, $month, $day)); } diff --git a/tests/Utilities/MiscellaneousTest.php b/tests/Utilities/MiscellaneousTest.php index 86e7670..909bb11 100644 --- a/tests/Utilities/MiscellaneousTest.php +++ b/tests/Utilities/MiscellaneousTest.php @@ -650,7 +650,7 @@ class MiscellaneousTest extends BaseTestCase public function testGetInvertedColorWithIncorrectLength() { - $this->setExpectedException(IncorrectColorHexLengthException::class); + $this->expectException(IncorrectColorHexLengthException::class); Miscellaneous::getInvertedColor(null); Miscellaneous::getInvertedColor(''); @@ -664,7 +664,7 @@ class MiscellaneousTest extends BaseTestCase public function testGetInvertedColorWithInvalidValue() { - $this->setExpectedException(InvalidColorHexValueException::class); + $this->expectException(InvalidColorHexValueException::class); Miscellaneous::getInvertedColor('0011zz'); Miscellaneous::getInvertedColor('001#zz'); diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 2507d7e..9c1baf3 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -135,7 +135,7 @@ class ReflectionTest extends BaseTestCase */ public function testGetChildClassesInvalidClass($invalidClass) { - $this->setExpectedException(CannotResolveClassNameException::class); + $this->expectException(CannotResolveClassNameException::class); self::assertNull(Reflection::getChildClasses($invalidClass)); self::assertNull(Reflection::getChildClasses(123)); @@ -143,7 +143,7 @@ class ReflectionTest extends BaseTestCase public function testGetChildClassesNotExistingClass() { - $this->setExpectedException(CannotResolveClassNameException::class); + $this->expectException(CannotResolveClassNameException::class); self::assertEquals('', Reflection::getChildClasses('xyz')); } @@ -174,13 +174,13 @@ class ReflectionTest extends BaseTestCase public function testGetOneChildClassWithMissingChildClasses() { - $this->setExpectedException(MissingChildClassesException::class); + $this->expectException(MissingChildClassesException::class); self::assertEquals('LoremIpsum', Reflection::getOneChildClass(C::class)); } public function testGetOneChildClassWithTooManyChildClasses() { - $this->setExpectedException(TooManyChildClassesException::class); + $this->expectException(TooManyChildClassesException::class); self::assertEquals(B::class, Reflection::getOneChildClass(A::class)); self::assertEquals(C::class, Reflection::getOneChildClass(A::class)); @@ -208,7 +208,7 @@ class ReflectionTest extends BaseTestCase */ public function testUsesTraitInvalidClass($class, $trait) { - $this->setExpectedException(CannotResolveClassNameException::class); + $this->expectException(CannotResolveClassNameException::class); self::assertNull(Reflection::usesTrait($class, $trait)); } @@ -218,7 +218,7 @@ class ReflectionTest extends BaseTestCase */ public function testUsesTraitInvalidTrait($trait) { - $this->setExpectedException(CannotResolveClassNameException::class); + $this->expectException(CannotResolveClassNameException::class); self::assertNull(Reflection::usesTrait(DateTime::class, $trait)); } @@ -504,7 +504,7 @@ class ReflectionTest extends BaseTestCase */ public function testSetPropertyValueUsingNotExistingProperty($object, $property) { - $this->setExpectedException(NotExistingPropertyException::class); + $this->expectException(NotExistingPropertyException::class); Reflection::setPropertyValue($object, $property, 'test test test'); } @@ -542,7 +542,7 @@ class ReflectionTest extends BaseTestCase */ public function testSetPropertiesValuesUsingNotExistingProperties($object, array $propertiesValues) { - $this->setExpectedException(NotExistingPropertyException::class); + $this->expectException(NotExistingPropertyException::class); Reflection::setPropertiesValues($object, $propertiesValues); } diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index 469bbb0..ba9bcf2 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -571,7 +571,7 @@ class RegexTest extends BaseTestCase */ public function testGetValidColorHexValueUsingEmptyValue($emptyValue) { - $this->setExpectedException(IncorrectColorHexLengthException::class); + $this->expectException(IncorrectColorHexLengthException::class); Regex::getValidColorHexValue($emptyValue); } @@ -590,7 +590,7 @@ class RegexTest extends BaseTestCase */ public function testGetValidColorHexValueUsingIncorrectValue($incorrectColor) { - $this->setExpectedException(IncorrectColorHexLengthException::class); + $this->expectException(IncorrectColorHexLengthException::class); Regex::getValidColorHexValue($incorrectColor); } @@ -609,7 +609,7 @@ class RegexTest extends BaseTestCase */ public function testGetValidColorHexValueUsingInvalidValue($invalidColor) { - $this->setExpectedException(InvalidColorHexValueException::class); + $this->expectException(InvalidColorHexValueException::class); Regex::getValidColorHexValue($invalidColor); } diff --git a/tests/ValueObject/SizeTest.php b/tests/ValueObject/SizeTest.php index b3dbbbd..ed52f00 100644 --- a/tests/ValueObject/SizeTest.php +++ b/tests/ValueObject/SizeTest.php @@ -131,7 +131,7 @@ class SizeTest extends BaseTestCase */ public function testFromArrayUsingInvalidSizeAsArray(array $size) { - $this->setExpectedException(InvalidSizeDimensionsException::class); + $this->expectException(InvalidSizeDimensionsException::class); Size::fromArray($size); } From b68dd78b06094193492bd0d54e6b7c10785c3561 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 08:39:50 +0200 Subject: [PATCH 005/137] Tests > fix "Using assertContains() with string haystacks is deprecated and will not be supported in PHPUnit 9. Refactor your test to use assertStringContainsString() or assertStringContainsStringIgnoringCase() instead." bug > make compatible with PHPUnit 8.0 (and PHP 7.2+) --- tests/Test/Base/BaseTestCaseTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Test/Base/BaseTestCaseTest.php b/tests/Test/Base/BaseTestCaseTest.php index 71dc496..4976db6 100644 --- a/tests/Test/Base/BaseTestCaseTest.php +++ b/tests/Test/Base/BaseTestCaseTest.php @@ -133,7 +133,7 @@ class BaseTestCaseTest extends BaseTestCase } $expectedContains = sprintf('/data/tests/%s%s', $directoryPath, $fileName); - static::assertContains($expectedContains, $path); + static::assertStringContainsString($expectedContains, $path); } /** From ce37db5f3339ce1398e346e5f3c5d9a6951f35b0 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 09:03:11 +0200 Subject: [PATCH 006/137] Tests > fix "Call to undefined method getMock()" bug > make compatible with PHPUnit 8.0 (and PHP 7.2+) --- tests/Utilities/QueryBuilderUtilityTest.php | 33 ++++++++++++++++----- tests/Utilities/RepositoryTest.php | 4 +-- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/tests/Utilities/QueryBuilderUtilityTest.php b/tests/Utilities/QueryBuilderUtilityTest.php index 0451ef8..2b6894c 100644 --- a/tests/Utilities/QueryBuilderUtilityTest.php +++ b/tests/Utilities/QueryBuilderUtilityTest.php @@ -56,7 +56,7 @@ class QueryBuilderUtilityTest extends BaseTestCase public function testSetCriteriaWithoutCriteria() { - $entityManager = $this->getMock(EntityManagerInterface::class); + $entityManager = $this->createMock(EntityManagerInterface::class); $queryBuilder = new QueryBuilder($entityManager); $newQueryBuilder = QueryBuilderUtility::setCriteria($queryBuilder); @@ -72,7 +72,7 @@ class QueryBuilderUtilityTest extends BaseTestCase 'ipsum' => 22, ]; - $entityManager = $this->getMock(EntityManagerInterface::class); + $entityManager = $this->createMock(EntityManagerInterface::class); $queryBuilder = new QueryBuilder($entityManager); $newQueryBuilder = QueryBuilderUtility::setCriteria($queryBuilder, $criteria); @@ -114,7 +114,13 @@ class QueryBuilderUtilityTest extends BaseTestCase 'flush', ]; - $entityManager = $this->getMock(EntityManager::class, $methods, [], '', false); + $entityManager = $this + ->getMockBuilder(EntityManager::class) + ->disableOriginalConstructor() + ->setMethods($methods) + ->getMock() + ; + $entities1 = []; $entities2 = [ @@ -132,7 +138,13 @@ class QueryBuilderUtilityTest extends BaseTestCase 'flush', ]; - $entityManager = $this->getMock(EntityManager::class, $methods, [], '', false); + $entityManager = $this + ->getMockBuilder(EntityManager::class) + ->disableOriginalConstructor() + ->setMethods($methods) + ->getMock() + ; + $entities1 = []; $entities2 = [ @@ -165,7 +177,7 @@ class QueryBuilderUtilityTest extends BaseTestCase */ public function provideQueryBuilderAndRootAlias() { - $entityManager = $this->getMock(EntityManagerInterface::class); + $entityManager = $this->createMock(EntityManagerInterface::class); yield[ new QueryBuilder($entityManager), @@ -192,7 +204,7 @@ class QueryBuilderUtilityTest extends BaseTestCase */ public function provideQueryBuilderAndPropertyAlias() { - $entityManager = $this->getMock(EntityManagerInterface::class); + $entityManager = $this->createMock(EntityManagerInterface::class); yield[ new QueryBuilder($entityManager), @@ -255,7 +267,12 @@ class QueryBuilderUtilityTest extends BaseTestCase */ public function provideQueryBuilderAndCriteria() { - $entityManager = $this->getMock(EntityManager::class, ['getExpressionBuilder'], [], '', false); + $entityManager = $this + ->getMockBuilder(EntityManager::class) + ->disableOriginalConstructor() + ->setMethods(['getExpressionBuilder']) + ->getMock() + ; $entityManager ->expects(static::any()) @@ -295,7 +312,7 @@ class QueryBuilderUtilityTest extends BaseTestCase */ public function provideQueryBuilderAndParameters() { - $entityManager = $this->getMock(EntityManagerInterface::class); + $entityManager = $this->createMock(EntityManagerInterface::class); yield[ new QueryBuilder($entityManager), diff --git a/tests/Utilities/RepositoryTest.php b/tests/Utilities/RepositoryTest.php index 72d58a7..412701f 100644 --- a/tests/Utilities/RepositoryTest.php +++ b/tests/Utilities/RepositoryTest.php @@ -212,7 +212,7 @@ class RepositoryTest extends BaseTestCase public function testGetEntityOrderedQueryBuilderUsingDefaults() { - $entityManager = $this->getMock(EntityManagerInterface::class); + $entityManager = $this->createMock(EntityManagerInterface::class); $entityRepository = $this ->getMockBuilder(EntityRepository::class) @@ -256,7 +256,7 @@ class RepositoryTest extends BaseTestCase */ public function testGetEntityOrderedQueryBuilder($property, $direction, $expectedOrderBy) { - $entityManager = $this->getMock(EntityManagerInterface::class); + $entityManager = $this->createMock(EntityManagerInterface::class); $entityRepository = $this ->getMockBuilder(EntityRepository::class) From 8a27cd94ef7d69279cacb8dba41040080a70ca03 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 10:15:57 +0200 Subject: [PATCH 007/137] Tests > fix "assertArraySubset() is deprecated and will be removed in PHPUnit 9" bug > make compatible with PHPUnit 8.0 (and PHP 7.2+) --- tests/Utilities/RepositoryTest.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/Utilities/RepositoryTest.php b/tests/Utilities/RepositoryTest.php index 412701f..553007e 100644 --- a/tests/Utilities/RepositoryTest.php +++ b/tests/Utilities/RepositoryTest.php @@ -236,12 +236,14 @@ class RepositoryTest extends BaseTestCase $selectDQLPart = $queryBuilder->getDQLPart('select'); $whereDQLPart = $queryBuilder->getDQLPart('where'); $orderDQLPart = $queryBuilder->getDQLPart('orderBy'); + $rootAliases = $queryBuilder->getRootAliases(); /* @var OrderBy $orderBy */ $orderBy = $orderDQLPart[0]; static::assertInstanceOf(QueryBuilder::class, $queryBuilder); - static::assertArraySubset(['qb'], $queryBuilder->getRootAliases()); + static::assertArrayHasKey(0, $rootAliases); + static::assertSame('qb', $rootAliases[0]); static::assertSame([], $selectDQLPart); static::assertNull($whereDQLPart); static::assertSame(['qb.name ASC'], $orderBy->getParts()); @@ -280,9 +282,11 @@ class RepositoryTest extends BaseTestCase $selectDQLPart = $queryBuilder->getDQLPart('select'); $whereDQLPart = $queryBuilder->getDQLPart('where'); $orderDQLPart = $queryBuilder->getDQLPart('orderBy'); + $rootAliases = $queryBuilder->getRootAliases(); static::assertInstanceOf(QueryBuilder::class, $queryBuilder); - static::assertArraySubset(['qb'], $queryBuilder->getRootAliases()); + static::assertArrayHasKey(0, $rootAliases); + static::assertSame('qb', $rootAliases[0]); static::assertSame([], $selectDQLPart); static::assertNull($whereDQLPart); From 95a81ab32289f2933e2047c7b3c1bd3dd636c937 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 10:40:51 +0200 Subject: [PATCH 008/137] Tests > fix "This test did not perform any assertions" bug > make compatible with PHPUnit 8.0 (and PHP 7.2+) --- tests/Utilities/ReflectionTest.php | 44 ++++++++++++++---------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 9c1baf3..09f9883 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -76,22 +76,20 @@ class ReflectionTest extends BaseTestCase ])); } - public function testGetClassNameDuplicatedName() + /** + * A case when namespace of class contains name of class (name of class is duplicated, occurs twice) + */ + public function testGetClassWhileNamespaceContainsClassName() { - /* - * Class with namespace containing name of class (duplicated string) - */ - if (class_exists('Symfony\Bundle\SecurityBundle\SecurityBundle')) { - self::assertEquals( - 'Symfony\Bundle\SecurityBundle\SecurityBundle', - Reflection::getClassName('Symfony\Bundle\SecurityBundle\SecurityBundle') - ); + self::assertEquals( + 'Meritoo\Common\Collection\Collection', + Reflection::getClassName(Collection::class) + ); - self::assertEquals( - 'SecurityBundle', - Reflection::getClassName('Symfony\Bundle\SecurityBundle\SecurityBundle', true) - ); - } + self::assertEquals( + 'Collection', + Reflection::getClassName(Collection::class, true) + ); } public function testGetClassNamespaceNotExistingClass() @@ -116,17 +114,15 @@ class ReflectionTest extends BaseTestCase ])); } - public function testGetClassNamespaceDuplicatedName() + /** + * A case when namespace of class contains name of class (name of class is duplicated, occurs twice) + */ + public function testGetClassNamespaceWhileNamespaceContainsClassName() { - /* - * Class with namespace containing name of class (duplicated string) - */ - if (class_exists('Symfony\Bundle\SecurityBundle\SecurityBundle')) { - self::assertEquals( - 'Symfony\Bundle\SecurityBundle', - Reflection::getClassNamespace('Symfony\Bundle\SecurityBundle\SecurityBundle') - ); - } + self::assertEquals( + 'Meritoo\Common\Collection', + Reflection::getClassNamespace(Collection::class) + ); } /** From 10bf198df5b706590b2ecb5acff5e08d28fab646 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 11:54:36 +0200 Subject: [PATCH 009/137] Phing > fix "This task requires the PHP_CodeSniffer package installed and available on the include path" bug > make compatible with PHPUnit 8.0 (and PHP 7.2+) --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3fc63ba..25d20c5 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "phpmd/phpmd": "^2.6", "phpunit/phpunit": "^8.0", "sebastian/phpcpd": "^4.1", - "squizlabs/php_codesniffer": "^3.4" + "squizlabs/php_codesniffer": " ^2.9" }, "autoload": { "psr-4": { From 7ddfcf6946b099b8bd3f621f6e2714cdc83802b5 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 12:02:08 +0200 Subject: [PATCH 010/137] .gitignore > ignore PHPUnit's results cache (related to PHPUnit 8.0) --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index cb92a06..cdd7d7b 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ ### PHPUnit # ------------------------------------------------------------------------------ /phpunit.xml +/.phpunit.result.cache # ------------------------------------------------------------------------------ From 1b4577cc8a00a6543a96adb88b45f4a835bbd02c Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 12:03:53 +0200 Subject: [PATCH 011/137] Fix coding standards (using PHP Coding Standards Fixer) --- src/Utilities/Arrays.php | 6 +++--- src/Utilities/Date.php | 2 +- src/Utilities/QueryBuilderUtility.php | 4 ++-- src/Utilities/Reflection.php | 2 +- tests/Utilities/QueryBuilderUtilityTest.php | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Utilities/Arrays.php b/src/Utilities/Arrays.php index f994950..d976226 100644 --- a/src/Utilities/Arrays.php +++ b/src/Utilities/Arrays.php @@ -1506,7 +1506,7 @@ class Arrays * * @param array $array The array to verify * @param mixed $element The element who index / key is needed - * @return bool|null|mixed + * @return bool|mixed|null */ public static function getIndexOf(array $array, $element) { @@ -1594,7 +1594,7 @@ class Arrays * * @param array $array The array with elements * @param mixed $element Element for who next element should be returned - * @return null|mixed + * @return mixed|null */ public static function getNextElement(array $array, $element) { @@ -1606,7 +1606,7 @@ class Arrays * * @param array $array The array with elements * @param mixed $element Element for who previous element should be returned - * @return null|mixed + * @return mixed|null */ public static function getPreviousElement(array $array, $element) { diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index b6f33c4..8b2afdb 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -68,7 +68,7 @@ class Date * * @param int $period The period, type of period. One of DatePeriod class constants, e.g. DatePeriod::LAST_WEEK. * @throws Exception - * @return null|DatePeriod + * @return DatePeriod|null */ public static function getDatesForPeriod($period) { diff --git a/src/Utilities/QueryBuilderUtility.php b/src/Utilities/QueryBuilderUtility.php index 0e87ed1..69cc89c 100644 --- a/src/Utilities/QueryBuilderUtility.php +++ b/src/Utilities/QueryBuilderUtility.php @@ -27,7 +27,7 @@ class QueryBuilderUtility * If null is returned, alias was not found. * * @param QueryBuilder $queryBuilder The query builder to retrieve root alias - * @return null|string + * @return string|null */ public static function getRootAlias(QueryBuilder $queryBuilder) { @@ -52,7 +52,7 @@ class QueryBuilderUtility * * @param QueryBuilder $queryBuilder The query builder to verify * @param string $property Name of property that maybe is joined - * @return null|string + * @return string|null */ public static function getJoinedPropertyAlias(QueryBuilder $queryBuilder, $property) { diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index c3fbafe..fb8e3fe 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -577,7 +577,7 @@ class Reflection * @param string $property Name of the property * @param int $filter (optional) Filter of properties. Uses \ReflectionProperty class constants. * By default all properties are allowed / processed. - * @return null|\ReflectionProperty + * @return \ReflectionProperty|null */ public static function getProperty($class, $property, $filter = null) { diff --git a/tests/Utilities/QueryBuilderUtilityTest.php b/tests/Utilities/QueryBuilderUtilityTest.php index 2b6894c..3181a35 100644 --- a/tests/Utilities/QueryBuilderUtilityTest.php +++ b/tests/Utilities/QueryBuilderUtilityTest.php @@ -33,7 +33,7 @@ class QueryBuilderUtilityTest extends BaseTestCase /** * @param QueryBuilder $queryBuilder The query builder to retrieve root alias - * @param null|string $rootAlias Expected root alias of given query builder + * @param string|null $rootAlias Expected root alias of given query builder * * @dataProvider provideQueryBuilderAndRootAlias */ @@ -45,7 +45,7 @@ class QueryBuilderUtilityTest extends BaseTestCase /** * @param QueryBuilder $queryBuilder The query builder to verify * @param string $propertyName Name of property that maybe is joined - * @param null|string $propertyAlias Expected alias of given property joined in given query builder + * @param string|null $propertyAlias Expected alias of given property joined in given query builder * * @dataProvider provideQueryBuilderAndPropertyAlias */ From 87249aa30bc5086a0aace64a7d39b5617751382e Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 13:12:04 +0200 Subject: [PATCH 012/137] TravisCI > run using PHP 7.2 & 7.3 > make compatible with PHP 7.2+ --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index f1bd310..67bef66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,8 @@ language: php php: - - 5.6 - - 7.0 - - 7.1 - 7.2 + - 7.3 before_install: - sudo locale-gen de_DE.UTF-8 es_ES.UTF-8 en_GB.UTF-8 en_US.UTF-8 fr_FR.UTF-8 it_IT.UTF-8 pl_PL.UTF-8 ru_RU.UTF-8 From 8a94241eb802630a9cd80ff61891100bf8530fbf Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 15:46:02 +0200 Subject: [PATCH 013/137] Regex > make compatible with PHP 7.3 Tests > Regex > fix "preg_match(): Compilation failed: invalid range in character class at offset 4" bug --- src/Utilities/Regex.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index 3f8f78b..703c540 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -25,7 +25,7 @@ class Regex * @var array */ private static $patterns = [ - 'email' => '/^[\w-.]{2,}@[\w-]+\.[\w]{2,}+$/', + 'email' => '/^[\w\-.]{2,}@[\w\-]+\.[\w]{2,}+$/', 'phone' => '/^\+?[0-9 ]+$/', 'camelCasePart' => '/([a-z]|[A-Z]){1}[a-z]*/', 'urlProtocol' => '/^([a-z]+:\/\/)', From 0b74f8da6f53c172bb6ad9d223e12ae88a44dfda Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 20:18:23 +0200 Subject: [PATCH 014/137] Template with placeholders that may be filled by real data --- docs/Value-Objects.md | 49 +++- .../Template/InvalidContentException.php | 36 +++ .../Template/NotEnoughValuesException.php | 39 ++++ src/ValueObject/Template.php | 151 ++++++++++++ src/ValueObject/Version.php | 2 +- .../Template/InvalidContentExceptionTest.php | 71 ++++++ .../Template/NotEnoughValuesExceptionTest.php | 85 +++++++ tests/ValueObject/TemplateTest.php | 215 ++++++++++++++++++ 8 files changed, 645 insertions(+), 3 deletions(-) create mode 100644 src/Exception/ValueObject/Template/InvalidContentException.php create mode 100644 src/Exception/ValueObject/Template/NotEnoughValuesException.php create mode 100644 src/ValueObject/Template.php create mode 100644 tests/Exception/ValueObject/Template/InvalidContentExceptionTest.php create mode 100644 tests/Exception/ValueObject/Template/NotEnoughValuesExceptionTest.php create mode 100644 tests/ValueObject/TemplateTest.php diff --git a/docs/Value-Objects.md b/docs/Value-Objects.md index 0d2f6ef..a85e7a2 100644 --- a/docs/Value-Objects.md +++ b/docs/Value-Objects.md @@ -239,6 +239,51 @@ $size->setSeparator('X'); $asString2 = (string)$size; // "200X100" ``` +### Template + +##### Namespace + +`Meritoo\Common\ValueObject\Template` + +##### Info + +Template with placeholders that may be filled by real data. Contains properties: +1. `$content` - raw string with placeholders (content of the template) + +##### New instance + +New instance can be created using constructor: + +```php +new Template('First name: %first_name%'); +``` + +Each placeholder should be wrapped by `%` character, e.g. `%first_name%`. If content of template is an empty string or does not contain 1 placeholder at least, an `Meritoo\Common\Exception\ValueObject\Template\InvalidContentException` exception will be thrown. + +Examples of invalid content of template: + +```php +new Template(''); // An empty string +new Template('test'); // Without placeholders +new Template('This is %test'); // With starting tag only (invalid placeholder) +``` + +##### Methods + +Has 1 public method: `fill(array $values)`. Returns content of the template filled with given values (by replacing placeholders with their proper values). + +Example of usage: + +```php +$template = new Template('My name is %name% and I am %profession%'); +$result = $template->fill([ + 'name' => 'Jane', + 'profession' => 'photographer', +]); // "My name is Jane and I am photographer" +``` + +Throws an `Meritoo\Common\Exception\ValueObject\Template\NotEnoughValuesException` exception if there is not enough values (iow. more placeholders than values). + ### Version ##### Namespace @@ -263,13 +308,13 @@ New instance can be created using: ``` 2. Static methods: - 1. `fromArray()` - creates new instance using given version as array + 1. `fromArray(array $version)` - creates new instance using given version as array ```php Version::fromArray([1, 0, 2]); ``` - 2. `fromString()` - creates new instance using given version as string: + 2. `fromString(string $version)` - creates new instance using given version as string: ```php Version::fromString('1.0.2'); diff --git a/src/Exception/ValueObject/Template/InvalidContentException.php b/src/Exception/ValueObject/Template/InvalidContentException.php new file mode 100644 index 0000000..c9fb140 --- /dev/null +++ b/src/Exception/ValueObject/Template/InvalidContentException.php @@ -0,0 +1,36 @@ + + * @copyright Meritoo + */ +class InvalidContentException extends Exception +{ + /** + * Creates an exception + * + * @param string $content Invalid content of template + * @return InvalidContentException + */ + public static function create(string $content): InvalidContentException + { + $template = 'Content of template \'%s\' is invalid. Did you use string with 1 placeholder at least?'; + $message = sprintf($template, $content); + + return new static($message); + } +} diff --git a/src/Exception/ValueObject/Template/NotEnoughValuesException.php b/src/Exception/ValueObject/Template/NotEnoughValuesException.php new file mode 100644 index 0000000..3ff696b --- /dev/null +++ b/src/Exception/ValueObject/Template/NotEnoughValuesException.php @@ -0,0 +1,39 @@ + + * @copyright Meritoo + */ +class NotEnoughValuesException extends Exception +{ + /** + * Creates an exception + * + * @param string $content Invalid content of template + * @param int $valuesCount Count of values + * @param int $placeholdersCount Count of placeholders + * @return NotEnoughValuesException + */ + public static function create(string $content, int $valuesCount, int $placeholdersCount): NotEnoughValuesException + { + $template = 'Not enough values (%d) to fill all placeholders (%d) in template \'%s\'. Did you provide all' + . ' required values?'; + $message = sprintf($template, $valuesCount, $placeholdersCount, $content); + + return new static($message); + } +} diff --git a/src/ValueObject/Template.php b/src/ValueObject/Template.php new file mode 100644 index 0000000..f3aa60f --- /dev/null +++ b/src/ValueObject/Template.php @@ -0,0 +1,151 @@ + + * @copyright Meritoo + */ +class Template +{ + /** + * Tag used at beginning and ending of placeholder + * + * @var string + */ + private const PLACEHOLDER_TAG = '%'; + + /** + * Raw string with placeholders (content of the template) + * + * @var string + */ + private $content; + + /** + * Class constructor + * + * @param string $content Raw string with placeholders (content of the template) + * @throws InvalidContentException + */ + public function __construct(string $content) + { + if (!static::isValid($content)) { + throw InvalidContentException::create($content); + } + + $this->content = $content; + } + + /** + * Returns content of the template filled with given values (by replacing placeholders with their proper values) + * + * @param array $values Pairs of key-value where: key - name of placeholder, value - value of the placeholder + * @throws NotEnoughValuesException + * @return string + */ + public function fill(array $values): string + { + $placeholders = static::getPlaceholders($this->content); + $valuesCount = count($values); + $placeholdersCount = count($placeholders[0]); + + // Oops, not enough values (iow. more placeholders than values) + if ($placeholdersCount > $valuesCount) { + throw NotEnoughValuesException::create($this->content, $valuesCount, $placeholdersCount); + } + + $result = $this->content; + + foreach ($placeholders[0] as $index => $placeholder) { + $placeholderName = $placeholders[1][$index]; + + if (isset($values[$placeholderName])) { + $value = $values[$placeholderName]; + $result = str_replace($placeholder, $value, $result); + } + } + + return $result; + } + + /** + * Returns information if given template is valid + * + * @param string $content Raw string with placeholders to validate (content of the template) + * @return bool + */ + private static function isValid(string $content): bool + { + if ('' === $content) { + return false; + } + + return (bool)preg_match_all(static::getPlaceholderPattern(), $content); + } + + /** + * Returns placeholders of given template + * + * @param string $content Content of template + * @return array + */ + private static function getPlaceholders(string $content): array + { + $result = []; + $matchCount = preg_match_all(static::getPlaceholderPattern(), $content, $result); + + if (false !== $matchCount && 0 < $matchCount) { + foreach ($result as $index => $placeholders) { + $result[$index] = array_unique($placeholders); + } + } + + return $result; + } + + /** + * Returns regular expression that defines format of placeholder + * + * Expectations: + * - surrounded by the placeholder's tags (at beginning and at the end) + * - at least 1 character + * - no placeholder's tag inside name of placeholder + * + * Invalid placeholders: + * - test + * - test% + * - % test% + * + * Valid placeholders: + * - %test% + * - %another_test% + * - %another-test% + * - %anotherTest% + * - %another test% + * + * @return string + */ + private static function getPlaceholderPattern(): string + { + return sprintf( + '/%s([^%s]+)%s/', + static::PLACEHOLDER_TAG, + static::PLACEHOLDER_TAG, + static::PLACEHOLDER_TAG + ); + } +} diff --git a/src/ValueObject/Version.php b/src/ValueObject/Version.php index 55e7cb4..d24bbe3 100644 --- a/src/ValueObject/Version.php +++ b/src/ValueObject/Version.php @@ -108,7 +108,7 @@ class Version * @param string $version The version * @return Version|null */ - public static function fromString($version) + public static function fromString(string $version) { $version = trim($version); diff --git a/tests/Exception/ValueObject/Template/InvalidContentExceptionTest.php b/tests/Exception/ValueObject/Template/InvalidContentExceptionTest.php new file mode 100644 index 0000000..e5bab54 --- /dev/null +++ b/tests/Exception/ValueObject/Template/InvalidContentExceptionTest.php @@ -0,0 +1,71 @@ + + * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\ValueObject\Template\InvalidContentException + */ +class InvalidContentExceptionTest extends BaseTestCase +{ + public function testConstructorVisibilityAndArguments(): void + { + static::assertConstructorVisibilityAndArguments( + InvalidContentException::class, + OopVisibilityType::IS_PUBLIC, + 3 + ); + } + + /** + * @param string $description Description of test + * @param string $content Invalid content of template + * @param string $expectedMessage Expected exception's message + * + * @dataProvider provideContent + */ + public function testCreate(string $description, string $content, string $expectedMessage): void + { + $exception = InvalidContentException::create($content); + static::assertSame($expectedMessage, $exception->getMessage(), $description); + } + + public function provideContent(): ?Generator + { + $template = 'Content of template \'%s\' is invalid. Did you use string with 1 placeholder at least?'; + + yield[ + 'An empty string', + '', + sprintf($template, ''), + ]; + + yield[ + 'Simple string', + 'Lorem ipsum', + sprintf($template, 'Lorem ipsum'), + ]; + + yield[ + 'One sentence', + 'Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh.', + sprintf($template, 'Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh.'), + ]; + } +} diff --git a/tests/Exception/ValueObject/Template/NotEnoughValuesExceptionTest.php b/tests/Exception/ValueObject/Template/NotEnoughValuesExceptionTest.php new file mode 100644 index 0000000..533fb55 --- /dev/null +++ b/tests/Exception/ValueObject/Template/NotEnoughValuesExceptionTest.php @@ -0,0 +1,85 @@ + + * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\ValueObject\Template\NotEnoughValuesException + */ +class NotEnoughValuesExceptionTest extends BaseTestCase +{ + public function testConstructorVisibilityAndArguments(): void + { + static::assertConstructorVisibilityAndArguments( + NotEnoughValuesException::class, + OopVisibilityType::IS_PUBLIC, + 3 + ); + } + + /** + * @param string $description Description of test + * @param string $content Invalid content of template + * @param int $valuesCount Count of values + * @param int $placeholdersCount Count of placeholders + * @param string $expectedMessage Expected exception's message + * + * @dataProvider provideContentAndValuesPlaceholdersCount + */ + public function testCreate( + string $description, + string $content, + int $valuesCount, + int $placeholdersCount, + string $expectedMessage + ): void { + $exception = NotEnoughValuesException::create($content, $valuesCount, $placeholdersCount); + static::assertSame($expectedMessage, $exception->getMessage(), $description); + } + + public function provideContentAndValuesPlaceholdersCount(): ?Generator + { + $template = 'Not enough values (%d) to fill all placeholders (%d) in template \'%s\'. Did you provide all' + . ' required values?'; + + yield[ + 'An empty string', + '', + 3, + 1, + sprintf($template, 3, 1, ''), + ]; + + yield[ + 'Simple string', + 'Lorem ipsum', + 1, + 4, + sprintf($template, 1, 4, 'Lorem ipsum'), + ]; + + yield[ + 'One sentence', + 'Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh.', + 5, + 0, + sprintf($template, 5, 0, 'Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh.'), + ]; + } +} diff --git a/tests/ValueObject/TemplateTest.php b/tests/ValueObject/TemplateTest.php new file mode 100644 index 0000000..6de3828 --- /dev/null +++ b/tests/ValueObject/TemplateTest.php @@ -0,0 +1,215 @@ + + * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\ValueObject\Template + */ +class TemplateTest extends BaseTestCase +{ + public function testConstructor(): void + { + static::assertConstructorVisibilityAndArguments( + Template::class, + OopVisibilityType::IS_PUBLIC, + 1, + 1 + ); + } + + /** + * @param string $content Raw string with placeholders (content of the template) + * @param string $exceptionMessage Expected message of exception + * + * @dataProvider provideInvalidContent + */ + public function testIsValidUsingInvalidContent(string $content, string $exceptionMessage): void + { + $this->expectException(InvalidContentException::class); + $this->expectExceptionMessage($exceptionMessage); + + new Template($content); + } + + /** + * @param Template $template Template to fill + * @param array $values Pairs of key-value where: key - name of placeholder, value - value of the + * placeholder + * @param string $exceptionMessage Expected message of exception + * + * @dataProvider provideTemplateToFillUsingNotEnoughValues + */ + public function testFillUsingNotEnoughValues(Template $template, array $values, string $exceptionMessage): void + { + $this->expectException(NotEnoughValuesException::class); + $this->expectExceptionMessage($exceptionMessage); + + $template->fill($values); + } + + /** + * @param string $description Description of test + * @param Template $template Template to fill + * @param array $values Pairs of key-value where: key - name of placeholder, value - value of the + * placeholder + * @param string $expected Expected result + * + * @dataProvider provideTemplateToFill + */ + public function testFill(string $description, Template $template, array $values, string $expected): void + { + static::assertSame($expected, $template->fill($values), $description); + } + + public function provideInvalidContent(): ?Generator + { + $template = 'Content of template \'%s\' is invalid. Did you use string with 1 placeholder at least?'; + + yield[ + 'An empty string' => '', + sprintf($template, ''), + ]; + + yield[ + 'Without placeholders' => 'test', + sprintf($template, 'test'), + ]; + + yield[ + 'With starting tag only (invalid placeholder)' => 'This is %test', + sprintf($template, 'This is %test'), + ]; + + yield[ + 'With ending tag only (invalid placeholder)' => 'This is test%', + sprintf($template, 'This is test%'), + ]; + } + + public function provideTemplateToFillUsingNotEnoughValues(): ?Generator + { + $template = 'Not enough values (%d) to fill all placeholders (%d) in template \'%s\'. Did you provide all' + . ' required values?'; + + yield[ + new Template('%test%'), + [], + sprintf( + $template, + 0, + 1, + '%test%' + ), + ]; + + yield[ + new Template('%test1% - %test2%'), + [ + 'test1' => 123, + ], + sprintf( + $template, + 1, + 2, + '%test1% - %test2%' + ), + ]; + } + + public function provideTemplateToFill(): ?Generator + { + yield[ + 'Template with 1 placeholder, but incorrect values', + new Template('%test%'), + [ + 'something' => 123, + ], + '%test%', + ]; + + yield[ + 'Template with 1 placeholder', + new Template('%test%'), + [ + 'test' => 123, + ], + '123', + ]; + + yield[ + 'Template with 1 placeholder, but more values', + new Template('%test%'), + [ + 'test' => 123, + 'anotherTest' => 456, + ], + '123', + ]; + + yield[ + 'Template with 2 placeholders', + new Template('My name is %name% and I am %profession%'), + [ + 'name' => 'Jane', + 'profession' => 'photographer', + ], + 'My name is Jane and I am photographer', + ]; + + yield[ + 'Template with 2 placeholders, but more values', + new Template('My name is %name% and I am %profession%'), + [ + 'name' => 'Jane', + 'test-test' => 123, + 'profession' => 'photographer', + 'anotherTest' => 456, + ], + 'My name is Jane and I am photographer', + ]; + + yield[ + 'Template with 2 placeholders that contains space', + new Template('My name is %first name% %last name% and I live in %current location%'), + [ + 'first name' => 'Jane', + 'last name' => 'Brown', + 'current location' => 'NY, USA', + ], + 'My name is Jane Brown and I live in NY, USA', + ]; + + yield[ + 'Template with 2 placeholders that contains space, but more values', + new Template('My name is %first name% %last name% and I live in %current location%'), + [ + 'first name' => 'Jane', + 'profession' => 'photographer', + 'last name' => 'Brown', + 'test-test' => 123, + 'anotherTest' => 456, + 'current location' => 'NY, USA', + ], + 'My name is Jane Brown and I live in NY, USA', + ]; + } +} From faf1da613434cf88e2332a03a04236b1edf529b0 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 21:08:11 +0200 Subject: [PATCH 015/137] Collection/storage of templates --- README.md | 2 +- docs/Base-test-case.md | 9 +- .../Collection.md} | 27 ++- docs/Collection/Templates.md | 65 ++++++ docs/Exceptions.md | 9 +- docs/Static-methods.md | 9 +- docs/Static-methods/Arrays.md | 9 +- docs/Static-methods/Regex.md | 9 +- docs/Value-Objects.md | 9 +- src/Collection/Templates.php | 65 ++++++ .../Template/TemplateNotFoundException.php | 36 ++++ tests/Collection/TemplatesTest.php | 188 ++++++++++++++++++ .../TemplateNotFoundExceptionTest.php | 71 +++++++ 13 files changed, 473 insertions(+), 35 deletions(-) rename docs/{Collection-of-elements.md => Collection/Collection.md} (63%) create mode 100644 docs/Collection/Templates.md create mode 100644 src/Collection/Templates.php create mode 100644 src/Exception/ValueObject/Template/TemplateNotFoundException.php create mode 100644 tests/Collection/TemplatesTest.php create mode 100644 tests/Exception/ValueObject/Template/TemplateNotFoundExceptionTest.php diff --git a/README.md b/README.md index b6dd475..1b83a0c 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ composer require meritoo/common-library # Usage 1. [Base test case (with common methods and data providers)](docs/Base-test-case.md) -2. [Collection of elements](docs/Collection-of-elements.md) +2. [Collection of elements](docs/Collection/Collection.md) 3. [Exceptions](docs/Static-methods.md) 4. [Static methods](docs/Static-methods.md) 1. [Arrays](docs/Static-methods/Arrays.md) diff --git a/docs/Base-test-case.md b/docs/Base-test-case.md index b35c744..bb8ac79 100644 --- a/docs/Base-test-case.md +++ b/docs/Base-test-case.md @@ -45,11 +45,12 @@ class MimeTypesTest extends BaseTestCase # More 1. [**Base test case (with common methods and data providers)**](Base-test-case.md) -2. [Collection of elements](Collection-of-elements.md) -3. [Exceptions](Exceptions.md) -4. [Static methods](Static-methods.md) +2. [Collection of elements](Collection/Collection.md) +3. [Templates](Collection/Templates.md) +4. [Exceptions](Exceptions.md) +5. [Static methods](Static-methods.md) 1. [Arrays](Static-methods/Arrays.md) 2. [Regex](Static-methods/Regex.md) -5. [Value Objects](Value-Objects.md) +6. [Value Objects](Value-Objects.md) [‹ Back to `Readme`](../README.md) diff --git a/docs/Collection-of-elements.md b/docs/Collection/Collection.md similarity index 63% rename from docs/Collection-of-elements.md rename to docs/Collection/Collection.md index 2493afc..c2f8f61 100644 --- a/docs/Collection-of-elements.md +++ b/docs/Collection/Collection.md @@ -2,9 +2,15 @@ Common and useful classes, methods, exceptions etc. -# Collection of elements +# Collection -Located here: `Meritoo\Common\Collection\Collection`. It's a set of some elements, e.g. objects. It's iterable and countable. Provides very useful methods. Some of them: +### Namespace + +`Meritoo\Common\Collection\Collection` + +### Info + +It's a set of some elements, e.g. objects. It's iterable and countable. Provides very useful methods. Some of them: - `getFirst()` - returns the first element in the collection - `getLast()` - returns the last element in the collection - `isEmpty()` - returns information if collection is empty @@ -42,12 +48,13 @@ var_dump($simpleCollection->has('dolor')); // bool(true) # More -1. [Base test case (with common methods and data providers)](Base-test-case.md) -2. [**Collection of elements**](Collection-of-elements.md) -3. [Exceptions](Exceptions.md) -4. [Static methods](Static-methods.md) - 1. [Arrays](Static-methods/Arrays.md) - 2. [Regex](Static-methods/Regex.md) -5. [Value Objects](Value-Objects.md) +1. [Base test case (with common methods and data providers)](../Base-test-case.md) +2. [**Collection of elements**](Collection.md) +3. [Templates](Templates.md) +4. [Exceptions](../Exceptions.md) +5. [Static methods](../Static-methods.md) + 1. [Arrays](../Static-methods/Arrays.md) + 2. [Regex](../Static-methods/Regex.md) +6. [Value Objects](../Value-Objects.md) -[‹ Back to `Readme`](../README.md) +[‹ Back to `Readme`](../../README.md) diff --git a/docs/Collection/Templates.md b/docs/Collection/Templates.md new file mode 100644 index 0000000..c4fa36a --- /dev/null +++ b/docs/Collection/Templates.md @@ -0,0 +1,65 @@ +# Meritoo Common Library + +Common and useful classes, methods, exceptions etc. + +# Templates + +### Namespace + +`Meritoo\Common\Collection\Templates` + +### Info + +Collection/storage of templates, instance of `Meritoo\Common\ValueObject\Template` class. + +##### New instance + +New instance can be created using: + +1. Constructor: + + ```php + new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), + ]); + ``` + +2. Static method `fromArray(array $templates)` - creates and returns the collection from given array + + ```php + Templates::fromArray([ + 'first' => 'First name: %first_name%', + 'last' => 'Last name: %last_name%', + ]); + ``` + +##### Methods + +Has all methods of parent class `Meritoo\Common\Collection\Collection` + `findTemplate(string $index)` method that finds and returns template with given index. + +Example of usage: + +```php +$templates = new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), +]); + +$template = $templates->findTemplate('first'); // new Template('First name: %first_name%') +``` + +Throws an `Meritoo\Common\Exception\ValueObject\Template\TemplateNotFoundException` exception if template with given index was not found. + +# More + +1. [Base test case (with common methods and data providers)](../Base-test-case.md) +2. [Collection of elements](Collection.md) +3. [**Templates**](Templates.md) +4. [Exceptions](../Exceptions.md) +5. [Static methods](../Static-methods.md) + 1. [Arrays](../Static-methods/Arrays.md) + 2. [Regex](../Static-methods/Regex.md) +6. [Value Objects](../Value-Objects.md) + +[‹ Back to `Readme`](../../README.md) diff --git a/docs/Exceptions.md b/docs/Exceptions.md index 14d7021..de4a570 100644 --- a/docs/Exceptions.md +++ b/docs/Exceptions.md @@ -54,11 +54,12 @@ class UnknownSimpleTypeException extends UnknownTypeException # More 1. [Base test case (with common methods and data providers)](Base-test-case.md) -2. [Collection of elements](Collection-of-elements.md) -3. [**Exceptions**](Exceptions.md) -4. [Static methods](Static-methods.md) +2. [Collection of elements](Collection/Collection.md) +3. [Templates](Collection/Templates.md) +4. [**Exceptions**](Exceptions.md) +5. [Static methods](Static-methods.md) 1. [Arrays](Static-methods/Arrays.md) 2. [Regex](Static-methods/Regex.md) -5. [Value Objects](Value-Objects.md) +6. [Value Objects](Value-Objects.md) [‹ Back to `Readme`](../README.md) diff --git a/docs/Static-methods.md b/docs/Static-methods.md index d1d2227..f1f0f7a 100644 --- a/docs/Static-methods.md +++ b/docs/Static-methods.md @@ -16,11 +16,12 @@ var_dump($firstElement); // string(5) "lorem" # More 1. [Base test case (with common methods and data providers)](Base-test-case.md) -2. [Collection of elements](Collection-of-elements.md) -3. [Exceptions](Exceptions.md) -4. [**Static methods**](Static-methods.md) +2. [Collection of elements](Collection/Collection.md) +3. [Templates](Collection/Templates.md) +4. [Exceptions](Exceptions.md) +5. [**Static methods**](Static-methods.md) 1. [Arrays](Static-methods/Arrays.md) 2. [Regex](Static-methods/Regex.md) -5. [Value Objects](Value-Objects.md) +6. [Value Objects](Value-Objects.md) [‹ Back to `Readme`](../README.md) diff --git a/docs/Static-methods/Arrays.md b/docs/Static-methods/Arrays.md index b798505..dda85ec 100644 --- a/docs/Static-methods/Arrays.md +++ b/docs/Static-methods/Arrays.md @@ -68,11 +68,12 @@ File: `src/Utilities/Arrays.php` # More 1. [Base test case (with common methods and data providers)](../Base-test-case.md) -2. [Collection of elements](../Collection-of-elements.md) -3. [Exceptions](../Exceptions.md) -4. [Static methods](../Static-methods.md) +2. [Collection of elements](../Collection/Collection.md) +3. [Templates](../Collection/Templates.md) +4. [Exceptions](../Exceptions.md) +5. [Static methods](../Static-methods.md) 1. [**Arrays**](Arrays.md) 2. [Regex](Regex.md) -5. [Value Objects](../Value-Objects.md) +6. [Value Objects](../Value-Objects.md) [‹ Back to `Readme`](../../README.md) diff --git a/docs/Static-methods/Regex.md b/docs/Static-methods/Regex.md index e4ec57c..14998a2 100644 --- a/docs/Static-methods/Regex.md +++ b/docs/Static-methods/Regex.md @@ -35,11 +35,12 @@ File: `src/Utilities/Regex.php` # More 1. [Base test case (with common methods and data providers)](../Base-test-case.md) -2. [Collection of elements](../Collection-of-elements.md) -3. [Exceptions](../Exceptions.md) -4. [Static methods](../Static-methods.md) +2. [Collection of elements](../Collection/Collection.md) +3. [Templates](../Collection/Templates.md) +4. [Exceptions](../Exceptions.md) +5. [Static methods](../Static-methods.md) 1. [Arrays](../Static-methods/Arrays.md) 2. [**Regex**](Regex.md) -5. [Value Objects](../Value-Objects.md) +6. [Value Objects](../Value-Objects.md) [‹ Back to `Readme`](../../README.md) diff --git a/docs/Value-Objects.md b/docs/Value-Objects.md index a85e7a2..fa8d6ec 100644 --- a/docs/Value-Objects.md +++ b/docs/Value-Objects.md @@ -338,11 +338,12 @@ $asString = (string)$version; // "1.0.2" # More 1. [Base test case (with common methods and data providers)](Base-test-case.md) -2. [Collection of elements](Collection-of-elements.md) -3. [Exceptions](Exceptions.md) -4. [Static methods](Static-methods.md) +2. [Collection of elements](Collection/Collection.md) +3. [Templates](Collection/Templates.md) +4. [Exceptions](Exceptions.md) +5. [Static methods](Static-methods.md) 1. [Arrays](Static-methods/Arrays.md) 2. [Regex](Static-methods/Regex.md) -5. [**Value Objects**](Value-Objects.md) +6. [**Value Objects**](Value-Objects.md) [‹ Back to `Readme`](../README.md) diff --git a/src/Collection/Templates.php b/src/Collection/Templates.php new file mode 100644 index 0000000..cbca41a --- /dev/null +++ b/src/Collection/Templates.php @@ -0,0 +1,65 @@ + + * @copyright Meritoo + */ +class Templates extends Collection +{ + /** + * Finds and returns template with given index + * + * @param string $index Index that contains required template + * @throws TemplateNotFoundException + * @return Template + */ + public function findTemplate(string $index): Template + { + /* @var Template $template */ + $template = $this->getByIndex($index); + + if ($template instanceof Template) { + return $template; + } + + // Oops, template not found + throw TemplateNotFoundException::create($index); + } + + /** + * Creates and returns the collection from given array + * + * @param array $templates Pairs of key-value where: key - template's index, value - template's content + * @return Templates + */ + public static function fromArray(array $templates): Templates + { + // No templates. Nothing to do. + if (empty($templates)) { + return new static(); + } + + $result = new static(); + + foreach ($templates as $index => $template) { + $result->add(new Template($template), $index); + } + + return $result; + } +} diff --git a/src/Exception/ValueObject/Template/TemplateNotFoundException.php b/src/Exception/ValueObject/Template/TemplateNotFoundException.php new file mode 100644 index 0000000..aee1843 --- /dev/null +++ b/src/Exception/ValueObject/Template/TemplateNotFoundException.php @@ -0,0 +1,36 @@ + + * @copyright Meritoo + */ +class TemplateNotFoundException extends Exception +{ + /** + * Creates the exception + * + * @param string $index Index that should contain template, but it was not found + * @return TemplateNotFoundException + */ + public static function create(string $index): TemplateNotFoundException + { + $template = 'Template with \'%s\' index was not found. Did you provide all required templates?'; + $message = sprintf($template, $index); + + return new static($message); + } +} diff --git a/tests/Collection/TemplatesTest.php b/tests/Collection/TemplatesTest.php new file mode 100644 index 0000000..2198728 --- /dev/null +++ b/tests/Collection/TemplatesTest.php @@ -0,0 +1,188 @@ + + * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Collection\Templates + */ +class TemplatesTest extends BaseTestCase +{ + public function testConstructor(): void + { + static::assertConstructorVisibilityAndArguments( + Templates::class, + OopVisibilityType::IS_PUBLIC, + 1 + ); + } + + /** + * @param string $description Description of test + * @param array $templates Pairs of key-value where: key - template's index, value - template's content + * @param Templates $expected Expected collection/storage of templates + * + * @dataProvider provideArrayWithTemplates + */ + public function testFromArray(string $description, array $templates, Templates $expected): void + { + static::assertEquals($expected, Templates::fromArray($templates), $description); + } + + public function testFindTemplateUsingEmptyCollection(): void + { + $template = 'Template with \'%s\' index was not found. Did you provide all required templates?'; + $message = sprintf($template, 'test'); + + $this->expectException(TemplateNotFoundException::class); + $this->expectExceptionMessage($message); + + $templates = new Templates(); + $templates->findTemplate('test'); + } + + /** + * @param Templates $templates All templates + * @param string $index Index that contains required template + * @param string $expectedMessage Expected message of exception + * + * @dataProvider provideTemplatesWithNotExistingIndex + */ + public function testFindTemplateUsingNotExistingIndex( + Templates $templates, + string $index, + string $expectedMessage + ): void { + $this->expectException(TemplateNotFoundException::class); + $this->expectExceptionMessage($expectedMessage); + + $templates->findTemplate($index); + } + + /** + * @param string $description Description of test + * @param Templates $templates All templates + * @param string $index Index that contains required template + * @param Template $expected Expected template + * + * @dataProvider provideTemplatesToFind + */ + public function testFindTemplate(string $description, Templates $templates, string $index, Template $expected): void + { + static::assertEquals($expected, $templates->findTemplate($index), $description); + } + + public function provideArrayWithTemplates(): ?Generator + { + yield[ + 'An empty array', + [], + new Templates(), + ]; + + yield[ + 'Number-based indexes', + [ + 'First name: %first_name%', + 'Last name: %last_name%', + ], + new Templates([ + new Template('First name: %first_name%'), + new Template('Last name: %last_name%'), + ]), + ]; + + yield[ + 'String-based indexes', + [ + 'first' => 'First name: %first_name%', + 'last' => 'Last name: %last_name%', + ], + new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), + ]), + ]; + } + + public function provideTemplatesWithNotExistingIndex(): ?Generator + { + $template = 'Template with \'%s\' index was not found. Did you provide all required templates?'; + + yield[ + new Templates(), + 'test', + sprintf($template, 'test'), + ]; + + yield[ + new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), + ]), + 'test', + sprintf($template, 'test'), + ]; + + yield[ + new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), + ]), + '', + sprintf($template, ''), + ]; + + yield[ + new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), + ]), + '4', + sprintf($template, 4), + ]; + } + + public function provideTemplatesToFind(): ?Generator + { + yield[ + '2 templates only', + new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), + ]), + 'first', + new Template('First name: %first_name%'), + ]; + + yield[ + 'Different indexes', + new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), + 1 => new Template('Hi %name%, how are you?'), + '2' => new Template('Your score is: %score%'), + ]), + '1', + new Template('Hi %name%, how are you?'), + ]; + } +} diff --git a/tests/Exception/ValueObject/Template/TemplateNotFoundExceptionTest.php b/tests/Exception/ValueObject/Template/TemplateNotFoundExceptionTest.php new file mode 100644 index 0000000..3c2982d --- /dev/null +++ b/tests/Exception/ValueObject/Template/TemplateNotFoundExceptionTest.php @@ -0,0 +1,71 @@ + + * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\ValueObject\Template\TemplateNotFoundException + */ +class TemplateNotFoundExceptionTest extends BaseTestCase +{ + public function testConstructor(): void + { + static::assertConstructorVisibilityAndArguments( + TemplateNotFoundException::class, + OopVisibilityType::IS_PUBLIC, + 3 + ); + } + + /** + * @param string $description Description of test + * @param string $index Index that should contain template, but it was not found + * @param TemplateNotFoundException $expected Expected exception + * + * @dataProvider provideIndexAndException + */ + public function testCreate(string $description, string $index, TemplateNotFoundException $expected): void + { + $created = TemplateNotFoundException::create($index); + static::assertEquals($expected, $created, $description); + } + + public function provideIndexAndException(): ?Generator + { + $template = 'Template with \'%s\' index was not found. Did you provide all required templates?'; + + yield[ + 'An empty string', + '', + new TemplateNotFoundException(sprintf($template, '')), + ]; + + yield[ + 'Non-empty string', + 'test', + new TemplateNotFoundException(sprintf($template, 'test')), + ]; + + yield[ + 'Integer', + '2', + new TemplateNotFoundException(sprintf($template, 2)), + ]; + } +} From ed1c9358aaa08f301dad9214975f96e210bc416e Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 21:16:25 +0200 Subject: [PATCH 016/137] Changelog > update > enter latest modifications --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bd054b..e013489 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ Common and useful classes, methods, exceptions etc. +# 1.0.1 + +1. Regex > make compatible with PHP 7.3 Tests > Regex > fix "preg_match(): Compilation failed: invalid range in +character class at offset 4" bug +2. Collection/storage of templates +3. Template with placeholders that may be filled by real data + # 1.0.0 1. Composer > support/require PHP 7.2+ (instead of 5.6+) From a4d6a1c78555c37124a5e90b77bccec8f5215ab5 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 21:16:40 +0200 Subject: [PATCH 017/137] Bump version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3eefcb9..7dea76e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +1.0.1 From a93355f2c841e6a27e20c276d27421a5577e8120 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 2 Apr 2019 21:40:31 +0200 Subject: [PATCH 018/137] RenderableInterface > something that may be rendered --- CHANGELOG.md | 1 + src/Renderable/RenderableInterface.php | 31 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/Renderable/RenderableInterface.php diff --git a/CHANGELOG.md b/CHANGELOG.md index e013489..8684758 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Common and useful classes, methods, exceptions etc. character class at offset 4" bug 2. Collection/storage of templates 3. Template with placeholders that may be filled by real data +4. RenderableInterface > something that may be rendered # 1.0.0 diff --git a/src/Renderable/RenderableInterface.php b/src/Renderable/RenderableInterface.php new file mode 100644 index 0000000..de10afa --- /dev/null +++ b/src/Renderable/RenderableInterface.php @@ -0,0 +1,31 @@ + + * @copyright Meritoo + */ +interface RenderableInterface +{ + /** + * Renders this object using given templates + * + * @param Templates $templates Collection/storage of templates that will be required while rendering this and + * related objects, e.g. children of this object + * @return string + */ + public function render(Templates $templates): string; +} From 312e721dc356cc5f08b6ba64ad2f7e9b0f97c511 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 3 Apr 2019 11:18:11 +0200 Subject: [PATCH 019/137] Phing > remove old and unused tools --- CHANGELOG.md | 4 ++++ VERSION | 2 +- composer.json | 3 --- phing/properties.dist | 1 - phing/tests.xml | 32 +------------------------------- 5 files changed, 6 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8684758..e21ced4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Common and useful classes, methods, exceptions etc. +# 1.0.2 + +1. Phing > remove old and unused tools + # 1.0.1 1. Regex > make compatible with PHP 7.3 Tests > Regex > fix "preg_match(): Compilation failed: invalid range in diff --git a/VERSION b/VERSION index 7dea76e..6d7de6e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.1 +1.0.2 diff --git a/composer.json b/composer.json index 25d20c5..c19df0f 100644 --- a/composer.json +++ b/composer.json @@ -22,9 +22,6 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", - "pdepend/pdepend": "^2.5", - "phploc/phploc": "^5.0", - "phpmd/phpmd": "^2.6", "phpunit/phpunit": "^8.0", "sebastian/phpcpd": "^4.1", "squizlabs/php_codesniffer": " ^2.9" diff --git a/phing/properties.dist b/phing/properties.dist index bcb2fb5..796246d 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -50,7 +50,6 @@ dir.tests = ${project.basedir}/tests # dir.build = ${project.basedir}/build dir.reports = ${dir.build}/reports -dir.reports.pdepend = ${dir.reports}/pdepend dir.reports.coverage = ${dir.reports}/phpunit_coverage # Data directories diff --git a/phing/tests.xml b/phing/tests.xml index 92f6190..5883735 100644 --- a/phing/tests.xml +++ b/phing/tests.xml @@ -43,10 +43,7 @@ @@ -72,32 +69,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -116,7 +87,6 @@ - From a90eeed583d14716f2f40cfb1ed1aa3f08ee8552 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 3 Apr 2019 11:21:29 +0200 Subject: [PATCH 020/137] Phing > configuration > minor updates --- CHANGELOG.md | 1 + phing/properties.dist | 4 ++-- phing/tests.xml | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e21ced4..c32cb66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Common and useful classes, methods, exceptions etc. # 1.0.2 1. Phing > remove old and unused tools +2. Phing > configuration > minor updates # 1.0.1 diff --git a/phing/properties.dist b/phing/properties.dist index 796246d..d1aa6d2 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -24,11 +24,11 @@ cache.clearWithWarmup = false # composer.download_command = bash ${project.basedir}/phing/composer-install.sh -# Path to composer executable or downloaded composer.phar file +# Path to Composer executable or downloaded composer.phar file # composer.path = ${project.basedir}/composer.phar -# Path to php executable used by composer +# Path to PHP executable used by Composer # composer.php = php diff --git a/phing/tests.xml b/phing/tests.xml index 5883735..a03b709 100644 --- a/phing/tests.xml +++ b/phing/tests.xml @@ -57,7 +57,7 @@ - + @@ -65,7 +65,7 @@ - + From cecaa65ef6775722cf26f15442912072c6c27aa0 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 3 Apr 2019 12:27:54 +0200 Subject: [PATCH 021/137] Implement Mutation Testing Framework (infection/infection package) --- .gitignore | 6 ++++++ CHANGELOG.md | 1 + composer.json | 1 + docs/Development.md | 40 ++++++++++++++++++++++++++++++++++++++++ infection.json.dist | 13 +++++++++++++ phing/properties.dist | 4 +++- phing/tests.xml | 7 ++++++- 7 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 infection.json.dist diff --git a/.gitignore b/.gitignore index cdd7d7b..a45c104 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,12 @@ /.phpunit.result.cache +# ------------------------------------------------------------------------------ +### Infection +# ------------------------------------------------------------------------------ +/infection.json + + # ------------------------------------------------------------------------------ ### PHP Coding Standards Fixer # ------------------------------------------------------------------------------ diff --git a/CHANGELOG.md b/CHANGELOG.md index c32cb66..78ad0c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Common and useful classes, methods, exceptions etc. 1. Phing > remove old and unused tools 2. Phing > configuration > minor updates +3. Implement Mutation Testing Framework (infection/infection package) # 1.0.1 diff --git a/composer.json b/composer.json index c19df0f..f39c07b 100644 --- a/composer.json +++ b/composer.json @@ -22,6 +22,7 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", + "infection/infection": "^0.11.4", "phpunit/phpunit": "^8.0", "sebastian/phpcpd": "^4.1", "squizlabs/php_codesniffer": " ^2.9" diff --git a/docs/Development.md b/docs/Development.md index 7f60fb0..211e9f4 100644 --- a/docs/Development.md +++ b/docs/Development.md @@ -112,6 +112,46 @@ docker-compose run --rm phpunit --verbose --no-coverage I have to use [squizlabs/php_codesniffer](https://packagist.org/packages/squizlabs/php_codesniffer) `^2.9` instead of `^3.3`, because [Phing doesn't support 3.x PHP_CodeSniffer](https://github.com/phingofficial/phing/issues/716). +# Mutation Tests + +Served by [Infection — Mutation Testing Framework](https://infection.github.io). + +### Running tests + +```bash +docker-compose exec php vendor/bin/infection --threads=5 +``` + +or + +```bash +docker-compose exec php phing -f phing/tests.xml test:infection +``` + +### Result of testing + +##### Terminal + +Example of output: +```bash +125 mutations were generated: + 105 mutants were killed + 3 mutants were not covered by tests + 5 covered mutants were not detected + 0 errors were encountered + 12 time outs were encountered + +Metrics: + Mutation Score Indicator (MSI): 93% + Mutation Code Coverage: 97% + Covered Code MSI: 95% +``` + +##### Stored in `build/reports/infection` directory + +* `build/reports/infection/infection-log.txt` +* `build/reports/infection/summary-log.txt` + # Other Rebuild project and run tests by running command: diff --git a/infection.json.dist b/infection.json.dist new file mode 100644 index 0000000..06b8a4c --- /dev/null +++ b/infection.json.dist @@ -0,0 +1,13 @@ +{ + "timeout": 10, + "source": { + "directories": [ + "src" + ] + }, + "logs": { + "text": "build/reports/infection/infection-log.txt", + "summary": "build/reports/infection/summary-log.txt", + "debug": "build/reports/infection/debug-log.txt" + } +} diff --git a/phing/properties.dist b/phing/properties.dist index d1aa6d2..3a49281 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -77,5 +77,7 @@ tests.database = ${dir.data.temporary}/database.sqlite # Paths of frameworks used to run tests: # - PHPUnit (unit tests) +# - Infection (mutation tests) # -tests.phpunit.command = ./vendor/bin/phpunit --verbose +tests.phpunit.command = ./vendor/bin/phpunit --verbose --no-coverage +tests.mutation.command = ./vendor/bin/infection --threads=5 diff --git a/phing/tests.xml b/phing/tests.xml index a03b709..3f97f01 100644 --- a/phing/tests.xml +++ b/phing/tests.xml @@ -48,7 +48,7 @@ @@ -74,6 +74,11 @@ + + + + + From ca4bf05b38bb0f2d493300c9568094686dab4589 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 3 Apr 2019 12:38:06 +0200 Subject: [PATCH 022/137] Travis CI > run many tasks using Phing (instead of PHPUnit only) --- .travis-php-config.ini | 1 + .travis.yml | 9 +++++++-- CHANGELOG.md | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 .travis-php-config.ini diff --git a/.travis-php-config.ini b/.travis-php-config.ini new file mode 100644 index 0000000..64adbeb --- /dev/null +++ b/.travis-php-config.ini @@ -0,0 +1 @@ +date.timezone = 'Europe/London' diff --git a/.travis.yml b/.travis.yml index 67bef66..d9ce276 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,9 +7,14 @@ php: before_install: - sudo locale-gen de_DE.UTF-8 es_ES.UTF-8 en_GB.UTF-8 en_US.UTF-8 fr_FR.UTF-8 it_IT.UTF-8 pl_PL.UTF-8 ru_RU.UTF-8 - composer global require hirak/prestissimo + - pear channel-discover pear.phing.info install: - - travis_wait 30 composer install -v + - pear install phing/phing + - phpenv rehash + +before_script: + - phpenv config-add .travis-php-config.ini script: - - php ./vendor/bin/phpunit + - phing diff --git a/CHANGELOG.md b/CHANGELOG.md index 78ad0c2..0471507 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Common and useful classes, methods, exceptions etc. 1. Phing > remove old and unused tools 2. Phing > configuration > minor updates 3. Implement Mutation Testing Framework (infection/infection package) +4. Travis CI > run many tasks using Phing (instead of PHPUnit only) # 1.0.1 From 1db4a55e3103d60087a660cbea03d9fd5b4fd428 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 3 Apr 2019 12:41:15 +0200 Subject: [PATCH 023/137] Fix integration with Coveralls (available as the badge in README.md) --- .coveralls.yml | 2 ++ CHANGELOG.md | 1 + composer.json | 1 + phpunit.xml.dist | 1 + 4 files changed, 5 insertions(+) create mode 100644 .coveralls.yml diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 0000000..38bd628 --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1,2 @@ +coverage_clover: build/reports/coveralls/clover.xml +json_path: build/reports/coveralls/upload.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 0471507..4844a74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Common and useful classes, methods, exceptions etc. 2. Phing > configuration > minor updates 3. Implement Mutation Testing Framework (infection/infection package) 4. Travis CI > run many tasks using Phing (instead of PHPUnit only) +5. Fix integration with [Coveralls](https://www.coveralls.io) (available as the badge in [README.md](README.md)) # 1.0.1 diff --git a/composer.json b/composer.json index f39c07b..ca10efa 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,7 @@ "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", "infection/infection": "^0.11.4", + "php-coveralls/php-coveralls": "^2.1", "phpunit/phpunit": "^8.0", "sebastian/phpcpd": "^4.1", "squizlabs/php_codesniffer": " ^2.9" diff --git a/phpunit.xml.dist b/phpunit.xml.dist index f54393f..a8faf74 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -26,5 +26,6 @@ + From 87422af5c7f645dd129a74e802e740f9f6325a22 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 3 Apr 2019 12:45:26 +0200 Subject: [PATCH 024/137] Implement PHPStan (https://github.com/phpstan/phpstan) --- CHANGELOG.md | 1 + composer.json | 1 + phing/properties.dist | 9 +++++++++ phing/tests.xml | 8 +++++++- phpstan.neon.dist | 5 +++++ 5 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 phpstan.neon.dist diff --git a/CHANGELOG.md b/CHANGELOG.md index 4844a74..c6e3ae8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Common and useful classes, methods, exceptions etc. 3. Implement Mutation Testing Framework (infection/infection package) 4. Travis CI > run many tasks using Phing (instead of PHPUnit only) 5. Fix integration with [Coveralls](https://www.coveralls.io) (available as the badge in [README.md](README.md)) +6. Implement [PHPStan](https://github.com/phpstan/phpstan) # 1.0.1 diff --git a/composer.json b/composer.json index ca10efa..b54fece 100644 --- a/composer.json +++ b/composer.json @@ -24,6 +24,7 @@ "friendsofphp/php-cs-fixer": "^2.14", "infection/infection": "^0.11.4", "php-coveralls/php-coveralls": "^2.1", + "phpstan/phpstan": "^0.11.1", "phpunit/phpunit": "^8.0", "sebastian/phpcpd": "^4.1", "squizlabs/php_codesniffer": " ^2.9" diff --git a/phing/properties.dist b/phing/properties.dist index 3a49281..ee23c95 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -63,6 +63,15 @@ dir.docker = ${project.basedir}/docker dir.docker.data = ${dir.docker}/data/db dir.docker.logs = ${dir.docker}/logs/nginx +# -------------------------------------------------------------------------------- +# Static Analysis +# -------------------------------------------------------------------------------- + +# Paths of frameworks used to run analysis: +# - PHPStan +# +check.phpstan.command = ./vendor/bin/phpstan analyse + # -------------------------------------------------------------------------------- # Testing # -------------------------------------------------------------------------------- diff --git a/phing/tests.xml b/phing/tests.xml index 3f97f01..a02ab9f 100644 --- a/phing/tests.xml +++ b/phing/tests.xml @@ -43,7 +43,8 @@ @@ -69,6 +70,11 @@ + + + + + diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..31f6166 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,5 @@ +parameters: + level: 1 + paths: + - src + - tests From 9f2a5294a82a5ab95b197f0560ae6822f2395028 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 3 Apr 2019 12:53:59 +0200 Subject: [PATCH 025/137] Phing > configuration > remove unnecessary tests/Resources/var/ directory (and subdirectories) --- phing/app.xml | 5 ----- phing/filesets.xml | 20 -------------------- phing/properties.dist | 4 ---- 3 files changed, 29 deletions(-) diff --git a/phing/app.xml b/phing/app.xml index 5688569..7a36756 100644 --- a/phing/app.xml +++ b/phing/app.xml @@ -76,11 +76,6 @@ - - - - - diff --git a/phing/filesets.xml b/phing/filesets.xml index c3aea0c..fa969ea 100644 --- a/phing/filesets.xml +++ b/phing/filesets.xml @@ -1,25 +1,8 @@ - - - - - - - - - - - - - - diff --git a/phing/properties.dist b/phing/properties.dist index ee23c95..c4caa95 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -39,10 +39,6 @@ composer.php = php # System directories # dir.src = ${project.basedir}/src -dir.var = ${project.basedir}/tests/Resources/var -dir.cache = ${dir.var}/cache -dir.logs = ${dir.var}/log -dir.sessions = ${dir.var}/sessions dir.data = ${project.basedir}/data dir.tests = ${project.basedir}/tests From 92e607a3f08710616fcd7136f223897cf09d1a9b Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 3 Apr 2019 15:06:05 +0200 Subject: [PATCH 026/137] PHPUnit > execute tests in random order --- CHANGELOG.md | 1 + phpunit.xml.dist | 3 +- tests/Collection/CollectionTest.php | 61 ++++++++++++++++++----------- tests/Utilities/UriTest.php | 11 +++++- 4 files changed, 51 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6e3ae8..15d2116 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Common and useful classes, methods, exceptions etc. 4. Travis CI > run many tasks using Phing (instead of PHPUnit only) 5. Fix integration with [Coveralls](https://www.coveralls.io) (available as the badge in [README.md](README.md)) 6. Implement [PHPStan](https://github.com/phpstan/phpstan) +7. PHPUnit > execute tests in random order # 1.0.1 diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a8faf74..b6e693d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,11 +1,12 @@ - + diff --git a/tests/Collection/CollectionTest.php b/tests/Collection/CollectionTest.php index 092ef89..5c5112a 100644 --- a/tests/Collection/CollectionTest.php +++ b/tests/Collection/CollectionTest.php @@ -347,27 +347,30 @@ class CollectionTest extends BaseTestCase */ public function provideElementToAdd() { - $collection = new Collection(); - yield[ - 'test1', + 'This is test 1', 1, 0, - $collection, + new Collection(), ]; yield[ - 'test2', + 'This is test 2', 2, 1, - $collection, + new Collection([ + 'I am 1st', + ]), ]; yield[ - 'test3', + 'This is test 3', 3, 2, - $collection, + new Collection([ + 'I am 1st', + 'I am 2nd', + ]), ]; } @@ -378,46 +381,58 @@ class CollectionTest extends BaseTestCase */ public function provideElementToAddWithIndex() { - $collection = new Collection(); - yield[ + 'This is test 1', 'test1', - 'aa', 1, - 'aa', - $collection, + 'test1', + new Collection(), ]; yield[ + 'This is test 2', 'test2', - 'oo', 2, - 'oo', - $collection, + 'test2', + new Collection([ + 'test1' => 'I am 1st', + ]), ]; yield[ - 'test3', + 'This is test 3', null, 3, 0, - $collection, + new Collection([ + 'test1' => 'I am 1st', + 'test2' => 'I am 2nd', + ]), ]; yield[ - 'test4', + 'This is test 4', '', 4, 1, - $collection, + new Collection([ + 'test1' => 'I am 1st', + 'test2' => 'I am 2nd', + 'I am 3rd', + ]), ]; yield[ + 'This is test 5', 'test5', - 'vv', 5, - 'vv', - $collection, + 'test5', + new Collection([ + 'test1' => 'I am 1st', + 'test2' => 'I am 2nd', + 2 => 'I am 3rd', + 3 => 'I am 4th', + ]), ]; } diff --git a/tests/Utilities/UriTest.php b/tests/Utilities/UriTest.php index 20b1eaf..6f92391 100644 --- a/tests/Utilities/UriTest.php +++ b/tests/Utilities/UriTest.php @@ -60,6 +60,15 @@ class UriTest extends BaseTestCase */ public function testReplenishProtocol($expected, $url, $protocol = '') { + /* + * Required to get protocol when it's not provided and to void test failure: + * + * Failed asserting that two strings are identical. + * Expected :'://test' + * Actual :'http://test' + */ + $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; + self::assertSame($expected, Uri::replenishProtocol($url, $protocol)); } @@ -251,7 +260,7 @@ class UriTest extends BaseTestCase public function provideUrlToReplenishProtocol() { yield[ - '://test', + 'http://test', 'test', '', ]; From da9ae20a33b9473342a9220b726af0bd5637c1a3 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 3 Apr 2019 19:47:08 +0200 Subject: [PATCH 027/137] Implement Psalm (https://github.com/vimeo/psalm) --- CHANGELOG.md | 1 + composer.json | 3 ++- psalm.xml | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 psalm.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 15d2116..e2eef17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Common and useful classes, methods, exceptions etc. 5. Fix integration with [Coveralls](https://www.coveralls.io) (available as the badge in [README.md](README.md)) 6. Implement [PHPStan](https://github.com/phpstan/phpstan) 7. PHPUnit > execute tests in random order +8. Implement [Psalm](https://github.com/vimeo/psalm) # 1.0.1 diff --git a/composer.json b/composer.json index b54fece..f010981 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,8 @@ "phpstan/phpstan": "^0.11.1", "phpunit/phpunit": "^8.0", "sebastian/phpcpd": "^4.1", - "squizlabs/php_codesniffer": " ^2.9" + "squizlabs/php_codesniffer": " ^2.9", + "vimeo/psalm": "^3.0" }, "autoload": { "psr-4": { diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..aedffd7 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 602855d2a7badb89891caff5aeda7490aae1f8c0 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 3 Apr 2019 20:26:06 +0200 Subject: [PATCH 028/137] PHPUnit > execute tests in random order > fix XSD namespace (required to use the "executionOrder" attribute) --- phpunit.xml.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index b6e693d..384d0a0 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -3,7 +3,7 @@ Date: Fri, 5 Apr 2019 20:36:21 +0200 Subject: [PATCH 029/137] PHPUnit > directory with code coverage > rename --- phing/properties.dist | 2 +- phpunit.xml.dist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/phing/properties.dist b/phing/properties.dist index c4caa95..b87a660 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -46,7 +46,7 @@ dir.tests = ${project.basedir}/tests # dir.build = ${project.basedir}/build dir.reports = ${dir.build}/reports -dir.reports.coverage = ${dir.reports}/phpunit_coverage +dir.reports.coverage = ${dir.reports}/phpunit-coverage # Data directories # diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 384d0a0..9981913 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -26,7 +26,7 @@ - + From d1c1d4847342bdb3f28c208f7102f850a0c03a56 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 5 Apr 2019 20:39:30 +0200 Subject: [PATCH 030/137] Infection (Mutation Testing Framework) > fix bugs while running (generate proper code coverage, bugs while running tests randomly) --- CHANGELOG.md | 2 ++ phing/properties.dist | 4 ++-- phpunit.xml.dist | 3 +++ tests/Utilities/ArraysTest.php | 22 ++++++++++++++++++++++ tests/Utilities/DateTest.php | 7 +++++++ tests/Utilities/MiscellaneousTest.php | 21 +++++++++++++++------ tests/Utilities/ReflectionTest.php | 14 +++++++++++--- 7 files changed, 62 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2eef17..836d922 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ Common and useful classes, methods, exceptions etc. 6. Implement [PHPStan](https://github.com/phpstan/phpstan) 7. PHPUnit > execute tests in random order 8. Implement [Psalm](https://github.com/vimeo/psalm) +9. Infection (Mutation Testing Framework) > fix bugs while running (generate proper code coverage, bugs while running +tests randomly) # 1.0.1 diff --git a/phing/properties.dist b/phing/properties.dist index b87a660..4627505 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -84,5 +84,5 @@ tests.database = ${dir.data.temporary}/database.sqlite # - PHPUnit (unit tests) # - Infection (mutation tests) # -tests.phpunit.command = ./vendor/bin/phpunit --verbose --no-coverage -tests.mutation.command = ./vendor/bin/infection --threads=5 +tests.phpunit.command = ./vendor/bin/phpunit --verbose +tests.mutation.command = ./vendor/bin/infection --ansi --threads=5 --coverage=build/reports/infection diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 9981913..2478270 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -4,6 +4,7 @@ + + diff --git a/tests/Utilities/ArraysTest.php b/tests/Utilities/ArraysTest.php index 688edce..3fd87bf 100644 --- a/tests/Utilities/ArraysTest.php +++ b/tests/Utilities/ArraysTest.php @@ -10,6 +10,7 @@ namespace Meritoo\Test\Common\Utilities; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Utilities\Arrays; +use Meritoo\Common\Utilities\Locale; use Meritoo\Test\Common\Utilities\Arrays\SimpleToString; /** @@ -42,6 +43,13 @@ class ArraysTest extends BaseTestCase */ public function testValues2string($description, $expected, array $array, $arrayColumnKey = '', $separator = ',') { + // Required to avoid failure: + // + // Failed asserting that two strings are identical + // 1,2,3,test 1,test 2,test 3,,test 4,,bbb,3.45 - expected + // 1,2,3,test 1,test 2,test 3,,test 4,,bbb,3,45 - actual + Locale::setLocale(LC_ALL, 'en', 'US'); + self::assertSame($expected, Arrays::values2string($array, $arrayColumnKey, $separator), $description); } @@ -64,6 +72,13 @@ class ArraysTest extends BaseTestCase $valuesKeysSeparator = '=', $valuesWrapper = '' ) { + // Required to avoid failure: + // + // Failed asserting that two strings are identical + // test_1=test test,test_2=2,test_3=3.45 - expected + // test_1=test test,test_2=2,test_3=3,45 - actual + Locale::setLocale(LC_ALL, 'en', 'US'); + self::assertSame( $expected, Arrays::valuesKeys2string($array, $separator, $valuesKeysSeparator, $valuesWrapper), @@ -111,6 +126,13 @@ class ArraysTest extends BaseTestCase */ public function testValues2csv($description, $expected, array $array, $separator = ',') { + // Required to avoid failure: + // + // Failed asserting that two strings are identical + // 1,2,3.45 - expected + // 1,2,3,45 - actual + Locale::setLocale(LC_ALL, 'en', 'US'); + self::assertSame($expected, Arrays::values2csv($array, $separator), $description); self::assertSame('', Arrays::values2csv($this->simpleArray), 'Simple array'); diff --git a/tests/Utilities/DateTest.php b/tests/Utilities/DateTest.php index 1af25bd..97b9f61 100644 --- a/tests/Utilities/DateTest.php +++ b/tests/Utilities/DateTest.php @@ -15,6 +15,7 @@ use Meritoo\Common\Exception\Type\UnknownDatePartTypeException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\DatePeriod; use Meritoo\Common\Utilities\Date; +use Meritoo\Common\Utilities\Locale; /** * Test case of the Date methods (only static functions) @@ -200,6 +201,12 @@ class DateTest extends BaseTestCase public function testGetCurrentDayOfWeekName() { + // Required to avoid failure: + // + // Failed asserting that 'giovedì' matches PCRE pattern + // "/^Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday$/" + Locale::setLocale(LC_ALL, 'en', 'US'); + $days = [ 'Monday', 'Tuesday', diff --git a/tests/Utilities/MiscellaneousTest.php b/tests/Utilities/MiscellaneousTest.php index 909bb11..20bcb8f 100644 --- a/tests/Utilities/MiscellaneousTest.php +++ b/tests/Utilities/MiscellaneousTest.php @@ -229,7 +229,7 @@ class MiscellaneousTest extends BaseTestCase * of strings or an array of patterns. * @param string|array $replacement The string or an array of strings to replace. It may be: string or an array * of strings. - * @param mixed $result Result of replacing + * @param mixed $result Result of replacing * * @dataProvider provideEmptyValuesToReplace */ @@ -245,7 +245,7 @@ class MiscellaneousTest extends BaseTestCase * strings or an array of patterns. * @param string $replacement The string or an array of strings to replace. It may be: string or an array of * strings. - * @param mixed $result Result of replacing + * @param mixed $result Result of replacing * * @dataProvider provideStringsToReplace */ @@ -261,7 +261,7 @@ class MiscellaneousTest extends BaseTestCase * strings or an array of patterns. * @param string $replacement The string or an array of strings to replace. It may be: string or an array of * strings. - * @param mixed $result Result of replacing + * @param mixed $result Result of replacing * * @dataProvider provideRegexToReplace */ @@ -277,7 +277,7 @@ class MiscellaneousTest extends BaseTestCase * strings or an array of patterns. * @param string $replacement The string or an array of strings to replace. It may be: string or an array of * strings. - * @param mixed $result Result of replacing + * @param mixed $result Result of replacing * * @dataProvider provideDataToReplaceWithQuoteStrings */ @@ -376,8 +376,17 @@ class MiscellaneousTest extends BaseTestCase $directory1Path = sys_get_temp_dir() . '/lorem/ipsum'; $directory2Path = sys_get_temp_dir() . '/lorem/dolor/sit'; - mkdir($directory1Path, 0777, true); - mkdir($directory2Path, 0777, true); + // Directory does not exist? Let's create it + // Required to avoid test failure + if (!file_exists($directory1Path)) { + mkdir($directory1Path, 0777, true); + } + + // Directory does not exist? Let's create it + // Required to avoid test failure + if (!file_exists($directory2Path)) { + mkdir($directory2Path, 0777, true); + } self::assertTrue(Miscellaneous::removeDirectory(sys_get_temp_dir() . '/lorem')); } diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 09f9883..4c742f6 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -176,14 +176,22 @@ class ReflectionTest extends BaseTestCase public function testGetOneChildClassWithTooManyChildClasses() { - $this->expectException(TooManyChildClassesException::class); + // Required to get all classes by get_declared_classes() function and avoid failure: + // + // Failed asserting that exception of type "Meritoo\Common\Exception\Reflection\TooManyChildClassesException" + // is thrown + new C(); - self::assertEquals(B::class, Reflection::getOneChildClass(A::class)); - self::assertEquals(C::class, Reflection::getOneChildClass(A::class)); + $this->expectException(TooManyChildClassesException::class); + Reflection::getOneChildClass(A::class); } public function testGetOneChildClass() { + // Required to get all classes by get_declared_classes() function and avoid throw of + // Meritoo\Common\Exception\Reflection\MissingChildClassesException exception + new C(); + self::assertEquals(C::class, Reflection::getOneChildClass(B::class)); } From 134a5a0108dc374f38cbd0200761f413bcde1754 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 5 Apr 2019 20:43:29 +0200 Subject: [PATCH 031/137] Phing > configuration > minor update --- phing/tests.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phing/tests.xml b/phing/tests.xml index a02ab9f..7a1d380 100644 --- a/phing/tests.xml +++ b/phing/tests.xml @@ -49,7 +49,8 @@ From 4f55f33385e5c2a7ddca445c7aea5d7b8b9a19e6 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 5 Apr 2019 20:47:37 +0200 Subject: [PATCH 032/137] Phing > php-coveralls > add task --- CHANGELOG.md | 1 + phing/properties.dist | 1 + phing/tests.xml | 8 +++++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 836d922..f010d85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Common and useful classes, methods, exceptions etc. 8. Implement [Psalm](https://github.com/vimeo/psalm) 9. Infection (Mutation Testing Framework) > fix bugs while running (generate proper code coverage, bugs while running tests randomly) +10. Phing > php-coveralls > add task # 1.0.1 diff --git a/phing/properties.dist b/phing/properties.dist index 4627505..436cec5 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -67,6 +67,7 @@ dir.docker.logs = ${dir.docker}/logs/nginx # - PHPStan # check.phpstan.command = ./vendor/bin/phpstan analyse +check.php_coveralls.command = ./vendor/bin/php-coveralls --ansi -v # -------------------------------------------------------------------------------- # Testing diff --git a/phing/tests.xml b/phing/tests.xml index 7a1d380..4ea22f7 100644 --- a/phing/tests.xml +++ b/phing/tests.xml @@ -44,7 +44,8 @@ @@ -76,6 +77,11 @@ + + + + + From 0f647051321af84e639a49251af2c08d11e2b0cc Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 5 Apr 2019 23:49:27 +0200 Subject: [PATCH 033/137] PHP Coding Standards Fixer > update configuration --- .php_cs.dist | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index d2f2f3c..3b7d3f1 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -4,11 +4,14 @@ $finder = PhpCsFixer\Finder::create() ->in([ __DIR__ . '/src', __DIR__ . '/tests', - ]); + ]) +; return PhpCsFixer\Config::create() ->setRules([ '@Symfony' => true, + '@PhpCsFixer' => true, + '@PHP71Migration' => true, 'binary_operator_spaces' => [ 'align_double_arrow' => true, ], @@ -24,4 +27,5 @@ return PhpCsFixer\Config::create() 'phpdoc_summary' => false, 'trim_array_spaces' => false, ]) - ->setFinder($finder); + ->setFinder($finder) +; From a13a62940861e31cd1834de527b5c947b422f639 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 6 Apr 2019 08:00:01 +0200 Subject: [PATCH 034/137] PHP Coding Standards Fixer > fix coding standard --- src/Collection/Templates.php | 1 - .../Type/UnknownDatePartTypeException.php | 5 +- .../UnknownOopVisibilityTypeException.php | 5 +- src/Traits/Collection/ArrayAccessTrait.php | 2 +- src/Traits/Collection/MainTrait.php | 8 +- src/Traits/Test/Base/BaseTestCaseTrait.php | 23 +- src/Traits/ValueObject/HumanTrait.php | 4 +- src/Type/DatePartType.php | 12 +- src/Type/DatePeriod.php | 29 +- src/Type/OopVisibilityType.php | 6 +- src/Utilities/Arrays.php | 135 ++--- src/Utilities/Bundle.php | 20 +- src/Utilities/Composer.php | 7 +- src/Utilities/Date.php | 91 +-- src/Utilities/MimeTypes.php | 18 +- src/Utilities/Miscellaneous.php | 135 ++--- src/Utilities/QueryBuilderUtility.php | 12 +- src/Utilities/Reflection.php | 39 +- src/Utilities/Regex.php | 15 +- src/Utilities/Repository.php | 41 +- src/Utilities/Uri.php | 16 +- src/ValueObject/Company.php | 4 +- src/ValueObject/Size.php | 4 +- src/ValueObject/Version.php | 24 +- tests/Collection/CollectionTest.php | 39 +- .../Base/UnknownTypeExceptionTest.php | 17 +- .../IncorrectBundleNameExceptionTest.php | 3 + .../Date/UnknownDatePartTypeExceptionTest.php | 3 + .../Exception/File/EmptyFileExceptionTest.php | 3 + .../File/EmptyFilePathExceptionTest.php | 3 + .../File/NotExistingFileExceptionTest.php | 3 + .../Method/DisabledMethodExceptionTest.php | 3 + .../CannotResolveClassNameExceptionTest.php | 3 + .../MissingChildClassesExceptionTest.php | 3 + .../NotExistingPropertyExceptionTest.php | 3 + .../TooManyChildClassesExceptionTest.php | 3 + .../IncorrectColorHexLengthExceptionTest.php | 3 + .../InvalidColorHexValueExceptionTest.php | 3 + .../InvalidHtmlAttributesExceptionTest.php | 3 + .../Regex/InvalidUrlExceptionTest.php | 3 + .../UnknownOopVisibilityTypeExceptionTest.php | 3 + .../InvalidSizeDimensionsExceptionTest.php | 3 + tests/Test/Base/BaseTestCaseTest.php | 14 +- tests/Type/Base/BaseTypeTest.php | 7 +- tests/Type/DatePartTypeTest.php | 3 + tests/Type/DatePeriodTest.php | 11 +- tests/Utilities/ArraysTest.php | 566 +++++++----------- tests/Utilities/Bootstrap4CssSelectorTest.php | 3 + tests/Utilities/BundleTest.php | 3 + tests/Utilities/ComposerTest.php | 23 +- tests/Utilities/CssSelectorTest.php | 3 + tests/Utilities/DateTest.php | 71 +-- tests/Utilities/GeneratorUtilityTest.php | 15 +- tests/Utilities/LocaleTest.php | 3 + tests/Utilities/MimeTypesTest.php | 3 + tests/Utilities/MiscellaneousTest.php | 127 ++-- tests/Utilities/QueryBuilderUtilityTest.php | 11 +- tests/Utilities/Reflection/F.php | 4 +- tests/Utilities/Reflection/H.php | 8 +- tests/Utilities/ReflectionTest.php | 19 +- tests/Utilities/RegexTest.php | 80 ++- tests/Utilities/Repository/Sortable.php | 20 +- tests/Utilities/RepositoryTest.php | 24 +- tests/Utilities/UriTest.php | 3 + tests/Utilities/XmlTest.php | 54 +- tests/ValueObject/AddressTest.php | 21 +- tests/ValueObject/BankAccountTest.php | 25 +- tests/ValueObject/CompanyTest.php | 41 +- tests/ValueObject/HumanTest.php | 3 + tests/ValueObject/SizeTest.php | 17 +- tests/ValueObject/VersionTest.php | 3 + 71 files changed, 812 insertions(+), 1133 deletions(-) diff --git a/src/Collection/Templates.php b/src/Collection/Templates.php index cbca41a..0ebe86c 100644 --- a/src/Collection/Templates.php +++ b/src/Collection/Templates.php @@ -30,7 +30,6 @@ class Templates extends Collection */ public function findTemplate(string $index): Template { - /* @var Template $template */ $template = $this->getByIndex($index); if ($template instanceof Template) { diff --git a/src/Exception/Type/UnknownDatePartTypeException.php b/src/Exception/Type/UnknownDatePartTypeException.php index 8155a50..2a85b2b 100644 --- a/src/Exception/Type/UnknownDatePartTypeException.php +++ b/src/Exception/Type/UnknownDatePartTypeException.php @@ -28,9 +28,6 @@ class UnknownDatePartTypeException extends UnknownTypeException */ public static function createException($unknownDatePart, $value) { - /* @var UnknownDatePartTypeException $exception */ - $exception = parent::create($unknownDatePart, new DatePartType(), sprintf('date part (with value %s)', $value)); - - return $exception; + return parent::create($unknownDatePart, new DatePartType(), sprintf('date part (with value %s)', $value)); } } diff --git a/src/Exception/Type/UnknownOopVisibilityTypeException.php b/src/Exception/Type/UnknownOopVisibilityTypeException.php index f8eb21d..6f4ef01 100644 --- a/src/Exception/Type/UnknownOopVisibilityTypeException.php +++ b/src/Exception/Type/UnknownOopVisibilityTypeException.php @@ -27,9 +27,6 @@ class UnknownOopVisibilityTypeException extends UnknownTypeException */ public static function createException($unknownType) { - /* @var UnknownOopVisibilityTypeException $exception */ - $exception = parent::create($unknownType, new OopVisibilityType(), 'OOP-related visibility'); - - return $exception; + return parent::create($unknownType, new OopVisibilityType(), 'OOP-related visibility'); } } diff --git a/src/Traits/Collection/ArrayAccessTrait.php b/src/Traits/Collection/ArrayAccessTrait.php index ddb8527..5db8567 100644 --- a/src/Traits/Collection/ArrayAccessTrait.php +++ b/src/Traits/Collection/ArrayAccessTrait.php @@ -57,7 +57,7 @@ trait ArrayAccessTrait /** * Returns information if element with given index/key exists * - * @param string|int $index The index/key of element + * @param int|string $index The index/key of element * @return bool */ private function exists($index) diff --git a/src/Traits/Collection/MainTrait.php b/src/Traits/Collection/MainTrait.php index 8c401fa..9188179 100644 --- a/src/Traits/Collection/MainTrait.php +++ b/src/Traits/Collection/MainTrait.php @@ -58,6 +58,7 @@ trait MainTrait foreach ($elements as $index => $element) { if ($useIndexes) { $this->add($element, $index); + continue; } @@ -93,6 +94,7 @@ trait MainTrait foreach ($this->elements as $index => $existing) { if ($element === $existing) { unset($this->elements[$index]); + break; } } @@ -150,7 +152,7 @@ trait MainTrait * Returns previous element for given element * * @param mixed $element The element to verify - * @return mixed|null + * @return null|mixed */ public function getPrevious($element) { @@ -161,7 +163,7 @@ trait MainTrait * Returns next element for given element * * @param mixed $element The element to verify - * @return mixed|null + * @return null|mixed */ public function getNext($element) { @@ -192,7 +194,7 @@ trait MainTrait * Returns element with given index * * @param mixed $index Index / key of the element - * @return mixed|null + * @return null|mixed */ public function getByIndex($index) { diff --git a/src/Traits/Test/Base/BaseTestCaseTrait.php b/src/Traits/Test/Base/BaseTestCaseTrait.php index 74eea20..30bffcd 100644 --- a/src/Traits/Test/Base/BaseTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTestCaseTrait.php @@ -163,7 +163,7 @@ trait BaseTestCaseTrait * Verifies visibility and arguments of method * * @param string $classNamespace Namespace of class that contains method to verify - * @param string|ReflectionMethod $method Name of method or just the method to verify + * @param ReflectionMethod|string $method Name of method or just the method to verify * @param string $visibilityType Expected visibility of verified method. One of * OopVisibilityType class constants. * @param int $argumentsCount (optional) Expected count/amount of arguments of the @@ -183,19 +183,15 @@ trait BaseTestCaseTrait $argumentsCount = 0, $requiredArgumentsCount = 0 ) { - /* - * Type of visibility is correct? - */ + // Type of visibility is not correct? if (!(new OopVisibilityType())->isCorrectType($visibilityType)) { throw new UnknownOopVisibilityTypeException($visibilityType); } $reflection = new ReflectionClass($classNamespace); - /* - * Name of method provided only? - * Let's find instance of the method (based on reflection) - */ + // Name of method provided only? + // Let's find instance of the method (based on reflection) if (!$method instanceof ReflectionMethod) { $method = $reflection->getMethod($method); } @@ -203,14 +199,15 @@ trait BaseTestCaseTrait switch ($visibilityType) { case OopVisibilityType::IS_PUBLIC: static::assertTrue($method->isPublic()); - break; + break; case OopVisibilityType::IS_PROTECTED: static::assertTrue($method->isProtected()); - break; + break; case OopVisibilityType::IS_PRIVATE: static::assertTrue($method->isPrivate()); + break; } @@ -234,9 +231,6 @@ trait BaseTestCaseTrait $argumentsCount = 0, $requiredArgumentsCount = 0 ) { - /* - * Let's grab the constructor - */ $reflection = new ReflectionClass($classNamespace); $method = $reflection->getConstructor(); @@ -256,9 +250,6 @@ trait BaseTestCaseTrait */ protected static function assertHasNoConstructor($classNamespace) { - /* - * Let's grab the constructor - */ $reflection = new ReflectionClass($classNamespace); $constructor = $reflection->getConstructor(); diff --git a/src/Traits/ValueObject/HumanTrait.php b/src/Traits/ValueObject/HumanTrait.php index b8b7cd8..e0eb795 100644 --- a/src/Traits/ValueObject/HumanTrait.php +++ b/src/Traits/ValueObject/HumanTrait.php @@ -99,7 +99,7 @@ trait HumanTrait /** * Returns email address * - * @return string|null + * @return null|string */ public function getEmail() { @@ -109,7 +109,7 @@ trait HumanTrait /** * Returns birth date * - * @return \DateTime|null + * @return null|\DateTime */ public function getBirthDate() { diff --git a/src/Type/DatePartType.php b/src/Type/DatePartType.php index dfa91c4..e6d8b2b 100644 --- a/src/Type/DatePartType.php +++ b/src/Type/DatePartType.php @@ -23,40 +23,40 @@ class DatePartType extends BaseType * * @var string */ - const DAY = 'day'; + public const DAY = 'day'; /** * The "hour" date part * * @var string */ - const HOUR = 'hour'; + public const HOUR = 'hour'; /** * The "minute" date part * * @var string */ - const MINUTE = 'minute'; + public const MINUTE = 'minute'; /** * The "month" date part * * @var string */ - const MONTH = 'month'; + public const MONTH = 'month'; /** * The "second" date part * * @var string */ - const SECOND = 'second'; + public const SECOND = 'second'; /** * The "year" date part * * @var string */ - const YEAR = 'year'; + public const YEAR = 'year'; } diff --git a/src/Type/DatePeriod.php b/src/Type/DatePeriod.php index abfe4db..590e8ff 100644 --- a/src/Type/DatePeriod.php +++ b/src/Type/DatePeriod.php @@ -26,63 +26,63 @@ class DatePeriod extends BaseType * * @var int */ - const LAST_MONTH = 4; + public const LAST_MONTH = 4; /** * The period constant: last week * * @var int */ - const LAST_WEEK = 1; + public const LAST_WEEK = 1; /** * The period constant: last year * * @var int */ - const LAST_YEAR = 7; + public const LAST_YEAR = 7; /** * The period constant: next month * * @var int */ - const NEXT_MONTH = 6; + public const NEXT_MONTH = 6; /** * The period constant: next week * * @var int */ - const NEXT_WEEK = 3; + public const NEXT_WEEK = 3; /** * The period constant: next year * * @var int */ - const NEXT_YEAR = 9; + public const NEXT_YEAR = 9; /** * The period constant: this month * * @var int */ - const THIS_MONTH = 5; + public const THIS_MONTH = 5; /** * The period constant: this week * * @var int */ - const THIS_WEEK = 2; + public const THIS_WEEK = 2; /** * The period constant: this year * * @var int */ - const THIS_YEAR = 8; + public const THIS_YEAR = 8; /** * The start date of period @@ -114,23 +114,20 @@ class DatePeriod extends BaseType * Returns formatted one of the period's date: start date or end date * * @param string $format Format used to format the date - * @param bool $startDate (optional) If is set to true, start date is formatted. Otherwise - end date. + * @param bool $startDate (optional) If is set to true, start date will be formatted. Otherwise - end date. * @return string */ public function getFormattedDate($format, $startDate = true) { $date = $this->getEndDate(); - /* - * Start date should be formatted? - */ + // Start date should be formatted? if ($startDate) { $date = $this->getStartDate(); } - /* - * Unknown date or format is invalid? - */ + // Unknown date or format is invalid? + // Nothing to do if (null === $date || !Date::isValidDateFormat($format)) { return ''; } diff --git a/src/Type/OopVisibilityType.php b/src/Type/OopVisibilityType.php index 1929710..95eb52a 100644 --- a/src/Type/OopVisibilityType.php +++ b/src/Type/OopVisibilityType.php @@ -19,19 +19,19 @@ class OopVisibilityType extends BaseType * * @var int */ - const IS_PRIVATE = 3; + public const IS_PRIVATE = 3; /** * The "protected" visibility of OOP * * @var int */ - const IS_PROTECTED = 2; + public const IS_PROTECTED = 2; /** * The "public" visibility of OOP * * @var int */ - const IS_PUBLIC = 1; + public const IS_PUBLIC = 1; } diff --git a/src/Utilities/Arrays.php b/src/Utilities/Arrays.php index d976226..b20fba7 100644 --- a/src/Utilities/Arrays.php +++ b/src/Utilities/Arrays.php @@ -21,16 +21,16 @@ class Arrays * * @var string */ - const POSITION_KEY_NAME = 'position'; + public const POSITION_KEY_NAME = 'position'; /** * Converts given array's column to string. * Recursive call is made for multi-dimensional arrays. * * @param array $array Data to be converted - * @param string|int $arrayColumnKey (optional) Column name. Default: "". + * @param int|string $arrayColumnKey (optional) Column name. Default: "". * @param string $separator (optional) Separator used between values. Default: ",". - * @return string|null + * @return null|string */ public static function values2string(array $array, $arrayColumnKey = '', $separator = ',') { @@ -85,7 +85,7 @@ class Arrays * @param string $valuesKeysSeparator (optional) Separator used between name and value. Default: "=". * @param string $valuesWrapper (optional) Wrapper used to wrap values, e.g. double-quote: key="value". * Default: "". - * @return string|null + * @return null|string */ public static function valuesKeys2string( array $array, @@ -123,7 +123,7 @@ class Arrays * * @param array $array Data to be converted. It have to be an array that represents database table. * @param string $separator (optional) Separator used between values. Default: ",". - * @return string|null + * @return null|string */ public static function values2csv(array $array, $separator = ',') { @@ -279,7 +279,7 @@ class Arrays * * @param array $array Data to get the breadcrumb * @param string $separator (optional) Separator used to stick the elements. Default: "/". - * @return string|null + * @return null|string */ public static function getLastElementBreadCrumb(array $array, $separator = '/') { @@ -328,9 +328,7 @@ class Arrays $last = end($array); if (is_array($last)) { - /* - * We've got an array, so looking for the last row of array will be done recursively - */ + // We've got an array, so looking for the last row of array will be done recursively $effect = self::getLastRow($last); /* @@ -381,7 +379,7 @@ class Arrays * @param string $jsVariableName (optional) Name of the variable that will be in generated JavaScript code * @param bool $preserveIndexes (optional) If is set to true and $jsVariableName isn't empty, indexes also * will be added to the JavaScript code. Otherwise not. - * @return string|null + * @return null|string */ public static function array2JavaScript(array $array, $jsVariableName = '', $preserveIndexes = false) { @@ -477,7 +475,7 @@ class Arrays * Quotes (adds quotes) to elements that are strings and returns new array (with quoted elements) * * @param array $array The array to check for string values - * @return array|null + * @return null|array */ public static function quoteStrings(array $array) { @@ -509,9 +507,9 @@ class Arrays /** * Removes marginal element (first or last) * - * @param string|array $item The item which should be shortened + * @param array|string $item The item which should be shortened * @param bool $last (optional) If is set to true, last element is removed. Otherwise - first. - * @return string|array + * @return array|string */ public static function removeMarginalElement($item, $last = true) { @@ -560,7 +558,7 @@ class Arrays * * @param array $array The array that contains element / item which should be removed * @param mixed $item The element / item which should be removed - * @return bool|array + * @return array|bool */ public static function removeElement(array $array, $item) { @@ -572,19 +570,13 @@ class Arrays return false; } - /* - * Flip the array to make it looks like: value => key - */ + // Flip the array to make it looks like: value => key $arrayFlipped = array_flip($array); - /* - * Take the key of element / item that should be removed - */ + // Take the key of element / item that should be removed $key = $arrayFlipped[$item]; - /* - * ...and remove the element / item - */ + // ...and remove the element / item unset($array[$key]); return $array; @@ -642,7 +634,7 @@ class Arrays * value will be used with it's key, because other will be overridden. * Otherwise - values are preserved and keys assigned to that values are * returned as an array. - * @return array|null + * @return null|array * * Example of $ignoreDuplicatedValues = false: * - provided array @@ -680,13 +672,12 @@ class Arrays */ if (is_array($value)) { $replaced[$key] = self::setKeysAsValues($value, $ignoreDuplicatedValues); + continue; } - /* - * Duplicated values shouldn't be ignored and processed value is used as key already? - * Let's use an array and that will contain all values (to avoid ignoring / overriding duplicated values) - */ + // Duplicated values shouldn't be ignored and processed value is used as key already? + // Let's use an array and that will contain all values (to avoid ignoring / overriding duplicated values) if (!$ignoreDuplicatedValues && isset($replaced[$value])) { $existing = self::makeArray($replaced[$value]); @@ -697,9 +688,7 @@ class Arrays continue; } - /* - * Standard behaviour - */ + // Standard behaviour $replaced[$value] = $key; } @@ -711,7 +700,7 @@ class Arrays * * @param array $array The array to sort * @param int $sortFlags (optional) Options of ksort() function - * @return array|null + * @return null|array */ public static function ksortRecursive(array &$array, $sortFlags = SORT_REGULAR) { @@ -739,7 +728,7 @@ class Arrays * Returns count / amount of elements that are not array * * @param array $array The array to count - * @return int|null + * @return null|int */ public static function getNonArrayElementsCount(array $array) { @@ -756,6 +745,7 @@ class Arrays foreach ($array as &$value) { if (is_array($value)) { $count += self::getNonArrayElementsCount($value); + continue; } @@ -857,10 +847,10 @@ class Arrays * @param array $array The array with elements * @param string $separator (optional) Separator used between elements. Default: ".". * @param string $parentPath (optional) Path of the parent element. Default: "". - * @param string|array $stopIfMatchedBy (optional) Patterns of keys or paths that matched will stop the process + * @param array|string $stopIfMatchedBy (optional) Patterns of keys or paths that matched will stop the process * of path building and including children of those keys or paths (recursive * will not be used for keys in lower level of given array). Default: "". - * @return array|null + * @return null|array * * Examples - $stopIfMatchedBy argument: * a) "\d+" @@ -910,6 +900,7 @@ class Arrays if (preg_match($pattern, $key) || preg_match($pattern, $path)) { $stopRecursion = true; + break; } } @@ -923,12 +914,11 @@ class Arrays */ if (!$valueIsArray || ($valueIsArray && empty($value)) || $stopRecursion) { $paths[$path] = $value; + continue; } - /* - * Let's iterate through the next level, using recursive - */ + // Let's iterate through the next level, using recursive if ($valueIsArray) { $recursivePaths = self::getLastElementsPaths($value, $separator, $path, $stopIfMatchedBy); $paths += $recursivePaths; @@ -978,9 +968,7 @@ class Arrays */ $areMatched = true; - /* - * Building the pattern - */ + // Building the pattern $rawPattern = $pattern; $pattern = sprintf('|%s|', $rawPattern); @@ -991,6 +979,7 @@ class Arrays */ if (!preg_match($pattern, $key)) { $areMatched = false; + break; } @@ -1141,7 +1130,7 @@ class Arrays * * @param array $array The array which should contain values of the key * @param string $key The key - * @return array|null + * @return null|array */ public static function getAllValuesOfKey(array $array, $key) { @@ -1158,6 +1147,7 @@ class Arrays foreach ($array as $index => $value) { if ($index === $key) { $values[] = $value; + continue; } @@ -1184,7 +1174,7 @@ class Arrays * @param string $keyName (optional) Name of key which will contain the position value * @param int $startPosition (optional) Default, start value of the position for main / given array, not the * children - * @return array|null + * @return null|array */ public static function setPositions(array $array, $keyName = self::POSITION_KEY_NAME, $startPosition = null) { @@ -1233,6 +1223,7 @@ class Arrays foreach ($array as $key => $value) { if (is_array($value)) { $result[$key] = self::trimRecursive($value); + continue; } @@ -1287,7 +1278,7 @@ class Arrays * * @param array $array An array to sort * @param array $keysOrder An array with keys of the 1st argument in proper / required order - * @return array|null + * @return null|array */ public static function sortByCustomKeysOrder(array $array, array $keysOrder) { @@ -1336,7 +1327,7 @@ class Arrays * * @param array $array The array with elements to implode * @param string $separator Separator used to stick together elements of given array - * @return string|null + * @return null|string */ public static function implodeSmart(array $array, $separator) { @@ -1437,9 +1428,7 @@ class Arrays foreach ($array1 as $key => $value) { $array2HasKey = array_key_exists($key, $array2); - /* - * Values should be compared only? - */ + // Values should be compared only? if ($valuesOnly) { $difference = null; @@ -1461,20 +1450,14 @@ class Arrays $effect[] = $difference; } - /* - * The key exists in 2nd array? - */ + // The key exists in 2nd array? } elseif ($array2HasKey) { - /* - * The value it's an array (it's a nested array)? - */ + // The value it's an array (it's a nested array)? if (is_array($value)) { $diff = []; if (is_array($array2[$key])) { - /* - * Let's verify the nested array - */ + // Let's verify the nested array $diff = self::arrayDiffRecursive($value, $array2[$key], $valuesOnly); } @@ -1484,16 +1467,12 @@ class Arrays $effect[$key] = $diff; } elseif ($value !== $array2[$key]) { - /* - * Value is different than in 2nd array? - * OKay, I've got difference - */ + // Value is different than in 2nd array? + // OKay, I've got difference $effect[$key] = $value; } } else { - /* - * OKay, I've got difference - */ + // OKay, I've got difference $effect[$key] = $value; } } @@ -1506,14 +1485,12 @@ class Arrays * * @param array $array The array to verify * @param mixed $element The element who index / key is needed - * @return bool|mixed|null + * @return null|bool|mixed */ public static function getIndexOf(array $array, $element) { - /* - * No elements? - * Nothing to do - */ + // No elements? + // Nothing to do if (empty($array)) { return false; } @@ -1531,10 +1508,10 @@ class Arrays * Returns an array with incremented indexes / keys * * @param array $array The array which indexes / keys should be incremented - * @param int|null $startIndex (optional) Index from which incrementation should be started. If not provided, + * @param null|int $startIndex (optional) Index from which incrementation should be started. If not provided, * the first index / key will be used. * @param int $incrementStep (optional) Value used for incrementation. The step of incrementation. - * @return array|null + * @return null|array */ public static function incrementIndexes(array $array, $startIndex = null, $incrementStep = 1) { @@ -1594,7 +1571,7 @@ class Arrays * * @param array $array The array with elements * @param mixed $element Element for who next element should be returned - * @return mixed|null + * @return null|mixed */ public static function getNextElement(array $array, $element) { @@ -1606,7 +1583,7 @@ class Arrays * * @param array $array The array with elements * @param mixed $element Element for who previous element should be returned - * @return mixed|null + * @return null|mixed */ public static function getPreviousElement(array $array, $element) { @@ -1617,7 +1594,7 @@ class Arrays * Returns information if given array is a multi dimensional array * * @param array $array The array to verify - * @return bool|null + * @return null|bool */ public static function isMultiDimensional(array $array) { @@ -1671,7 +1648,7 @@ class Arrays * Returns non-empty values, e.g. without "" (empty string), null or [] * * @param array $values The values to filter - * @return array|null + * @return null|array */ public static function getNonEmptyValues(array $values) { @@ -1696,7 +1673,7 @@ class Arrays * * @param array $values The values to filter * @param string $separator (optional) Separator used to implode the values. Default: ", ". - * @return string|null + * @return null|string */ public static function getNonEmptyValuesAsString(array $values, $separator = ', ') { @@ -1727,7 +1704,7 @@ class Arrays * @param array $array The array with elements * @param mixed $element Element for who next element should be returned * @param bool $next (optional) If is set to true, returns next neighbour. Otherwise - previous. - * @return mixed|null + * @return null|mixed */ private static function getNeighbour(array $array, $element, $next = true) { @@ -1770,9 +1747,7 @@ class Arrays return null; } - /* - * Looking for key of the neighbour (next or previous element) - */ + // Looking for key of the neighbour (next or previous element) if ($next) { ++$indexOfKey; } else { diff --git a/src/Utilities/Bundle.php b/src/Utilities/Bundle.php index 105d8d9..dfbde0e 100644 --- a/src/Utilities/Bundle.php +++ b/src/Utilities/Bundle.php @@ -25,7 +25,7 @@ class Bundle * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" * @param string $extension (optional) Extension of the view / template (default: "html.twig") * @throws IncorrectBundleNameException - * @return string|null + * @return null|string */ public static function getBundleViewPath($viewPath, $bundleName, $extension = 'html.twig') { @@ -37,23 +37,17 @@ class Bundle return null; } - /* - * Given name of bundle is invalid? - */ + // Oops, given name of bundle is invalid if (!Regex::isValidBundleName($bundleName)) { throw IncorrectBundleNameException::create($bundleName); } - /* - * Path of the view / template doesn't end with given extension? - */ + // Make sure that path of the view / template ends with given extension if (!Regex::endsWith($viewPath, $extension)) { $viewPath = sprintf('%s.%s', $viewPath, $extension); } - /* - * Prepare short name of bundle and path of view / template with "/" (instead of ":") - */ + // Prepare short name of bundle and path of view / template with "/" (instead of ":") $shortBundleName = static::getShortBundleName($bundleName); $viewPath = str_replace(':', '/', $viewPath); @@ -65,13 +59,11 @@ class Bundle * * @param string $fullBundleName Full name of the bundle, e.g. "MyExtraBundle" * @throws IncorrectBundleNameException - * @return string|null + * @return null|string */ public static function getShortBundleName($fullBundleName) { - /* - * Given name of bundle is invalid? - */ + // Oops, given name of bundle is invalid if (!Regex::isValidBundleName($fullBundleName)) { if (!is_string($fullBundleName)) { $fullBundleName = gettype($fullBundleName); diff --git a/src/Utilities/Composer.php b/src/Utilities/Composer.php index 28e91c7..1e423e8 100644 --- a/src/Utilities/Composer.php +++ b/src/Utilities/Composer.php @@ -8,8 +8,6 @@ namespace Meritoo\Common\Utilities; -use stdClass; - /** * Useful Composer-related methods (only static functions) * @@ -23,14 +21,14 @@ class Composer * * @var string */ - const FILE_NAME_MAIN = 'composer.json'; + public const FILE_NAME_MAIN = 'composer.json'; /** * Returns value from composer.json file * * @param string $composerJsonPath Path of composer.json file * @param string $nodeName Name of node who value should be returned - * @return string|null + * @return null|string */ public static function getValue($composerJsonPath, $nodeName) { @@ -63,7 +61,6 @@ class Composer return null; } - /* @var stdClass $data */ return $data->{$nodeName}; } } diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index 8b2afdb..ab60312 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -29,7 +29,7 @@ class Date * * @var string */ - const DATE_DIFFERENCE_UNIT_DAYS = 'days'; + public const DATE_DIFFERENCE_UNIT_DAYS = 'days'; /** * The 'hours' unit of date difference. @@ -37,7 +37,7 @@ class Date * * @var string */ - const DATE_DIFFERENCE_UNIT_HOURS = 'hours'; + public const DATE_DIFFERENCE_UNIT_HOURS = 'hours'; /** * The 'minutes' unit of date difference. @@ -45,7 +45,7 @@ class Date * * @var string */ - const DATE_DIFFERENCE_UNIT_MINUTES = 'minutes'; + public const DATE_DIFFERENCE_UNIT_MINUTES = 'minutes'; /** * The 'months' unit of date difference. @@ -53,7 +53,7 @@ class Date * * @var string */ - const DATE_DIFFERENCE_UNIT_MONTHS = 'months'; + public const DATE_DIFFERENCE_UNIT_MONTHS = 'months'; /** * The 'years' unit of date difference. @@ -61,14 +61,14 @@ class Date * * @var string */ - const DATE_DIFFERENCE_UNIT_YEARS = 'years'; + public const DATE_DIFFERENCE_UNIT_YEARS = 'years'; /** * Returns date's period (that contains start and end date) for given period * * @param int $period The period, type of period. One of DatePeriod class constants, e.g. DatePeriod::LAST_WEEK. * @throws Exception - * @return DatePeriod|null + * @return null|DatePeriod */ public static function getDatesForPeriod($period) { @@ -183,7 +183,7 @@ class Date * * @param string $format (optional) Format of returned value. A string acceptable by the DateTime::format() * method. - * @return string|null + * @return null|string */ public static function generateRandomTime($format = 'H:i:s') { @@ -213,9 +213,7 @@ class Date $seconds[] = $i; } - /* - * Prepare random time (hour, minute and second) - */ + // Prepare random time (hour, minute and second) $hour = $hours[array_rand($hours)]; $minute = $minutes[array_rand($minutes)]; $second = $seconds[array_rand($seconds)]; @@ -259,23 +257,17 @@ class Date $month = (int)$month; $day = (int)$day; - /* - * Oops, incorrect year - */ + // Oops, given year is incorrect if ($year <= 0) { throw UnknownDatePartTypeException::createException(DatePartType::YEAR, $year); } - /* - * Oops, incorrect month - */ + // Oops, given month is incorrect if ($month < 1 || $month > 12) { throw UnknownDatePartTypeException::createException(DatePartType::MONTH, $month); } - /* - * Oops, incorrect day - */ + // Oops, given day is incorrect if ($day < 1 || $day > 31) { throw UnknownDatePartTypeException::createException(DatePartType::DAY, $day); } @@ -353,8 +345,8 @@ class Date * If the unit of date difference is null, all units are returned in array (units are keys of the array). * Otherwise - one, integer value is returned. * - * @param string|DateTime $dateStart The start date - * @param string|DateTime $dateEnd The end date + * @param DateTime|string $dateStart The start date + * @param DateTime|string $dateEnd The end date * @param string $differenceUnit (optional) Unit of date difference. One of this class * DATE_DIFFERENCE_UNIT_* constants. If is set to null all units are * returned in the array. @@ -401,9 +393,7 @@ class Date if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_YEARS === $differenceUnit) { $diff = $end->diff($start); - /* - * Difference between dates in years should be returned only? - */ + // Difference between dates in years should be returned only? if (self::DATE_DIFFERENCE_UNIT_YEARS === $differenceUnit) { return $diff->y; } @@ -414,9 +404,7 @@ class Date if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_MONTHS === $differenceUnit) { $diff = $end->diff($start); - /* - * Difference between dates in months should be returned only? - */ + // Difference between dates in months should be returned only? if (self::DATE_DIFFERENCE_UNIT_MONTHS === $differenceUnit) { return $diff->m; } @@ -427,55 +415,41 @@ class Date if (null === $differenceUnit || in_array($differenceUnit, $relatedUnits, true)) { $days = (int)floor($dateDiff / $daySeconds); - /* - * Difference between dates in days should be returned only? - */ + // Difference between dates in days should be returned only? if (self::DATE_DIFFERENCE_UNIT_DAYS === $differenceUnit) { return $days; } - /* - * All units should be returned? - */ + // All units should be returned? if (null === $differenceUnit) { $difference[self::DATE_DIFFERENCE_UNIT_DAYS] = $days; } - /* - * Calculation for later usage - */ + // Calculation for later usage $daysInSeconds = $days * $daySeconds; } if (null === $differenceUnit || in_array($differenceUnit, $relatedUnits, true)) { $hours = (int)floor(($dateDiff - $daysInSeconds) / $hourSeconds); - /* - * Difference between dates in hours should be returned only? - */ + // Difference between dates in hours should be returned only? if (self::DATE_DIFFERENCE_UNIT_HOURS === $differenceUnit) { return $hours; } - /* - * All units should be returned? - */ + // All units should be returned? if (null === $differenceUnit) { $difference[self::DATE_DIFFERENCE_UNIT_HOURS] = $hours; } - /* - * Calculation for later usage - */ + // Calculation for later usage $hoursInSeconds = $hours * $hourSeconds; } if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_MINUTES === $differenceUnit) { $minutes = (int)floor(($dateDiff - $daysInSeconds - $hoursInSeconds) / 60); - /* - * Difference between dates in minutes should be returned only? - */ + // Difference between dates in minutes should be returned only? if (self::DATE_DIFFERENCE_UNIT_MINUTES === $differenceUnit) { return $minutes; } @@ -583,7 +557,7 @@ class Date * @param string $dateFormat (optional) Format of date used to verify if given value is actually a date. * It should be format matched to the given value, e.g. "Y-m-d H:i" for * "2015-01-01 10:00" value. Default: "Y-m-d". - * @return DateTime|bool + * @return bool|DateTime */ public static function getDateTime($value, $allowCompoundFormats = false, $dateFormat = 'Y-m-d') { @@ -710,28 +684,19 @@ class Date return false; } - /* - * Datetime to string - */ $formatted = (new DateTime())->format($format); - /* - * Formatted date it's the format who is validated? - * The format is invalid - */ + // Formatted date it's the format who is validated? + // The format is invalid if ($formatted === $format) { return false; } - /* - * Validate the format used to create the datetime - */ + // Validate the format used to create the datetime $fromFormat = DateTime::createFromFormat($format, $formatted); - /* - * It's instance of DateTime? - * The format is valid - */ + // It's instance of DateTime? + // The format is valid if ($fromFormat instanceof DateTime) { return true; } diff --git a/src/Utilities/MimeTypes.php b/src/Utilities/MimeTypes.php index 2c02b10..9b61023 100644 --- a/src/Utilities/MimeTypes.php +++ b/src/Utilities/MimeTypes.php @@ -706,9 +706,6 @@ class MimeTypes continue; } - /* - * Extensions should be returned as upper case? - */ if ($asUpperCase) { if (is_array($extension)) { array_walk($extension, function (&$value) { @@ -729,7 +726,7 @@ class MimeTypes * Returns extension for given mime type * * @param string $mimeType The mime type, e.g. "video/mpeg" - * @return string|array + * @return array|string */ public static function getExtension($mimeType) { @@ -772,29 +769,24 @@ class MimeTypes return ''; } - /* - * 1st possibility: the finfo class - */ + // 1st possibility: the finfo class if (class_exists('finfo')) { $finfo = new \finfo(); return $finfo->file($filePath, FILEINFO_MIME_TYPE); } - /* - * 2nd possibility: the mime_content_type function - */ + // 2nd possibility: the mime_content_type function if (function_exists('mime_content_type')) { return mime_content_type($filePath); } - /* - * Oops, there is no possibility to read the mime type - */ + // Oops, there is no possibility to read the mime type $template = 'Neither \'finfo\' class nor \'mime_content_type\' function exists. There is no way to read the' . ' mime type of file \'%s\'.'; $message = sprintf($template, $filePath); + throw new \RuntimeException($message); } diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index cdc1ef7..7f45397 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -27,7 +27,7 @@ class Miscellaneous * Otherwise - only content of given directory is returned. * @param int $maxFilesCount (optional) Maximum files that will be returned. If it's null, all files are * returned. - * @return array|null + * @return null|array */ public static function getDirectoryContent($directoryPath, $recursive = false, $maxFilesCount = null) { @@ -222,11 +222,6 @@ class Miscellaneous */ public static function getUniqueFileName($originalFileName, $objectId = 0) { - /* - * Get parts of the file name: - * - without extension - * - and... the extension - */ $withoutExtension = self::getFileNameWithoutExtension($originalFileName); $extension = self::getFileExtension($originalFileName, true); @@ -238,20 +233,13 @@ class Miscellaneous */ $withoutExtension = Urlizer::urlize($withoutExtension); - /* - * Now I have to complete the template used to build / generate unique name - */ + // Now I have to complete the template used to build / generate unique name $template = '%s-%s.%s'; // [file's name]-[unique key].[file's extension] - /* - * Add some uniqueness - */ + // Add some uniqueness $unique = self::getUniqueString(mt_rand()); - /* - * Finally build and return the unique name - */ - + // Finally build and return the unique name if ($objectId > 0) { $template = '%s-%s-%s.%s'; // [file's name]-[unique key]-[object ID].[file's extension] @@ -345,9 +333,7 @@ class Miscellaneous $converted = $converter->transliterate($string); - /* - * Make the string lowercase and human-readable - */ + // Make the string lowercase and human-readable if ($lowerCaseHuman) { $matches = []; $matchCount = preg_match_all('|[A-Z]{1}[^A-Z]*|', $converted, $matches); @@ -390,10 +376,10 @@ class Miscellaneous * Replaces part of string with other string or strings. * There is a few combination of what should be searched and with what it should be replaced. * - * @param string|array $subject The string or an array of strings to search and replace - * @param string|array $search String or pattern or array of patterns to find. It may be: string, an array + * @param array|string $subject The string or an array of strings to search and replace + * @param array|string $search String or pattern or array of patterns to find. It may be: string, an array * of strings or an array of patterns. - * @param string|array $replacement The string or an array of strings to replace. It may be: string or an array + * @param array|string $replacement The string or an array of strings to replace. It may be: string or an array * of strings. * @param bool $quoteStrings (optional) If is set to true, strings are surrounded with single quote sign * @return string @@ -466,9 +452,7 @@ class Miscellaneous } } - /* - * 1st step: replace strings, simple operation with strings - */ + // 1st step: replace strings, simple operation with strings if ($bothAreStrings) { $effect = str_replace($search, $replacement, $subject); } @@ -503,15 +487,10 @@ class Miscellaneous $effect = []; } - /* - * I have to make the subject an array... - */ $subject = Arrays::makeArray($subject); - /* - * ...and use iterate through the subjects, - * because explode() function expects strings as both arguments (1st and 2nd) - */ + // I have to iterate through the subjects, because explode() function expects strings as both arguments + // (1st and 2nd) foreach ($subject as $subSubject) { $subEffect = ''; @@ -521,9 +500,7 @@ class Miscellaneous foreach ($exploded as $key => $item) { $subEffect .= $item; - /* - * The replacement shouldn't be included when the searched string was not found - */ + // The replacement shouldn't be included when the searched string was not found if ($explodedCount > 1 && $key < $explodedCount - 1 && isset($replacement[$key])) { $subEffect .= $replacement[$key]; } @@ -531,6 +508,7 @@ class Miscellaneous if ($subjectIsArray) { $effect[] = $subEffect; + continue; } @@ -571,7 +549,6 @@ class Miscellaneous public static function getOperatingSystemNameServer() { return PHP_OS; - /* * Previous version: * return php_uname('s'); @@ -668,7 +645,7 @@ class Miscellaneous $spacePosition = mb_strrpos($lineWithAberration, ' ', 0, $encoding); if (false !== $spacePosition && 0 < $spacePosition) { - /* @var int $spacePosition */ + /** @var int $spacePosition */ $perLine = $spacePosition; $insertSeparator = true; } @@ -705,7 +682,7 @@ class Miscellaneous * @param string $directoryPath Directory path * @param bool $contentOnly (optional) If is set to true, only content of the directory is removed, not * directory itself. Otherwise - directory is removed too (default behaviour). - * @return bool|null + * @return null|bool */ public static function removeDirectory($directoryPath, $contentOnly = false) { @@ -735,9 +712,7 @@ class Miscellaneous } } - /* - * Directory should be removed too? - */ + // Directory should be removed too? if (!$contentOnly) { return rmdir($directoryPath); } @@ -789,7 +764,7 @@ class Miscellaneous * Make a string's first character lowercase * * @param string $text The text to get first character lowercase - * @param bool|null $restLowercase (optional) Information that to do with rest of given string + * @param null|bool $restLowercase (optional) Information that to do with rest of given string * @return string * * Values of the $restLowercase argument: @@ -818,7 +793,7 @@ class Miscellaneous * Make a string's first character uppercase * * @param string $text The text to get uppercase - * @param bool|null $restLowercase (optional) Information that to do with rest of given string + * @param null|bool $restLowercase (optional) Information that to do with rest of given string * @return string * * Values of the $restLowercase argument: @@ -932,7 +907,7 @@ class Miscellaneous * * @param string $string The string to check * @param string $separator The separator which divides elements of string - * @return string|null + * @return null|string */ public static function getLastElementOfString($string, $separator) { @@ -980,30 +955,23 @@ class Miscellaneous * - concatenatePaths(['path/first', 'path/second', 'path/third']); * - concatenatePaths('path/first', 'path/second', 'path/third'); * - * @param string|array $paths Paths co concatenate. As described above: an array of paths / strings or strings + * @param array|string $paths Paths co concatenate. As described above: an array of paths / strings or strings * passed as following arguments. * @return string */ public static function concatenatePaths($paths) { - /* - * If paths are not provided as array, get the paths from methods' arguments - */ + // If paths are not provided as array, get the paths from methods' arguments if (!is_array($paths)) { $paths = func_get_args(); } - /* - * No paths provided? - * Nothing to do - */ + // No paths provided? + // Nothing to do if (empty($paths)) { return ''; } - /* - * Some useful variables - */ $concatenated = ''; $firstWindowsBased = false; $separator = DIRECTORY_SEPARATOR; @@ -1011,16 +979,12 @@ class Miscellaneous foreach ($paths as $path) { $path = trim($path); - /* - * Empty paths are useless - */ + // Empty paths are useless if (empty($path)) { continue; } - /* - * Does the first path is a Windows-based path? - */ + // Does the first path is a Windows-based path? if (Arrays::isFirstElement($paths, $path)) { $firstWindowsBased = Regex::isWindowsBasedPath($path); @@ -1029,14 +993,10 @@ class Miscellaneous } } - /* - * Remove the starting / beginning directory's separator - */ + // Remove the starting / beginning directory's separator $path = self::removeStartingDirectorySeparator($path, $separator); - /* - * Removes the ending directory's separator - */ + // Removes the ending directory's separator $path = self::removeEndingDirectorySeparator($path, $separator); /* @@ -1046,12 +1006,11 @@ class Miscellaneous */ if ($firstWindowsBased && empty($concatenated)) { $concatenated = $path; + continue; } - /* - * Concatenate the paths / strings with OS-related directory separator between them (slash or backslash) - */ + // Concatenate the paths / strings with OS-related directory separator between them (slash or backslash) $concatenated = sprintf('%s%s%s', $concatenated, $separator, $path); } @@ -1138,22 +1097,23 @@ class Miscellaneous switch ($globalSourceType) { case INPUT_GET: $globalSource = $_GET; - break; + break; case INPUT_POST: $globalSource = $_POST; - break; + break; case INPUT_COOKIE: $globalSource = $_COOKIE; - break; + break; case INPUT_SERVER: $globalSource = $_SERVER; - break; + break; case INPUT_ENV: $globalSource = $_ENV; + break; } @@ -1201,6 +1161,7 @@ class Miscellaneous for ($i = ($length - $textLength); 0 < $i; --$i) { if ($before) { $text = '0' . $text; + continue; } @@ -1213,9 +1174,9 @@ class Miscellaneous /** * Returns information if given value is located in interval between given utmost left and right values * - * @param int|float $value Value to verify - * @param int|float $left Left utmost value of interval - * @param int|float $right Right utmost value of interval + * @param float|int $value Value to verify + * @param float|int $left Left utmost value of interval + * @param float|int $right Right utmost value of interval * @return bool */ public static function isBetween($value, $left, $right) @@ -1277,9 +1238,7 @@ class Miscellaneous */ public static function getInvertedColor($color) { - /* - * Prepare the color for later usage - */ + // Prepare the color for later usage $color = trim($color); $withHash = Regex::startsWith($color, '#'); @@ -1289,23 +1248,17 @@ class Miscellaneous */ $validColor = Regex::getValidColorHexValue($color); - /* - * Grab color's components - */ + // Grab color's components $red = hexdec(substr($validColor, 0, 2)); $green = hexdec(substr($validColor, 2, 2)); $blue = hexdec(substr($validColor, 4, 2)); - /* - * Calculate inverted color's components - */ + // Calculate inverted color's components $redInverted = self::getValidColorComponent(255 - $red); $greenInverted = self::getValidColorComponent(255 - $green); $blueInverted = self::getValidColorComponent(255 - $blue); - /* - * Voila, here is the inverted color - */ + // Voila, here is the inverted color $invertedColor = sprintf('%s%s%s', $redInverted, $greenInverted, $blueInverted); if ($withHash) { @@ -1328,9 +1281,7 @@ class Miscellaneous $fileName = 'composer.json'; $directoryPath = __DIR__; - /* - * Path of directory it's not the path of last directory? - */ + // Path of directory it's not the path of last directory? while (DIRECTORY_SEPARATOR !== $directoryPath) { $filePath = static::concatenatePaths($directoryPath, $fileName); diff --git a/src/Utilities/QueryBuilderUtility.php b/src/Utilities/QueryBuilderUtility.php index 69cc89c..8d466b0 100644 --- a/src/Utilities/QueryBuilderUtility.php +++ b/src/Utilities/QueryBuilderUtility.php @@ -27,7 +27,7 @@ class QueryBuilderUtility * If null is returned, alias was not found. * * @param QueryBuilder $queryBuilder The query builder to retrieve root alias - * @return string|null + * @return null|string */ public static function getRootAlias(QueryBuilder $queryBuilder) { @@ -52,7 +52,7 @@ class QueryBuilderUtility * * @param QueryBuilder $queryBuilder The query builder to verify * @param string $property Name of property that maybe is joined - * @return string|null + * @return null|string */ public static function getJoinedPropertyAlias(QueryBuilder $queryBuilder, $property) { @@ -70,7 +70,7 @@ class QueryBuilderUtility $pattern = sprintf($patternTemplate, $property); foreach ($joins as $joinExpressions) { - /* @var $expression Join */ + /** @var Join $expression */ foreach ($joinExpressions as $expression) { $joinedProperty = $expression->getJoin(); @@ -90,7 +90,7 @@ class QueryBuilderUtility * @param array $criteria (optional) The criteria used in WHERE clause. It may simple array with pairs * key-value or an array of arrays where second element of sub-array is the * comparison operator. Example below. - * @param string|null $alias (optional) Alias used in the query + * @param null|string $alias (optional) Alias used in the query * @return QueryBuilder * * Example of the $criteria argument: @@ -173,9 +173,7 @@ class QueryBuilderUtility $entityManager->remove($entity); } - /* - * The deleted objects should be flushed? - */ + // The deleted objects should be flushed? if ($flushDeleted) { $entityManager->flush(); } diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index fb8e3fe..23c9d65 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -74,7 +74,7 @@ class Reflection * Constants whose values are integers are considered only. * * @param object|string $class The object or name of object's class - * @return int|null + * @return null|int */ public static function getMaxNumberConstant($class) { @@ -249,6 +249,7 @@ class Reflection $value = $object->{$getterName}(); $valueFound = true; + break; } } @@ -275,7 +276,7 @@ class Reflection * Returns values of given property for given objects. * Looks for proper getter for the property. * - * @param Collection|object|array $objects The objects that should contain given property. It may be also one + * @param array|Collection|object $objects The objects that should contain given property. It may be also one * object. * @param string $property Name of the property that contains a value * @param bool $force (optional) If is set to true, try to retrieve value even if the @@ -316,7 +317,7 @@ class Reflection * @param array|object|string $source An array of objects, namespaces, object or namespace * @param bool $withoutNamespace (optional) If is set to true, namespace is omitted. Otherwise - * not, full name of class is returned, with namespace. - * @return string|null + * @return null|string */ public static function getClassName($source, $withoutNamespace = false) { @@ -338,9 +339,7 @@ class Reflection $source = Arrays::getFirstElement($source); } - /* - * Let's prepare name of class - */ + // Let's prepare name of class if (is_object($source)) { $name = get_class($source); } elseif (is_string($source) && (class_exists($source) || trait_exists($source))) { @@ -472,7 +471,7 @@ class Reflection * Returns a parent class or false if there is no parent class * * @param array|object|string $source An array of objects, namespaces, object or namespace - * @return \ReflectionClass|bool + * @return bool|\ReflectionClass */ public static function getParentClass($source) { @@ -489,7 +488,7 @@ class Reflection * @param array|object|string $class Class who child classes should be returned. An array of objects, strings, * object or string. * @throws CannotResolveClassNameException - * @return array|null + * @return null|array */ public static function getChildClasses($class) { @@ -505,9 +504,7 @@ class Reflection $className = self::getClassName($class); - /* - * Oops, cannot resolve class - */ + // Oops, cannot resolve class if (null === $className) { throw CannotResolveClassNameException::create($class); } @@ -577,7 +574,7 @@ class Reflection * @param string $property Name of the property * @param int $filter (optional) Filter of properties. Uses \ReflectionProperty class constants. * By default all properties are allowed / processed. - * @return \ReflectionProperty|null + * @return null|\ReflectionProperty */ public static function getProperty($class, $property, $filter = null) { @@ -585,7 +582,7 @@ class Reflection $properties = self::getProperties($className, $filter); if (!empty($properties)) { - /* @var $reflectionProperty \ReflectionProperty */ + /** @var \ReflectionProperty $reflectionProperty */ foreach ($properties as $reflectionProperty) { if ($reflectionProperty->getName() === $property) { return $reflectionProperty; @@ -604,23 +601,19 @@ class Reflection * @param bool $verifyParents If is set to true, parent classes are verified if they use given * trait. Otherwise - not. * @throws CannotResolveClassNameException - * @return bool|null + * @return null|bool */ public static function usesTrait($class, $trait, $verifyParents = false) { $className = self::getClassName($class); $traitName = self::getClassName($trait); - /* - * Oops, cannot resolve class - */ + // Oops, cannot resolve class if (null === $className || '' === $className) { throw CannotResolveClassNameException::create($class); } - /* - * Oops, cannot resolve trait - */ + // Oops, cannot resolve trait if (null === $traitName || '' === $traitName) { throw new CannotResolveClassNameException($class, false); } @@ -646,7 +639,7 @@ class Reflection * If given class does not extend another, returns null. * * @param array|object|string $class An array of objects, namespaces, object or namespace - * @return string|null + * @return null|string */ public static function getParentClassName($class) { @@ -673,9 +666,7 @@ class Reflection { $reflectionProperty = self::getProperty($object, $property); - /* - * Oops, property does not exist - */ + // Oops, property does not exist if (null === $reflectionProperty) { throw NotExistingPropertyException::create($object, $property); } diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index 703c540..148f3b2 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -271,7 +271,7 @@ class Regex eval(sprintf('$isEqual = %s%s;', $value, $filterExpression)); - /* @var bool $isEqual */ + /** @var bool $isEqual */ $remove = !$isEqual; } @@ -317,6 +317,7 @@ class Regex $effect = $effect && $matched; } elseif ($matched) { $effect = $matched; + break; } } @@ -458,14 +459,10 @@ class Regex return false; } - /* - * I have to escape all slashes (directory separators): "/" -> "\/" - */ + // I have to escape all slashes (directory separators): "/" -> "\/" $prepared = preg_quote($path, '/'); - /* - * Slash at the ending is optional - */ + // Slash at the ending is optional if (self::endsWith($path, '/')) { $prepared .= '?'; } @@ -775,7 +772,7 @@ class Regex * (default behaviour). Otherwise - not. * @throws IncorrectColorHexLengthException * @throws InvalidColorHexValueException - * @return string|bool + * @return bool|string */ public static function getValidColorHexValue($color, $throwException = true) { @@ -986,7 +983,7 @@ class Regex * Returns slug for given value * * @param string $value Value that should be transformed to slug - * @return string|bool + * @return bool|string */ public static function createSlug($value) { diff --git a/src/Utilities/Repository.php b/src/Utilities/Repository.php index 32dc95c..e0b8e2e 100644 --- a/src/Utilities/Repository.php +++ b/src/Utilities/Repository.php @@ -24,7 +24,7 @@ class Repository * * @var string */ - const POSITION_KEY = 'position'; + public const POSITION_KEY = 'position'; /** * Replenishes positions of given items @@ -57,24 +57,17 @@ class Repository } foreach ($items as &$item) { - /* - * The item is not sortable? - */ + // Not sortable? if (!self::isSortable($item)) { continue; } - /* - * Position has been set? - * Nothing to do - */ + // Sorted already (position has been set)? if (self::isSorted($item)) { continue; } - /* - * Calculate position - */ + // Calculate position if ($asLast) { ++$position; } else { @@ -87,6 +80,7 @@ class Repository */ if (is_object($item)) { $item->setPosition($position); + continue; } @@ -118,31 +112,23 @@ class Repository $extreme = null; foreach ($items as $item) { - /* - * The item is not sortable? - */ + // Not sortable? if (!self::isSortable($item)) { continue; } $position = null; - /* - * Let's grab the position - */ + // Let's grab the position if (is_object($item)) { $position = $item->getPosition(); } elseif (array_key_exists(static::POSITION_KEY, $item)) { $position = $item[static::POSITION_KEY]; } - /* - * Maximum value is expected? - */ + // Maximum value is expected? if ($max) { - /* - * Position was found and it's larger than previously found position (the extreme position)? - */ + // Position was found and it's larger than previously found position (the extreme position)? if (null === $extreme || (null !== $position && $position > $extreme)) { $extreme = $position; } @@ -218,17 +204,12 @@ class Repository */ private static function isSorted($item) { - /* - * Given item is not sortable? - */ + // Not sortable? if (!self::isSortable($item)) { return false; } - /* - * It's an object or it's an array - * and position has been set? - */ + // It's an object or it's an array and position has been set? return (is_object($item) && null !== $item->getPosition()) diff --git a/src/Utilities/Uri.php b/src/Utilities/Uri.php index ebc1142..f1a47b8 100644 --- a/src/Utilities/Uri.php +++ b/src/Utilities/Uri.php @@ -90,9 +90,7 @@ class Uri * $matches[2] - protocol version, e.g. 1.1 */ - /* - * Oops, cannot match protocol - */ + // Oops, cannot match protocol if (0 === $matchCount) { return ''; } @@ -244,9 +242,7 @@ class Uri $currentUrl = self::getServerNameOrIp(true); $url = self::replenishProtocol($url); - /* - * Let's prepare pattern of current url - */ + // Let's prepare pattern of current url $search = [ ':', '/', @@ -274,9 +270,7 @@ class Uri */ public static function replenishProtocol($url, $protocol = '') { - /* - * Let's trim the url - */ + // Let's trim the url if (is_string($url)) { $url = trim($url); } @@ -297,9 +291,7 @@ class Uri return $url; } - /* - * Protocol is not provided? - */ + // Protocol is not provided? if (empty($protocol)) { $protocol = self::getProtocolName(); } diff --git a/src/ValueObject/Company.php b/src/ValueObject/Company.php index 05facea..2f3ae53 100644 --- a/src/ValueObject/Company.php +++ b/src/ValueObject/Company.php @@ -44,7 +44,7 @@ class Company * * @param string $name Name of company * @param Address $address Address of company - * @param BankAccount|null $bankAccount (optional) Bank account of company + * @param null|BankAccount $bankAccount (optional) Bank account of company */ public function __construct($name, Address $address, BankAccount $bankAccount = null) { @@ -92,7 +92,7 @@ class Company /** * Returns bank account of company * - * @return BankAccount|null + * @return null|BankAccount */ public function getBankAccount() { diff --git a/src/ValueObject/Size.php b/src/ValueObject/Size.php index 1336ca1..3ad92c8 100644 --- a/src/ValueObject/Size.php +++ b/src/ValueObject/Size.php @@ -195,7 +195,7 @@ class Size * @param string $size The size represented as string (width and height separated by given separator) * @param string $unit (optional) Unit used when width or height should be returned with unit. Default: "px". * @param string $separator (optional) Separator used to split width and height. Default: " x ". - * @return Size|null + * @return null|Size */ public static function fromString($size, $unit = 'px', $separator = ' x ') { @@ -223,7 +223,7 @@ class Size * * @param array $array The size represented as array * @param string $unit (optional) Unit used when width or height should be returned with unit. Default: "px". - * @return Size|null + * @return null|Size */ public static function fromArray(array $array, $unit = 'px') { diff --git a/src/ValueObject/Version.php b/src/ValueObject/Version.php index d24bbe3..8e0ddb8 100644 --- a/src/ValueObject/Version.php +++ b/src/ValueObject/Version.php @@ -54,6 +54,16 @@ class Version $this->patchPart = $patchPart; } + /** + * Returns representation of object as string + * + * @return string + */ + public function __toString() + { + return sprintf('%d.%d.%d', $this->getMajorPart(), $this->getMinorPart(), $this->getPatchPart()); + } + /** * Returns the "major" part. * Incremented when you make incompatible API changes. @@ -87,16 +97,6 @@ class Version return $this->patchPart; } - /** - * Returns representation of object as string - * - * @return string - */ - public function __toString() - { - return sprintf('%d.%d.%d', $this->getMajorPart(), $this->getMinorPart(), $this->getPatchPart()); - } - /** * Returns new instance based on given version as string. * Given version should contain 3 dot-separated integers, 1 per each part ("major", "minor" and "patch"). @@ -106,7 +106,7 @@ class Version * "10.4.0"; * * @param string $version The version - * @return Version|null + * @return null|Version */ public static function fromString(string $version) { @@ -148,7 +148,7 @@ class Version * [10, 4, 0]; * * @param array $version The version - * @return Version|null + * @return null|Version */ public static function fromArray(array $version) { diff --git a/tests/Collection/CollectionTest.php b/tests/Collection/CollectionTest.php index 5c5112a..4a28dce 100644 --- a/tests/Collection/CollectionTest.php +++ b/tests/Collection/CollectionTest.php @@ -19,6 +19,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Collection\Collection */ class CollectionTest extends BaseTestCase { @@ -43,6 +46,24 @@ class CollectionTest extends BaseTestCase */ private $simpleElements; + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + parent::setUp(); + + $this->simpleElements = [ + 'lorem', + 'ipsum', + 123 => 'dolor', + 345 => 'sit', + ]; + + $this->emptyCollection = new Collection(); + $this->simpleCollection = new Collection($this->simpleElements); + } + public function testEmptyCollection() { static::assertSame(0, $this->emptyCollection->count()); @@ -502,22 +523,4 @@ class CollectionTest extends BaseTestCase new \DateTime('2001-01-01'), ]; } - - /** - * {@inheritdoc} - */ - protected function setUp(): void - { - parent::setUp(); - - $this->simpleElements = [ - 'lorem', - 'ipsum', - 123 => 'dolor', - 345 => 'sit', - ]; - - $this->emptyCollection = new Collection(); - $this->simpleCollection = new Collection($this->simpleElements); - } } diff --git a/tests/Exception/Base/UnknownTypeExceptionTest.php b/tests/Exception/Base/UnknownTypeExceptionTest.php index 9dc6113..6820c79 100644 --- a/tests/Exception/Base/UnknownTypeExceptionTest.php +++ b/tests/Exception/Base/UnknownTypeExceptionTest.php @@ -18,12 +18,15 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Base\UnknownTypeException */ class UnknownTypeExceptionTest extends BaseTestCase { public function testConstructorVisibilityAndArguments() { - static::assertConstructorVisibilityAndArguments(UnknownTestTypeException::class, OopVisibilityType::IS_PUBLIC, 3); + static::assertConstructorVisibilityAndArguments(UnknownTypeException::class, OopVisibilityType::IS_PUBLIC, 3); } public function testWithoutException() @@ -46,9 +49,9 @@ class UnknownTypeExceptionTest extends BaseTestCase */ class TestType extends BaseType { - const TEST_1 = 'test_1'; + public const TEST_1 = 'test_1'; - const TEST_2 = 'test_2'; + public const TEST_2 = 'test_2'; } /** @@ -56,6 +59,9 @@ class TestType extends BaseType * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Base\UnknownTypeException */ class UnknownTestTypeException extends UnknownTypeException { @@ -67,10 +73,7 @@ class UnknownTestTypeException extends UnknownTypeException */ public static function createException($unknownType) { - /* @var UnknownTestTypeException $exception */ - $exception = parent::create($unknownType, new TestType(), 'type of something used for testing'); - - return $exception; + return parent::create($unknownType, new TestType(), 'type of something used for testing'); } } diff --git a/tests/Exception/Bundle/IncorrectBundleNameExceptionTest.php b/tests/Exception/Bundle/IncorrectBundleNameExceptionTest.php index 5c2d420..69c40ab 100644 --- a/tests/Exception/Bundle/IncorrectBundleNameExceptionTest.php +++ b/tests/Exception/Bundle/IncorrectBundleNameExceptionTest.php @@ -17,6 +17,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Bundle\IncorrectBundleNameException */ class IncorrectBundleNameExceptionTest extends BaseTestCase { diff --git a/tests/Exception/Date/UnknownDatePartTypeExceptionTest.php b/tests/Exception/Date/UnknownDatePartTypeExceptionTest.php index f694ef1..13ddd0b 100644 --- a/tests/Exception/Date/UnknownDatePartTypeExceptionTest.php +++ b/tests/Exception/Date/UnknownDatePartTypeExceptionTest.php @@ -19,6 +19,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Type\UnknownDatePartTypeException */ class UnknownDatePartTypeExceptionTest extends BaseTestCase { diff --git a/tests/Exception/File/EmptyFileExceptionTest.php b/tests/Exception/File/EmptyFileExceptionTest.php index a2ee08d..f209bfe 100644 --- a/tests/Exception/File/EmptyFileExceptionTest.php +++ b/tests/Exception/File/EmptyFileExceptionTest.php @@ -18,6 +18,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\File\EmptyFileException */ class EmptyFileExceptionTest extends BaseTestCase { diff --git a/tests/Exception/File/EmptyFilePathExceptionTest.php b/tests/Exception/File/EmptyFilePathExceptionTest.php index b582579..97a2eff 100644 --- a/tests/Exception/File/EmptyFilePathExceptionTest.php +++ b/tests/Exception/File/EmptyFilePathExceptionTest.php @@ -17,6 +17,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\File\EmptyFilePathException */ class EmptyFilePathExceptionTest extends BaseTestCase { diff --git a/tests/Exception/File/NotExistingFileExceptionTest.php b/tests/Exception/File/NotExistingFileExceptionTest.php index 08f8868..ce01a93 100644 --- a/tests/Exception/File/NotExistingFileExceptionTest.php +++ b/tests/Exception/File/NotExistingFileExceptionTest.php @@ -18,6 +18,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\File\NotExistingFileException */ class NotExistingFileExceptionTest extends BaseTestCase { diff --git a/tests/Exception/Method/DisabledMethodExceptionTest.php b/tests/Exception/Method/DisabledMethodExceptionTest.php index a815b4e..c7d4613 100644 --- a/tests/Exception/Method/DisabledMethodExceptionTest.php +++ b/tests/Exception/Method/DisabledMethodExceptionTest.php @@ -18,6 +18,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Method\DisabledMethodException */ class DisabledMethodExceptionTest extends BaseTestCase { diff --git a/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php b/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php index c6f9082..5d4c8d6 100644 --- a/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php +++ b/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php @@ -18,6 +18,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Reflection\CannotResolveClassNameException */ class CannotResolveClassNameExceptionTest extends BaseTestCase { diff --git a/tests/Exception/Reflection/MissingChildClassesExceptionTest.php b/tests/Exception/Reflection/MissingChildClassesExceptionTest.php index 900d6e2..7da3484 100644 --- a/tests/Exception/Reflection/MissingChildClassesExceptionTest.php +++ b/tests/Exception/Reflection/MissingChildClassesExceptionTest.php @@ -18,6 +18,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Reflection\MissingChildClassesException */ class MissingChildClassesExceptionTest extends BaseTestCase { diff --git a/tests/Exception/Reflection/NotExistingPropertyExceptionTest.php b/tests/Exception/Reflection/NotExistingPropertyExceptionTest.php index e172003..aadd974 100644 --- a/tests/Exception/Reflection/NotExistingPropertyExceptionTest.php +++ b/tests/Exception/Reflection/NotExistingPropertyExceptionTest.php @@ -17,6 +17,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Reflection\NotExistingPropertyException */ class NotExistingPropertyExceptionTest extends BaseTestCase { diff --git a/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php b/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php index 3c19cad..9bb26b0 100644 --- a/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php +++ b/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php @@ -18,6 +18,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Reflection\TooManyChildClassesException */ class TooManyChildClassesExceptionTest extends BaseTestCase { diff --git a/tests/Exception/Regex/IncorrectColorHexLengthExceptionTest.php b/tests/Exception/Regex/IncorrectColorHexLengthExceptionTest.php index 9482dbd..36c3fbb 100644 --- a/tests/Exception/Regex/IncorrectColorHexLengthExceptionTest.php +++ b/tests/Exception/Regex/IncorrectColorHexLengthExceptionTest.php @@ -18,6 +18,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Regex\IncorrectColorHexLengthException */ class IncorrectColorHexLengthExceptionTest extends BaseTestCase { diff --git a/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php b/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php index ec32268..1de82d3 100644 --- a/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php +++ b/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php @@ -18,6 +18,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Regex\InvalidColorHexValueException */ class InvalidColorHexValueExceptionTest extends BaseTestCase { diff --git a/tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php b/tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php index 6772791..6b3cc33 100644 --- a/tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php +++ b/tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php @@ -18,6 +18,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Regex\InvalidHtmlAttributesException */ class InvalidHtmlAttributesExceptionTest extends BaseTestCase { diff --git a/tests/Exception/Regex/InvalidUrlExceptionTest.php b/tests/Exception/Regex/InvalidUrlExceptionTest.php index 0e36d77..0910d0f 100644 --- a/tests/Exception/Regex/InvalidUrlExceptionTest.php +++ b/tests/Exception/Regex/InvalidUrlExceptionTest.php @@ -18,6 +18,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Regex\InvalidUrlException */ class InvalidUrlExceptionTest extends BaseTestCase { diff --git a/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php b/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php index 3f8377b..f5440ad 100644 --- a/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php +++ b/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php @@ -19,6 +19,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Type\UnknownOopVisibilityTypeException */ class UnknownOopVisibilityTypeExceptionTest extends BaseTestCase { diff --git a/tests/Exception/ValueObject/InvalidSizeDimensionsExceptionTest.php b/tests/Exception/ValueObject/InvalidSizeDimensionsExceptionTest.php index ece3449..87422e5 100644 --- a/tests/Exception/ValueObject/InvalidSizeDimensionsExceptionTest.php +++ b/tests/Exception/ValueObject/InvalidSizeDimensionsExceptionTest.php @@ -17,6 +17,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\ValueObject\InvalidSizeDimensionsException */ class InvalidSizeDimensionsExceptionTest extends BaseTestCase { diff --git a/tests/Test/Base/BaseTestCaseTest.php b/tests/Test/Base/BaseTestCaseTest.php index 4976db6..83d024d 100644 --- a/tests/Test/Base/BaseTestCaseTest.php +++ b/tests/Test/Base/BaseTestCaseTest.php @@ -19,6 +19,9 @@ use Meritoo\Common\Utilities\GeneratorUtility; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Test\Base\BaseTestCase */ class BaseTestCaseTest extends BaseTestCase { @@ -67,16 +70,16 @@ class BaseTestCaseTest extends BaseTestCase $generator = (new SimpleTestCase())->provideDateTimeInstance(); $generatedElements = GeneratorUtility::getGeneratorElements($generator); - /* @var DateTime $instance1 */ + /** @var DateTime $instance1 */ $instance1 = $generatedElements[0][0]; - /* @var DateTime $instance2 */ + /** @var DateTime $instance2 */ $instance2 = $generatedElements[1][0]; - /* @var DateTime $instance3 */ + /** @var DateTime $instance3 */ $instance3 = $generatedElements[2][0]; - /* @var DateTime $instance4 */ + /** @var DateTime $instance4 */ $instance4 = $generatedElements[3][0]; self::assertCount(count($expectedElements), $generatedElements); @@ -170,6 +173,9 @@ class BaseTestCaseTest extends BaseTestCase * * @author Meritoo * @copyright Meritoo + * + * @internal + * @coversNothing */ class SimpleTestCase extends BaseTestCase { diff --git a/tests/Type/Base/BaseTypeTest.php b/tests/Type/Base/BaseTypeTest.php index f21a1dc..99decad 100644 --- a/tests/Type/Base/BaseTypeTest.php +++ b/tests/Type/Base/BaseTypeTest.php @@ -17,6 +17,9 @@ use Meritoo\Common\Type\Base\BaseType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Type\Base\BaseType */ class BaseTypeTest extends BaseTestCase { @@ -199,7 +202,7 @@ class TestEmptyType extends BaseType */ class TestType extends BaseType { - const TEST_1 = 'test_1'; + public const TEST_1 = 'test_1'; - const TEST_2 = 'test_2'; + public const TEST_2 = 'test_2'; } diff --git a/tests/Type/DatePartTypeTest.php b/tests/Type/DatePartTypeTest.php index 782c259..73e5d2f 100644 --- a/tests/Type/DatePartTypeTest.php +++ b/tests/Type/DatePartTypeTest.php @@ -16,6 +16,9 @@ use Meritoo\Common\Type\DatePartType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Type\DatePartType */ class DatePartTypeTest extends BaseTypeTestCase { diff --git a/tests/Type/DatePeriodTest.php b/tests/Type/DatePeriodTest.php index a73ceaf..fdfed51 100644 --- a/tests/Type/DatePeriodTest.php +++ b/tests/Type/DatePeriodTest.php @@ -19,6 +19,9 @@ use Meritoo\Common\Type\OopVisibilityType; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Type\DatePeriod */ class DatePeriodTest extends BaseTypeTestCase { @@ -151,9 +154,7 @@ class DatePeriodTest extends BaseTypeTestCase $startDate = new DateTime('2001-01-01'); $endDate = new DateTime('2002-02-02'); - /* - * For start date - */ + // For start date yield[ new DatePeriod($startDate, $endDate), 'Y', @@ -182,9 +183,7 @@ class DatePeriodTest extends BaseTypeTestCase '2001-01-01 00:00', ]; - /* - * For end date - */ + // For end date yield[ new DatePeriod($startDate, $endDate), 'Y', diff --git a/tests/Utilities/ArraysTest.php b/tests/Utilities/ArraysTest.php index 3fd87bf..3882298 100644 --- a/tests/Utilities/ArraysTest.php +++ b/tests/Utilities/ArraysTest.php @@ -18,6 +18,9 @@ use Meritoo\Test\Common\Utilities\Arrays\SimpleToString; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\Arrays */ class ArraysTest extends BaseTestCase { @@ -27,6 +30,132 @@ class ArraysTest extends BaseTestCase private $complexArray; private $superComplexArray; + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + parent::setUp(); + + $this->simpleArray = [ + 'Lorem', + 'ipsum', + 'dolor', + 'sit', + 'amet', + ]; + + $this->simpleArrayWithKeys = [ + 'Lorem' => 'ipsum', + 'dolor' => 'sit', + 'amet' => 'consectetur', + ]; + + $this->twoDimensionsArray = [ + [ + 'lorem', + 'ipsum', + 'dolor', + 'sit', + 'amet', + ], + [ + 'consectetur', + 'adipiscing', + 'elit', + ], + [ + 'donec', + 'sagittis', + 'fringilla', + 'eleifend', + ], + ]; + + $this->complexArray = [ + 'lorem' => [ + 'ipsum' => [ + 'dolor' => 'sit', + 'diam' => [ + 'non' => 'egestas', + ], + ], + ], + 'consectetur' => 'adipiscing', + 'mollis' => 1234, + 2 => [], + 'sit' => [ + 'nullam' => 'donec', + 'aliquet' => [ + 'vitae' => [ + 'ligula' => 'quis', + ], + ], + 'elit', + ], + 'amet' => [ + 'iaculis', + 'primis', + ], + ]; + + $this->superComplexArray = [ + 'ipsum' => [ + 'quis' => [ + 'vestibulum' => [ + 'porta-1' => [ + 'turpis', + 'urna', + ], + 'porta-2' => [ + 'tortor' => [ + 'in' => [ + 'dui', + 'dolor' => [ + 'aliquam', + ], + ], + ], + ], + 'porta-3' => [ + 1, + 2, + 3, + ], + ], + ], + ], + 'primis' => [ + [ + 'in', + 'faucibus', + 'orci', + ], + [ + 'luctus', + 'et', + 'ultrices', + ], + ], + ]; + } + + /** + * {@inheritdoc} + */ + protected function tearDown(): void + { + parent::tearDown(); + + unset( + $this->simpleArray, + $this->simpleArrayWithKeys, + $this->twoDimensionsArray, + $this->complexArray, + $this->superComplexArray + ); + } + public function testConstructor() { static::assertHasNoConstructor(Arrays::class); @@ -136,7 +265,8 @@ class ArraysTest extends BaseTestCase self::assertSame($expected, Arrays::values2csv($array, $separator), $description); self::assertSame('', Arrays::values2csv($this->simpleArray), 'Simple array'); - self::assertSame("lorem,ipsum,dolor,sit,amet\n" + self::assertSame( + "lorem,ipsum,dolor,sit,amet\n" . "consectetur,adipiscing,elit\n" . 'donec,sagittis,fringilla,eleifend', Arrays::values2csv($this->twoDimensionsArray), @@ -146,14 +276,10 @@ class ArraysTest extends BaseTestCase public function testGetFirstKey() { - /* - * Negative cases - */ + // Negative cases self::assertNull(Arrays::getFirstKey([])); - /* - * Positive cases - */ + // Positive cases self::assertEquals(0, Arrays::getFirstKey($this->simpleArray)); self::assertEquals('lorem', Arrays::getFirstKey($this->complexArray)); } @@ -167,14 +293,10 @@ class ArraysTest extends BaseTestCase public function testGetFirstElement() { - /* - * Negative cases - */ + // Negative cases self::assertNull(Arrays::getFirstElement([])); - /* - * Positive cases - */ + // Positive cases self::assertEquals('Lorem', Arrays::getFirstElement($this->simpleArray)); self::assertEquals('Lorem', Arrays::getFirstElement($this->simpleArray)); self::assertEquals('lorem', Arrays::getFirstElement($this->twoDimensionsArray, false)); @@ -191,14 +313,10 @@ class ArraysTest extends BaseTestCase public function testGetLastElement() { - /* - * Negative cases - */ + // Negative cases self::assertNull(Arrays::getLastElement([])); - /* - * Positive cases - */ + // Positive cases self::assertEquals('amet', Arrays::getLastElement($this->simpleArray)); self::assertEquals('eleifend', Arrays::getLastElement($this->twoDimensionsArray, false)); self::assertEquals('primis', Arrays::getLastElement($this->complexArray, false)); @@ -222,14 +340,10 @@ class ArraysTest extends BaseTestCase public function testGetLastRow() { - /* - * Negative cases - */ + // Negative cases self::assertNull(Arrays::getLastRow([])); - /* - * Positive cases - */ + // Positive cases self::assertEquals([], Arrays::getLastRow($this->simpleArray)); self::assertEquals([], Arrays::getLastRow($this->simpleArrayWithKeys)); @@ -275,14 +389,10 @@ class ArraysTest extends BaseTestCase public function testArray2JavaScript() { - /* - * Negative cases - */ + // Negative cases self::assertNull(Arrays::array2JavaScript([])); - /* - * Positive cases - */ + // Positive cases self::assertEquals('new Array(\'Lorem\', \'ipsum\', \'dolor\', \'sit\', \'amet\');', Arrays::array2JavaScript($this->simpleArray)); self::assertEquals('var letsTest = new Array(\'Lorem\', \'ipsum\', \'dolor\', \'sit\', \'amet\');', Arrays::array2JavaScript($this->simpleArray, 'letsTest')); @@ -350,7 +460,7 @@ letsTest[2] = value_2;'; /** * @param string $description Description of test case - * @param array|null $expected Expected new array (with quoted elements) + * @param null|array $expected Expected new array (with quoted elements) * @param array $array The array to check for string values * * @dataProvider provideArrayToQuoteStrings @@ -365,9 +475,7 @@ letsTest[2] = value_2;'; $array = $this->simpleArray; $string = 'Lorem ipsum'; - /* - * Removing first element - */ + // Removing first element self::assertSame([ 0 => 'Lorem', 1 => 'ipsum', @@ -376,9 +484,7 @@ letsTest[2] = value_2;'; ], Arrays::removeMarginalElement($array)); self::assertEquals('Lorem ipsu', Arrays::removeMarginalElement($string)); - /* - * Removing last element - */ + // Removing last element self::assertSame([ 1 => 'ipsum', 2 => 'dolor', @@ -489,14 +595,10 @@ letsTest[2] = value_2;'; public function testGetNonArrayElementsCount() { - /* - * Negative cases - */ + // Negative cases self::assertNull(Arrays::getNonArrayElementsCount([])); - /* - * Positive cases - */ + // Positive cases self::assertEquals(5, Arrays::getNonArrayElementsCount($this->simpleArray)); self::assertEquals(3, Arrays::getNonArrayElementsCount($this->simpleArrayWithKeys)); self::assertEquals(12, Arrays::getNonArrayElementsCount($this->twoDimensionsArray)); @@ -504,15 +606,11 @@ letsTest[2] = value_2;'; public function testString2array() { - /* - * Negative cases - */ + // Negative cases self::assertNull(Arrays::string2array('')); self::assertNull(Arrays::string2array(null)); - /* - * Positive cases - */ + // Positive cases $array = [ 'light' => '#fff', 'dark' => '#000', @@ -534,9 +632,7 @@ letsTest[2] = value_2;'; public function testAreKeysInArray() { - /* - * Negative cases - */ + // Negative cases self::assertFalse(Arrays::areKeysInArray([], [])); self::assertFalse(Arrays::areKeysInArray([null], $this->simpleArray)); self::assertFalse(Arrays::areKeysInArray([''], $this->simpleArray)); @@ -552,9 +648,7 @@ letsTest[2] = value_2;'; self::assertFalse(Arrays::areKeysInArray($keys1, $this->complexArray)); self::assertFalse(Arrays::areKeysInArray($keys1, $this->complexArray, false)); - /* - * Positive cases - */ + // Positive cases $keys12 = [ 2, 'mollis', @@ -607,9 +701,7 @@ letsTest[2] = value_2;'; public function testGetLastElementsPathsUsingDefaults() { - /* - * Using default separator and other default arguments - */ + // Using default separator and other default arguments $expected = [ 'lorem.ipsum.dolor' => 'sit', 'lorem.ipsum.diam.non' => 'egestas', @@ -628,9 +720,7 @@ letsTest[2] = value_2;'; public function testGetLastElementsPathsUsingCustomSeparator() { - /* - * Using custom separator - */ + // Using custom separator $separator = ' -> '; $expected = [ sprintf('lorem%sipsum%sdolor', $separator, $separator) => 'sit', @@ -649,7 +739,7 @@ letsTest[2] = value_2;'; } /** - * @param string|array $stopIfMatchedBy Patterns of keys or paths that matched will stop the process of path + * @param array|string $stopIfMatchedBy Patterns of keys or paths that matched will stop the process of path * building and including children of those keys or paths (recursive will * not be used for keys in lower level of given array) * @param string $separator Separator used in resultant strings. Default: ".". @@ -666,19 +756,13 @@ letsTest[2] = value_2;'; { $pattern = '\d+'; - /* - * Empty array - */ + // Empty array self::assertFalse(Arrays::areAllKeysMatchedByPattern([], $pattern)); - /* - * Simple array with integers as keys only - */ + // Simple array with integers as keys only self::assertTrue(Arrays::areAllKeysMatchedByPattern($this->simpleArray, $pattern)); - /* - * Complex array with strings and integers as keys - */ + // Complex array with strings and integers as keys self::assertFalse(Arrays::areAllKeysMatchedByPattern($this->complexArray, $pattern)); $array = [ @@ -686,33 +770,23 @@ letsTest[2] = value_2;'; 'c' => 'd', ]; - /* - * Yet another simple array, but with strings as keys - */ + // Yet another simple array, but with strings as keys self::assertFalse(Arrays::areAllKeysMatchedByPattern($array, $pattern)); - /* - * The same array with another pattern - */ + // The same array with another pattern $pattern = '\w+'; self::assertTrue(Arrays::areAllKeysMatchedByPattern($array, $pattern)); - /* - * The same array with mixed keys (strings and integers as keys) - */ + // The same array with mixed keys (strings and integers as keys) $array[1] = 'x'; $pattern = '\d+'; self::assertFalse(Arrays::areAllKeysMatchedByPattern($array, $pattern)); - /* - * Multidimensional array - negative case - */ + // Multidimensional array - negative case $array['e'] = ['f' => 'g']; self::assertFalse(Arrays::areAllKeysMatchedByPattern($array, $pattern)); - /* - * Multidimensional array - positive case - */ + // Multidimensional array - positive case unset($array[1]); $pattern = '\w+'; self::assertTrue(Arrays::areAllKeysMatchedByPattern($array, $pattern)); @@ -728,14 +802,10 @@ letsTest[2] = value_2;'; public function testIssetRecursive() { - /* - * Negative cases - */ + // Negative cases self::assertFalse(Arrays::issetRecursive([], [])); - /* - * Positive cases - */ + // Positive cases $unExistingKeys = [ 'a', 'b', @@ -778,14 +848,10 @@ letsTest[2] = value_2;'; public function testGetValueByKeysPath() { - /* - * Negative cases - */ + // Negative cases self::assertNull(Arrays::getValueByKeysPath([], [])); - /* - * Positive cases - */ + // Positive cases self::assertNull(Arrays::getValueByKeysPath($this->simpleArray, [])); self::assertEquals('ipsum', Arrays::getValueByKeysPath($this->simpleArray, [1])); self::assertEquals('sit', Arrays::getValueByKeysPath($this->simpleArray, [3])); @@ -839,14 +905,10 @@ letsTest[2] = value_2;'; public function testGetAllValuesOfKey() { - /* - * Positive case - 1-dimension array - */ + // Positive case - 1-dimension array self::assertEquals(['ipsum'], Arrays::getAllValuesOfKey($this->simpleArray, 1)); - /* - * Positive case - 2-dimensions array - */ + // Positive case - 2-dimensions array $effect = [ [ 'lorem', @@ -861,14 +923,10 @@ letsTest[2] = value_2;'; self::assertEquals($effect, Arrays::getAllValuesOfKey($this->twoDimensionsArray, 0)); - /* - * Positive case - multi-dimensions array - */ + // Positive case - multi-dimensions array self::assertEquals(['primis'], Arrays::getAllValuesOfKey($this->complexArray, 1)); - /* - * Positive case - multi-dimensions array - */ + // Positive case - multi-dimensions array $effect = [ 0 => [ 'in' => [ @@ -885,22 +943,16 @@ letsTest[2] = value_2;'; public function testKsortRecursive() { - /* - * Negative cases - */ + // Negative cases $array = []; self::assertNull(Arrays::ksortRecursive($array)); - /* - * Positive cases - */ + // Positive cases self::assertEquals($this->simpleArray, Arrays::ksortRecursive($this->simpleArray)); self::assertEquals($this->simpleArray, Arrays::ksortRecursive($this->simpleArray, SORT_NUMERIC)); self::assertEquals($this->twoDimensionsArray, Arrays::ksortRecursive($this->twoDimensionsArray)); - /* - * Positive case - multi-dimensions array - */ + // Positive case - multi-dimensions array $effect = [ 'amet' => [ 'iaculis', @@ -930,9 +982,7 @@ letsTest[2] = value_2;'; self::assertEquals($effect, Arrays::ksortRecursive($this->complexArray)); - /* - * Positive case - multi-dimensions array - with options of ksort() function - */ + // Positive case - multi-dimensions array - with options of ksort() function $effect = [ 2 => [], 'amet' => [ @@ -965,23 +1015,17 @@ letsTest[2] = value_2;'; public function testSetPositions() { - /* - * Negative cases - */ + // Negative cases self::assertNull(Arrays::setPositions([])); - /* - * Positive case - 1-dimension array - */ + // Positive case - 1-dimension array $array = [ 'abc', ]; self::assertEquals($array, Arrays::setPositions($array)); - /* - * Positive case - 2-dimensions array - */ + // Positive case - 2-dimensions array $effect = $this->twoDimensionsArray; $effect[0][Arrays::POSITION_KEY_NAME] = 1; $effect[1][Arrays::POSITION_KEY_NAME] = 2; @@ -989,9 +1033,7 @@ letsTest[2] = value_2;'; self::assertEquals($effect, Arrays::setPositions($this->twoDimensionsArray)); - /* - * Positive case - multi-level array - */ + // Positive case - multi-level array $array = [ 'lorem', 'ipsum' => [ @@ -1034,9 +1076,7 @@ letsTest[2] = value_2;'; self::assertEquals($effect, Arrays::setPositions($array)); - /* - * Positive case - non-default name of key with position value & 2-dimensions array - */ + // Positive case - non-default name of key with position value & 2-dimensions array $keyName = 'level'; $effect = $this->twoDimensionsArray; @@ -1046,9 +1086,7 @@ letsTest[2] = value_2;'; self::assertEquals($effect, Arrays::setPositions($this->twoDimensionsArray, $keyName)); - /* - * Positive case - non-default start value of position & 2-dimensions array - */ + // Positive case - non-default start value of position & 2-dimensions array $startPosition = 5; $effect = $this->twoDimensionsArray; @@ -1062,14 +1100,10 @@ letsTest[2] = value_2;'; public function testTrimRecursive() { - /* - * Negative cases - */ + // Negative cases self::assertSame([], Arrays::trimRecursive([])); - /* - * Positive cases - */ + // Positive cases self::assertEquals(['a'], Arrays::trimRecursive([' a '])); self::assertEquals([ 'a', @@ -1126,14 +1160,10 @@ letsTest[2] = value_2;'; public function testSortByCustomKeysOrder() { - /* - * Negative cases - */ + // Negative cases self::assertNull(Arrays::sortByCustomKeysOrder([], [])); - /* - * Positive cases - */ + // Positive cases self::assertEquals([0], Arrays::sortByCustomKeysOrder([0], [])); self::assertEquals($this->simpleArray, Arrays::sortByCustomKeysOrder($this->simpleArray, [])); @@ -1204,19 +1234,13 @@ letsTest[2] = value_2;'; { $separator = '/'; - /* - * Empty array - */ + // Empty array self::assertNull(Arrays::implodeSmart([], $separator)); - /* - * Simple, one-dimension array - */ + // Simple, one-dimension array self::assertEquals(implode($separator, $this->simpleArray), Arrays::implodeSmart($this->simpleArray, $separator)); - /* - * An array with elements that contain separator - */ + // An array with elements that contain separator $array = [ 'lorem' . $separator, 'ipsum', @@ -1229,9 +1253,7 @@ letsTest[2] = value_2;'; 'dolor', ]), Arrays::implodeSmart($array, $separator)); - /* - * Complex array - */ + // Complex array self::assertEquals(implode($separator, [ 'donec', 'quis', @@ -1241,51 +1263,39 @@ letsTest[2] = value_2;'; public function testGetNextElement() { - /* - * Negative cases - */ + // Negative cases self::assertNull(Arrays::getNextElement($this->simpleArray, 'amet')); self::assertNull(Arrays::getNextElement($this->simpleArray, 'xyz')); self::assertNull(Arrays::getNextElement($this->simpleArray, 0)); self::assertNull(Arrays::getNextElement([], '')); self::assertNull(Arrays::getNextElement([], null)); - /* - * Positive cases - */ + // Positive cases self::assertEquals('ipsum', Arrays::getNextElement($this->simpleArray, 'Lorem')); self::assertEquals('sit', Arrays::getNextElement($this->simpleArray, 'dolor')); } public function testGetPreviousElement() { - /* - * Negative cases - */ + // Negative cases self::assertNull(Arrays::getPreviousElement($this->simpleArray, 'Lorem')); self::assertNull(Arrays::getPreviousElement($this->simpleArray, 'xyz')); self::assertNull(Arrays::getPreviousElement($this->simpleArray, 0)); self::assertNull(Arrays::getPreviousElement([], '')); self::assertNull(Arrays::getPreviousElement([], null)); - /* - * Positive cases - */ + // Positive cases self::assertEquals('ipsum', Arrays::getPreviousElement($this->simpleArray, 'dolor')); self::assertEquals('sit', Arrays::getPreviousElement($this->simpleArray, 'amet')); } public function testGetIndexOf() { - /* - * Negative cases - */ + // Negative cases self::assertFalse(Arrays::getIndexOf([], 'a')); self::assertNull(Arrays::getIndexOf($this->simpleArray, 'loremmm')); - /* - * Positive cases - */ + // Positive cases self::assertEquals(1, Arrays::getIndexOf($this->simpleArray, 'ipsum')); self::assertEquals('dolor', Arrays::getIndexOf($this->simpleArrayWithKeys, 'sit')); self::assertEquals('mollis', Arrays::getIndexOf($this->complexArray, 1234)); @@ -1293,14 +1303,10 @@ letsTest[2] = value_2;'; public function testIncrementIndexes() { - /* - * Negative cases - */ + // Negative cases self::assertNull(Arrays::incrementIndexes([])); - /* - * Positive cases - */ + // Positive cases $array = [ 1 => 'Lorem', 2 => 'ipsum', @@ -1331,9 +1337,7 @@ letsTest[2] = value_2;'; public function testAreAllValuesEmpty() { - /* - * Negative cases - */ + // Negative cases self::assertFalse(Arrays::areAllValuesEmpty([])); self::assertFalse(Arrays::areAllValuesEmpty([], true)); self::assertFalse(Arrays::areAllValuesEmpty($this->simpleArray)); @@ -1353,9 +1357,7 @@ letsTest[2] = value_2;'; ]; self::assertFalse(Arrays::areAllValuesEmpty($array, true)); - /* - * Positive cases - */ + // Positive cases $array = [ '', 0, @@ -1371,15 +1373,11 @@ letsTest[2] = value_2;'; public function testDiffRecursive() { - /* - * Negative cases - */ + // Negative cases self::assertEquals([], Arrays::arrayDiffRecursive([], [])); self::assertEquals([], Arrays::arrayDiffRecursive([], [], true)); - /* - * Positive cases - full comparison (keys and values) - */ + // Positive cases - full comparison (keys and values) self::assertEquals(['a'], Arrays::arrayDiffRecursive(['a'], [])); self::assertEquals([], Arrays::arrayDiffRecursive([], ['a'])); self::assertEquals([], Arrays::arrayDiffRecursive($this->simpleArray, $this->simpleArray)); @@ -1432,9 +1430,7 @@ letsTest[2] = value_2;'; self::assertEquals($this->twoDimensionsArray[1], Arrays::arrayDiffRecursive($this->twoDimensionsArray[1], $this->twoDimensionsArray)); - /* - * Positive cases - simple comparison (values only) - */ + // Positive cases - simple comparison (values only) self::assertEquals(['a'], Arrays::arrayDiffRecursive(['a'], [], true)); $array = [ @@ -1533,35 +1529,25 @@ letsTest[2] = value_2;'; public function testGetDimensionsCount() { - /* - * Basic cases - */ + // Basic cases self::assertEquals(0, Arrays::getDimensionsCount([])); self::assertEquals(1, Arrays::getDimensionsCount([''])); - /* - * Simple cases - */ + // Simple cases self::assertEquals(1, Arrays::getDimensionsCount($this->simpleArray)); self::assertEquals(1, Arrays::getDimensionsCount($this->simpleArrayWithKeys)); - /* - * Complex cases - */ + // Complex cases self::assertEquals(2, Arrays::getDimensionsCount($this->twoDimensionsArray)); self::assertEquals(4, Arrays::getDimensionsCount($this->complexArray)); } public function testIsMultiDimensional() { - /* - * Negative cases - */ + // Negative cases self::assertNull(Arrays::isMultiDimensional([])); - /* - * Positive cases - */ + // Positive cases self::assertFalse(Arrays::isMultiDimensional($this->simpleArray)); self::assertFalse(Arrays::isMultiDimensional($this->simpleArrayWithKeys)); @@ -1717,9 +1703,7 @@ letsTest[2] = value_2;'; */ public function provideStopIfMatchedByForGetLastElementsPaths() { - /* - * Special exception: do not use, stop recursive on the "diam" key - */ + // Special exception: do not use, stop recursive on the "diam" key yield[ 'diam', '.', @@ -1780,9 +1764,7 @@ letsTest[2] = value_2;'; ], ]; - /* - * Stop building of paths on more sophisticated keys - */ + // Stop building of paths on more sophisticated keys yield[ [ 'porta\-\d+', @@ -1857,9 +1839,7 @@ letsTest[2] = value_2;'; ], ]; - /* - * Stop building of paths on these paths (verify paths only) - */ + // Stop building of paths on these paths (verify paths only) yield[ [ 'ipsum > quis > vestibulum > porta-1', @@ -1894,9 +1874,7 @@ letsTest[2] = value_2;'; ], ]; - /* - * Stop building of paths if path contains any of these part (verify part of paths only) - */ + // Stop building of paths if path contains any of these part (verify part of paths only) yield[ [ 'vestibulum > porta-1', @@ -2701,130 +2679,4 @@ letsTest[2] = value_2;'; ], ]; } - - /** - * {@inheritdoc} - */ - protected function setUp(): void - { - parent::setUp(); - - $this->simpleArray = [ - 'Lorem', - 'ipsum', - 'dolor', - 'sit', - 'amet', - ]; - - $this->simpleArrayWithKeys = [ - 'Lorem' => 'ipsum', - 'dolor' => 'sit', - 'amet' => 'consectetur', - ]; - - $this->twoDimensionsArray = [ - [ - 'lorem', - 'ipsum', - 'dolor', - 'sit', - 'amet', - ], - [ - 'consectetur', - 'adipiscing', - 'elit', - ], - [ - 'donec', - 'sagittis', - 'fringilla', - 'eleifend', - ], - ]; - - $this->complexArray = [ - 'lorem' => [ - 'ipsum' => [ - 'dolor' => 'sit', - 'diam' => [ - 'non' => 'egestas', - ], - ], - ], - 'consectetur' => 'adipiscing', - 'mollis' => 1234, - 2 => [], - 'sit' => [ - 'nullam' => 'donec', - 'aliquet' => [ - 'vitae' => [ - 'ligula' => 'quis', - ], - ], - 'elit', - ], - 'amet' => [ - 'iaculis', - 'primis', - ], - ]; - - $this->superComplexArray = [ - 'ipsum' => [ - 'quis' => [ - 'vestibulum' => [ - 'porta-1' => [ - 'turpis', - 'urna', - ], - 'porta-2' => [ - 'tortor' => [ - 'in' => [ - 'dui', - 'dolor' => [ - 'aliquam', - ], - ], - ], - ], - 'porta-3' => [ - 1, - 2, - 3, - ], - ], - ], - ], - 'primis' => [ - [ - 'in', - 'faucibus', - 'orci', - ], - [ - 'luctus', - 'et', - 'ultrices', - ], - ], - ]; - } - - /** - * {@inheritdoc} - */ - protected function tearDown(): void - { - parent::tearDown(); - - unset( - $this->simpleArray, - $this->simpleArrayWithKeys, - $this->twoDimensionsArray, - $this->complexArray, - $this->superComplexArray - ); - } } diff --git a/tests/Utilities/Bootstrap4CssSelectorTest.php b/tests/Utilities/Bootstrap4CssSelectorTest.php index ee6787d..bda9bc4 100644 --- a/tests/Utilities/Bootstrap4CssSelectorTest.php +++ b/tests/Utilities/Bootstrap4CssSelectorTest.php @@ -16,6 +16,9 @@ use Meritoo\Common\Utilities\Bootstrap4CssSelector; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\Bootstrap4CssSelector */ class Bootstrap4CssSelectorTest extends BaseTestCase { diff --git a/tests/Utilities/BundleTest.php b/tests/Utilities/BundleTest.php index 03e9340..12507ee 100644 --- a/tests/Utilities/BundleTest.php +++ b/tests/Utilities/BundleTest.php @@ -18,6 +18,9 @@ use Meritoo\Common\Utilities\Bundle; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\Bundle */ class BundleTest extends BaseTestCase { diff --git a/tests/Utilities/ComposerTest.php b/tests/Utilities/ComposerTest.php index e8f8117..9980e62 100644 --- a/tests/Utilities/ComposerTest.php +++ b/tests/Utilities/ComposerTest.php @@ -17,6 +17,9 @@ use Meritoo\Common\Utilities\Composer; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\Composer */ class ComposerTest extends BaseTestCase { @@ -27,6 +30,16 @@ class ComposerTest extends BaseTestCase */ private $composerJsonPath; + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + parent::setUp(); + + $this->composerJsonPath = $this->getFilePathForTesting(Composer::FILE_NAME_MAIN); + } + public function testConstructor() { static::assertHasNoConstructor(Composer::class); @@ -80,14 +93,4 @@ class ComposerTest extends BaseTestCase '1.0.2', ]; } - - /** - * {@inheritdoc} - */ - protected function setUp(): void - { - parent::setUp(); - - $this->composerJsonPath = $this->getFilePathForTesting(Composer::FILE_NAME_MAIN); - } } diff --git a/tests/Utilities/CssSelectorTest.php b/tests/Utilities/CssSelectorTest.php index 0ab9535..b406891 100644 --- a/tests/Utilities/CssSelectorTest.php +++ b/tests/Utilities/CssSelectorTest.php @@ -16,6 +16,9 @@ use Meritoo\Common\Utilities\CssSelector; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\CssSelector */ class CssSelectorTest extends BaseTestCase { diff --git a/tests/Utilities/DateTest.php b/tests/Utilities/DateTest.php index 97b9f61..419b837 100644 --- a/tests/Utilities/DateTest.php +++ b/tests/Utilities/DateTest.php @@ -22,6 +22,9 @@ use Meritoo\Common\Utilities\Locale; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\Date */ class DateTest extends BaseTestCase { @@ -89,14 +92,10 @@ class DateTest extends BaseTestCase public function testGetDateTimeConcreteDates() { - /* - * Using the standard date format provided by the tested method - */ + // Using the standard date format provided by the tested method self::assertInstanceOf(DateTime::class, Date::getDateTime('2015-03-20')); - /* - * Using custom date format - */ + // Using custom date format self::assertInstanceOf(DateTime::class, Date::getDateTime('2015-03-20 11:30', false, 'Y-m-d H:i')); self::assertInstanceOf(DateTime::class, Date::getDateTime('20.03.2015', false, 'd.m.Y')); } @@ -248,8 +247,8 @@ class DateTest extends BaseTestCase } /** - * @param string|DateTime $dateStart The start date - * @param string|DateTime $dateEnd The end date + * @param DateTime|string $dateStart The start date + * @param DateTime|string $dateEnd The end date * * @dataProvider provideEmptyDatesForDateDifference */ @@ -266,9 +265,7 @@ class DateTest extends BaseTestCase public function testGetDateDifferenceOneDay() { - /* - * Difference of 1 day - */ + // Difference of 1 day $dateStart = '2017-01-01'; $dateEnd = '2017-01-02'; @@ -298,9 +295,7 @@ class DateTest extends BaseTestCase self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MINUTES)); self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); - /* - * Difference of 1 day (using the relative date format) - */ + // Difference of 1 day (using the relative date format) $effect = [ Date::DATE_DIFFERENCE_UNIT_YEARS => 0, Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, @@ -318,9 +313,7 @@ class DateTest extends BaseTestCase public function testGetDateDifferenceOneDayTwoHours() { - /* - * Difference of 1 day, 2 hours and 15 minutes - */ + // Difference of 1 day, 2 hours and 15 minutes $dateStart = '2017-01-01 12:00'; $dateEnd = '2017-01-02 14:15'; @@ -353,9 +346,7 @@ class DateTest extends BaseTestCase public function testGetDateDifferenceOneMonthFortyOneDays() { - /* - * Difference of 1 month, 41 days, 4 hours and 30 minutes - */ + // Difference of 1 month, 41 days, 4 hours and 30 minutes $dateStart = '2017-01-01 12:00'; $dateEnd = '2017-02-11 16:30'; @@ -516,9 +507,7 @@ class DateTest extends BaseTestCase public function testGetDateDifferenceNoDifference() { - /* - * No difference - */ + // No difference $dateStart = '2017-01-01 12:00'; $dateEnd = $dateStart; @@ -572,18 +561,14 @@ class DateTest extends BaseTestCase public function testGetDatesCollection() { - /* - * 1 date only - */ + // 1 date only $effect = [ 1 => new DateTime('2017-01-02'), ]; self::assertEquals($effect, Date::getDatesCollection(new DateTime('2017-01-01'), 1)); - /* - * 3 dates with default date interval (days) - */ + // 3 dates with default date interval (days) $effect = [ 1 => new DateTime('2017-01-02'), 2 => new DateTime('2017-01-03'), @@ -592,9 +577,7 @@ class DateTest extends BaseTestCase self::assertEquals($effect, Date::getDatesCollection(new DateTime('2017-01-01'), 3)); - /* - * 3 dates with custom date interval (hours) - */ + // 3 dates with custom date interval (hours) $effect = [ 1 => new DateTime('2017-01-01 10:30'), 2 => new DateTime('2017-01-01 11:30'), @@ -603,9 +586,7 @@ class DateTest extends BaseTestCase self::assertEquals($effect, Date::getDatesCollection(new DateTime('2017-01-01 09:30'), 3, 'PT%dH')); - /* - * 3 dates with custom date interval (months) - */ + // 3 dates with custom date interval (months) $effect = [ 1 => new DateTime('2017-02-01'), 2 => new DateTime('2017-03-01'), @@ -705,42 +686,32 @@ class DateTest extends BaseTestCase */ public function provideIncorrectDateTimeValue() { - /* - * Incorrect one-character values - */ + // Incorrect one-character values yield['a']; yield['m']; - /* - * Incorrect strings - */ + // Incorrect strings yield['ss']; yield['sss']; yield['mm']; yield['yy']; yield['yyyy']; - /* - * Incorrect integer values - */ + // Incorrect integer values yield[1]; yield[10]; yield[15]; yield[100]; yield[1000]; - /* - * Incorrect string / numeric values - */ + // Incorrect string / numeric values yield['1']; yield['10']; yield['15']; yield['100']; yield['1000']; - /* - * Incorrect dates - */ + // Incorrect dates yield['0-0-0']; yield['20-01-01']; yield['2015-0-0']; diff --git a/tests/Utilities/GeneratorUtilityTest.php b/tests/Utilities/GeneratorUtilityTest.php index 7642c87..1877597 100644 --- a/tests/Utilities/GeneratorUtilityTest.php +++ b/tests/Utilities/GeneratorUtilityTest.php @@ -16,6 +16,9 @@ use Meritoo\Common\Utilities\GeneratorUtility; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\GeneratorUtility */ class GeneratorUtilityTest extends BaseTestCase { @@ -26,9 +29,7 @@ class GeneratorUtilityTest extends BaseTestCase public function testGetGeneratorElements() { - /* - * Generator that provides boolean value - */ + // Generator that provides boolean value $elements = [ [false], [true], @@ -46,15 +47,11 @@ class GeneratorUtilityTest extends BaseTestCase [[]], ]; - /* - * Generator that provides an empty value - */ + // Generator that provides an empty value $generator = $this->provideEmptyValue(); self::assertEquals($elements, GeneratorUtility::getGeneratorElements($generator)); - /* - * Generator that provides instance of DateTime class - */ + // Generator that provides instance of DateTime class $generator = $this->provideDateTimeInstance(); self::assertCount(4, GeneratorUtility::getGeneratorElements($generator)); } diff --git a/tests/Utilities/LocaleTest.php b/tests/Utilities/LocaleTest.php index 6a2c9ea..9a21384 100644 --- a/tests/Utilities/LocaleTest.php +++ b/tests/Utilities/LocaleTest.php @@ -18,6 +18,9 @@ use ReflectionException; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\Locale */ class LocaleTest extends BaseTestCase { diff --git a/tests/Utilities/MimeTypesTest.php b/tests/Utilities/MimeTypesTest.php index ee0e85e..904c63f 100644 --- a/tests/Utilities/MimeTypesTest.php +++ b/tests/Utilities/MimeTypesTest.php @@ -17,6 +17,9 @@ use Meritoo\Common\Utilities\MimeTypes; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\MimeTypes */ class MimeTypesTest extends BaseTestCase { diff --git a/tests/Utilities/MiscellaneousTest.php b/tests/Utilities/MiscellaneousTest.php index 20bcb8f..15e33cc 100644 --- a/tests/Utilities/MiscellaneousTest.php +++ b/tests/Utilities/MiscellaneousTest.php @@ -21,6 +21,9 @@ use stdClass; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\Miscellaneous */ class MiscellaneousTest extends BaseTestCase { @@ -29,6 +32,28 @@ class MiscellaneousTest extends BaseTestCase private $stringDotSeparated; private $stringWithoutSpaces; + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + parent::setUp(); + + $this->stringSmall = 'Lorem ipsum dolor sit amet.'; + $this->stringCommaSeparated = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit'; + $this->stringDotSeparated = 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis.'; + $this->stringWithoutSpaces = 'LoremIpsumDolorSitAmetConsecteturAdipiscingElit'; + } + + /** + * {@inheritdoc} + */ + protected function tearDown(): void + { + parent::tearDown(); + unset($this->stringSmall, $this->stringCommaSeparated, $this->stringDotSeparated, $this->stringWithoutSpaces); + } + public function testConstructor() { static::assertHasNoConstructor(Miscellaneous::class); @@ -93,24 +118,16 @@ class MiscellaneousTest extends BaseTestCase public function testGetFileNameFromPath() { - /* - * Path with file - */ + // Path with file self::assertEquals('sit.amet.JPG', Miscellaneous::getFileNameFromPath('lorem/ipsum-dolor/sit.amet.JPG')); - /* - * Path without file - */ + // Path without file self::assertEquals('', Miscellaneous::getFileNameFromPath('lorem/ipsum-dolor/sit-amet')); - /* - * Path with a dot "." in name of directory - */ + // Path with a dot "." in name of directory self::assertEquals('sit.amet.JPG', Miscellaneous::getFileNameFromPath('lorem/ipsum.dolor/sit.amet.JPG')); - /* - * Relative path - */ + // Relative path self::assertEquals('sit.amet.JPG', Miscellaneous::getFileNameFromPath('lorem/ipsum/../dolor/sit.amet.JPG')); } @@ -119,14 +136,10 @@ class MiscellaneousTest extends BaseTestCase $originalFileName = 'Lorem.ipsum-dolor.sit.JPG'; $pattern = '|^lorem\-ipsum\-dolor\-sit\-[a-z0-9.-]+\.jpg$|'; - /* - * With object ID - */ + // With object ID $uniqueFileName1 = Miscellaneous::getUniqueFileName($originalFileName, 123); - /* - * Without object ID - */ + // Without object ID $uniqueFileName2 = Miscellaneous::getUniqueFileName($originalFileName); $isCorrect1 = (bool)preg_match($pattern, $uniqueFileName1); @@ -200,7 +213,7 @@ class MiscellaneousTest extends BaseTestCase } /** - * @param string|array $search An empty value to find + * @param array|string $search An empty value to find * @dataProvider provideEmptyValue */ public function testReplaceEmptyValue($search) @@ -224,10 +237,10 @@ class MiscellaneousTest extends BaseTestCase /** * @param string $description Description of test - * @param string|array $subject The string or an array of strings to search and replace - * @param string|array $search String or pattern or array of patterns to find. It may be: string, an array + * @param array|string $subject The string or an array of strings to search and replace + * @param array|string $search String or pattern or array of patterns to find. It may be: string, an array * of strings or an array of patterns. - * @param string|array $replacement The string or an array of strings to replace. It may be: string or an array + * @param array|string $replacement The string or an array of strings to replace. It may be: string or an array * of strings. * @param mixed $result Result of replacing * @@ -328,9 +341,7 @@ class MiscellaneousTest extends BaseTestCase public function testGetOperatingSystemNameServer() { - /* - * While running Docker OS is a Linux - */ + // While running Docker OS is a Linux self::assertEquals('Linux', Miscellaneous::getOperatingSystemNameServer()); } @@ -531,9 +542,7 @@ class MiscellaneousTest extends BaseTestCase public function testConcatenatePathsInNixOs() { - /* - * For *nix operating system - */ + // For *nix operating system $paths1 = [ 'first/directory', 'second/one', @@ -546,9 +555,7 @@ class MiscellaneousTest extends BaseTestCase public function testConcatenatePathsInWindowsOs() { - /* - * For Windows operating system - */ + // For Windows operating system $paths2 = [ 'C:\first\directory', 'second\one', @@ -597,18 +604,14 @@ class MiscellaneousTest extends BaseTestCase public function testIsBetween() { - /* - * Negative cases - */ + // Negative cases self::assertFalse(Miscellaneous::isBetween(0, 0, 0)); self::assertFalse(Miscellaneous::isBetween('0', '0', '0')); self::assertFalse(Miscellaneous::isBetween(0, 0, 1)); self::assertFalse(Miscellaneous::isBetween(-1, -1, -1)); self::assertFalse(Miscellaneous::isBetween(1.2, 0.1, 1.1)); - /* - * Positive cases - */ + // Positive cases self::assertTrue(Miscellaneous::isBetween(1, 0, 2)); self::assertTrue(Miscellaneous::isBetween('1', '0', '2')); self::assertTrue(Miscellaneous::isBetween(-1, -2, 2)); @@ -628,9 +631,7 @@ class MiscellaneousTest extends BaseTestCase public function testGetValidColorComponent() { - /* - * Negative cases - */ + // Negative cases self::assertEquals(0, Miscellaneous::getValidColorComponent(null)); self::assertEquals(0, Miscellaneous::getValidColorComponent('')); self::assertEquals(0, Miscellaneous::getValidColorComponent('0')); @@ -638,18 +639,14 @@ class MiscellaneousTest extends BaseTestCase self::assertEquals(0, Miscellaneous::getValidColorComponent(256)); self::assertEquals(0, Miscellaneous::getValidColorComponent(256, false)); - /* - * Positive cases - part 1 - */ + // Positive cases - part 1 self::assertEquals(1, Miscellaneous::getValidColorComponent(1)); self::assertEquals('0a', Miscellaneous::getValidColorComponent(10)); self::assertEquals('0f', Miscellaneous::getValidColorComponent(15)); self::assertEquals(64, Miscellaneous::getValidColorComponent(100)); self::assertEquals('ff', Miscellaneous::getValidColorComponent(255)); - /* - * Positive cases - part 2 - */ + // Positive cases - part 2 self::assertEquals(1, Miscellaneous::getValidColorComponent(1, false)); self::assertEquals(10, Miscellaneous::getValidColorComponent(10, false)); self::assertEquals(15, Miscellaneous::getValidColorComponent(15, false)); @@ -684,9 +681,7 @@ class MiscellaneousTest extends BaseTestCase public function testGetInvertedColor() { - /* - * Simple cases - */ + // Simple cases self::assertEquals('000000', Miscellaneous::getInvertedColor('fff')); self::assertEquals('ffffff', Miscellaneous::getInvertedColor('000')); self::assertEquals('000000', Miscellaneous::getInvertedColor('ffffff')); @@ -694,18 +689,14 @@ class MiscellaneousTest extends BaseTestCase self::assertEquals('#000000', Miscellaneous::getInvertedColor('#ffffff')); self::assertEquals('#ffffff', Miscellaneous::getInvertedColor('#000000')); - /* - * Advanced cases - part 1 - */ + // Advanced cases - part 1 self::assertEquals('ffffee', Miscellaneous::getInvertedColor('001')); self::assertEquals('ffeeff', Miscellaneous::getInvertedColor('010')); self::assertEquals('eeffff', Miscellaneous::getInvertedColor('100')); self::assertEquals('333333', Miscellaneous::getInvertedColor('ccc')); self::assertEquals('333333', Miscellaneous::getInvertedColor('CCC')); - /* - * Advanced cases - part 2 - */ + // Advanced cases - part 2 self::assertEquals('3e3e3e', Miscellaneous::getInvertedColor('c1c1c1')); self::assertEquals('3e3e3e', Miscellaneous::getInvertedColor('C1C1C1')); self::assertEquals('#dd5a01', Miscellaneous::getInvertedColor('#22a5fe')); @@ -713,9 +704,7 @@ class MiscellaneousTest extends BaseTestCase self::assertEquals('#464646', Miscellaneous::getInvertedColor('#b9b9b9')); self::assertEquals('#080808', Miscellaneous::getInvertedColor('#f7f7f7')); - /* - * Advanced cases - verification - */ + // Advanced cases - verification self::assertEquals('000011', Miscellaneous::getInvertedColor('ffffee')); self::assertEquals('cccccc', Miscellaneous::getInvertedColor('333333')); self::assertEquals('#22a5fe', Miscellaneous::getInvertedColor('#dd5a01')); @@ -1475,26 +1464,4 @@ class MiscellaneousTest extends BaseTestCase 'Lorem \'commodo\' dolor sit \'egestas\'', ]; } - - /** - * {@inheritdoc} - */ - protected function setUp(): void - { - parent::setUp(); - - $this->stringSmall = 'Lorem ipsum dolor sit amet.'; - $this->stringCommaSeparated = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit'; - $this->stringDotSeparated = 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis.'; - $this->stringWithoutSpaces = 'LoremIpsumDolorSitAmetConsecteturAdipiscingElit'; - } - - /** - * {@inheritdoc} - */ - protected function tearDown(): void - { - parent::tearDown(); - unset($this->stringSmall, $this->stringCommaSeparated, $this->stringDotSeparated, $this->stringWithoutSpaces); - } } diff --git a/tests/Utilities/QueryBuilderUtilityTest.php b/tests/Utilities/QueryBuilderUtilityTest.php index 3181a35..3f4aa4d 100644 --- a/tests/Utilities/QueryBuilderUtilityTest.php +++ b/tests/Utilities/QueryBuilderUtilityTest.php @@ -23,6 +23,9 @@ use Meritoo\Common\Utilities\QueryBuilderUtility; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\QueryBuilderUtility */ class QueryBuilderUtilityTest extends BaseTestCase { @@ -33,7 +36,7 @@ class QueryBuilderUtilityTest extends BaseTestCase /** * @param QueryBuilder $queryBuilder The query builder to retrieve root alias - * @param string|null $rootAlias Expected root alias of given query builder + * @param null|string $rootAlias Expected root alias of given query builder * * @dataProvider provideQueryBuilderAndRootAlias */ @@ -45,7 +48,7 @@ class QueryBuilderUtilityTest extends BaseTestCase /** * @param QueryBuilder $queryBuilder The query builder to verify * @param string $propertyName Name of property that maybe is joined - * @param string|null $propertyAlias Expected alias of given property joined in given query builder + * @param null|string $propertyAlias Expected alias of given property joined in given query builder * * @dataProvider provideQueryBuilderAndPropertyAlias */ @@ -93,9 +96,7 @@ class QueryBuilderUtilityTest extends BaseTestCase $criteriaCount = count($criteria); $nullsCount = 0; - /* - * I have to verify count/amount of NULLs and decrease $criteriaCount, because for null parameter is not added - */ + // I have to verify count/amount of NULLs and decrease $criteriaCount, because for null parameter is not added array_walk($criteria, function ($value) use (&$nullsCount) { if (null === $value) { ++$nullsCount; diff --git a/tests/Utilities/Reflection/F.php b/tests/Utilities/Reflection/F.php index 7206544..574a4d2 100644 --- a/tests/Utilities/Reflection/F.php +++ b/tests/Utilities/Reflection/F.php @@ -31,9 +31,7 @@ class F $this->username = $username; $this->gInstance = new G($firstName, $lastName); - /* - * Called to avoid "Unused private method getAccountBalance" warning only - */ + // Called to avoid "Unused private method getAccountBalance" warning only $this->getAccountBalance(); } diff --git a/tests/Utilities/Reflection/H.php b/tests/Utilities/Reflection/H.php index a5ce14d..bd626c3 100644 --- a/tests/Utilities/Reflection/H.php +++ b/tests/Utilities/Reflection/H.php @@ -17,11 +17,11 @@ namespace Meritoo\Test\Common\Utilities\Reflection; */ class H { - const DOLOR = 'sit'; + public const DOLOR = 'sit'; - const LOREM = 'ipsum'; + public const LOREM = 'ipsum'; - const MAX_USERS = 5; + public const MAX_USERS = 5; - const MIN_USERS = 2; + public const MIN_USERS = 2; } diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 4c742f6..9b136e9 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -33,6 +33,9 @@ use ReflectionProperty; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\Reflection */ class ReflectionTest extends BaseTestCase { @@ -53,18 +56,14 @@ class ReflectionTest extends BaseTestCase public function testGetClassNameNotExistingClass() { - /* - * Not existing class - */ + // Not existing class self::assertEquals('', Reflection::getClassName('xyz')); self::assertEquals('', Reflection::getClassName('xyz', true)); } public function testGetClassNameExistingClass() { - /* - * Existing class - */ + // Existing class self::assertEquals(self::class, Reflection::getClassName(self::class)); self::assertEquals('ReflectionTest', Reflection::getClassName(self::class, true)); self::assertEquals(DateTime::class, Reflection::getClassName(new DateTime())); @@ -94,17 +93,13 @@ class ReflectionTest extends BaseTestCase public function testGetClassNamespaceNotExistingClass() { - /* - * Not existing class - */ + // Not existing class self::assertEquals('', Reflection::getClassNamespace('xyz')); } public function testGetClassNamespaceExistingClass() { - /* - * Existing class - */ + // Existing class self::assertEquals('Meritoo\Test\Common\Utilities', Reflection::getClassNamespace(self::class)); self::assertEquals(DateTime::class, Reflection::getClassNamespace(new DateTime())); diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index ba9bcf2..9af9937 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -6,24 +6,49 @@ * file that was distributed with this source code. */ -namespace Meritoo\Common\Utilities; +namespace Meritoo\Test\Common\Utilities; use Generator; use Meritoo\Common\Exception\Regex\IncorrectColorHexLengthException; use Meritoo\Common\Exception\Regex\InvalidColorHexValueException; use Meritoo\Common\Test\Base\BaseTestCase; +use Meritoo\Common\Utilities\Regex; /** * Test case of the useful regular expressions methods * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\Regex */ class RegexTest extends BaseTestCase { private $simpleText; private $camelCaseText; + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + parent::setUp(); + + $this->simpleText = 'lorem ipsum dolor sit'; + $simpleUppercase = ucwords($this->simpleText); + $this->camelCaseText = str_replace(' ', '', lcfirst($simpleUppercase)); // 'loremIpsumDolorSit' + } + + /** + * {@inheritdoc} + */ + protected function tearDown(): void + { + parent::tearDown(); + unset($this->simpleText, $this->camelCaseText); + } + public function testConstructor() { static::assertHasNoConstructor(Regex::class); @@ -171,23 +196,17 @@ class RegexTest extends BaseTestCase public function testStartsWithDirectorySeparator() { - /* - * Not provided, default separator - */ + // Not provided, default separator self::assertTrue(Regex::startsWithDirectorySeparator('/my/extra/directory')); self::assertFalse(Regex::startsWithDirectorySeparator('my/extra/directory')); - /* - * Slash as separator - */ + // Slash as separator $separatorSlash = '/'; self::assertTrue(Regex::startsWithDirectorySeparator('/my/extra/directory', $separatorSlash)); self::assertFalse(Regex::startsWithDirectorySeparator('my/extra/directory', $separatorSlash)); - /* - * Backslash as separator - */ + // Backslash as separator $separatorBackslash = '\\'; self::assertTrue(Regex::startsWithDirectorySeparator('\my\extra\directory', $separatorBackslash)); @@ -196,23 +215,17 @@ class RegexTest extends BaseTestCase public function testEndsWithDirectorySeparator() { - /* - * Not provided, default separator - */ + // Not provided, default separator self::assertTrue(Regex::endsWithDirectorySeparator('my simple text/')); self::assertFalse(Regex::endsWithDirectorySeparator('my simple text')); - /* - * Slash as separator - */ + // Slash as separator $separatorSlash = '/'; self::assertTrue(Regex::endsWithDirectorySeparator('my simple text/', $separatorSlash)); self::assertFalse(Regex::endsWithDirectorySeparator('my simple text', $separatorSlash)); - /* - * Backslash as separator - */ + // Backslash as separator $separatorBackslash = '\\'; self::assertTrue(Regex::endsWithDirectorySeparator('my simple text\\', $separatorBackslash)); @@ -912,17 +925,13 @@ class RegexTest extends BaseTestCase false, ]; - /* - * Microsoft sp. z o.o. - */ + // Microsoft sp. z o.o. yield[ '5270103391', true, ]; - /* - * Onet S.A. - */ + // Onet S.A. yield[ '7340009469', true, @@ -1994,25 +2003,4 @@ class RegexTest extends BaseTestCase true, ]; } - - /** - * {@inheritdoc} - */ - protected function setUp(): void - { - parent::setUp(); - - $this->simpleText = 'lorem ipsum dolor sit'; - $simpleUppercase = ucwords($this->simpleText); - $this->camelCaseText = str_replace(' ', '', lcfirst($simpleUppercase)); // 'loremIpsumDolorSit' - } - - /** - * {@inheritdoc} - */ - protected function tearDown(): void - { - parent::tearDown(); - unset($this->simpleText, $this->camelCaseText); - } } diff --git a/tests/Utilities/Repository/Sortable.php b/tests/Utilities/Repository/Sortable.php index fc877b6..82b2cfb 100644 --- a/tests/Utilities/Repository/Sortable.php +++ b/tests/Utilities/Repository/Sortable.php @@ -34,6 +34,16 @@ class Sortable $this->position = $position; } + /** + * Returns representation of object as string + * + * @return string + */ + public function __toString() + { + return sprintf('%s (position: %d)', self::class, $this->getPosition()); + } + /** * Returns position used while sorting * @@ -53,14 +63,4 @@ class Sortable { $this->position = $position; } - - /** - * Returns representation of object as string - * - * @return string - */ - public function __toString() - { - return sprintf('%s (position: %d)', self::class, $this->getPosition()); - } } diff --git a/tests/Utilities/RepositoryTest.php b/tests/Utilities/RepositoryTest.php index 553007e..89f0c0f 100644 --- a/tests/Utilities/RepositoryTest.php +++ b/tests/Utilities/RepositoryTest.php @@ -10,7 +10,6 @@ namespace Meritoo\Test\Common\Utilities; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; -use Doctrine\ORM\Query\Expr\OrderBy; use Doctrine\ORM\QueryBuilder; use Generator; use Meritoo\Common\Test\Base\BaseTestCase; @@ -23,6 +22,9 @@ use stdClass; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\Repository */ class RepositoryTest extends BaseTestCase { @@ -53,27 +55,19 @@ class RepositoryTest extends BaseTestCase new stdClass(), ]; - /* - * Using defaults - */ + // Using defaults Repository::replenishPositions($before); static::assertEquals($before, $after); - /* - * Place items at the top - */ + // Place items at the top Repository::replenishPositions($before, false); static::assertEquals($before, $after); - /* - * Set positions even there is no extreme position (at the end) - */ + // Set positions even there is no extreme position (at the end) Repository::replenishPositions($before, true, true); static::assertEquals($before, $after); - /* - * Set positions even there is no extreme position (at the top) - */ + // Set positions even there is no extreme position (at the top) Repository::replenishPositions($before, false, true); static::assertEquals($before, $after); } @@ -238,7 +232,7 @@ class RepositoryTest extends BaseTestCase $orderDQLPart = $queryBuilder->getDQLPart('orderBy'); $rootAliases = $queryBuilder->getRootAliases(); - /* @var OrderBy $orderBy */ + /** @var OrderBy $orderBy */ $orderBy = $orderDQLPart[0]; static::assertInstanceOf(QueryBuilder::class, $queryBuilder); @@ -293,7 +287,7 @@ class RepositoryTest extends BaseTestCase if (empty($property)) { static::assertSame([], $orderDQLPart); } else { - /* @var OrderBy $orderBy */ + /** @var OrderBy $orderBy */ $orderBy = $orderDQLPart[0]; static::assertSame([$expectedOrderBy], $orderBy->getParts()); diff --git a/tests/Utilities/UriTest.php b/tests/Utilities/UriTest.php index 6f92391..6b3bf18 100644 --- a/tests/Utilities/UriTest.php +++ b/tests/Utilities/UriTest.php @@ -17,6 +17,9 @@ use Meritoo\Common\Utilities\Uri; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\Uri */ class UriTest extends BaseTestCase { diff --git a/tests/Utilities/XmlTest.php b/tests/Utilities/XmlTest.php index 073c320..3d09c50 100644 --- a/tests/Utilities/XmlTest.php +++ b/tests/Utilities/XmlTest.php @@ -17,38 +17,15 @@ use SimpleXMLElement; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Utilities\Xml */ class XmlTest extends BaseTestCase { private $simpleXml; private $advancedXml; - public function testConstructor() - { - static::assertHasNoConstructor(Xml::class); - } - - public function testMergeNodes() - { - /* - * An empty XMLs - */ - $element1 = new SimpleXMLElement(''); - $element2 = new SimpleXMLElement(''); - - $merged = Xml::mergeNodes($element1, $element2); - self::assertEquals('', (string)$merged); - - /* - * XMLs with data - */ - $element1 = new SimpleXMLElement($this->simpleXml); - $element2 = new SimpleXMLElement($this->advancedXml); - - $merged = Xml::mergeNodes($element1, $element2); - self::assertEquals('John', (string)$merged->author[0]->first_name); - } - /** * {@inheritdoc} */ @@ -90,7 +67,28 @@ class XmlTest extends BaseTestCase { parent::tearDown(); - unset($this->simpleXml); - unset($this->advancedXml); + unset($this->simpleXml, $this->advancedXml); + } + + public function testConstructor() + { + static::assertHasNoConstructor(Xml::class); + } + + public function testMergeNodes() + { + // An empty XMLs + $element1 = new SimpleXMLElement(''); + $element2 = new SimpleXMLElement(''); + + $merged = Xml::mergeNodes($element1, $element2); + self::assertEquals('', (string)$merged); + + // XMLs with data + $element1 = new SimpleXMLElement($this->simpleXml); + $element2 = new SimpleXMLElement($this->advancedXml); + + $merged = Xml::mergeNodes($element1, $element2); + self::assertEquals('John', (string)$merged->author[0]->first_name); } } diff --git a/tests/ValueObject/AddressTest.php b/tests/ValueObject/AddressTest.php index 63806e4..e70895f 100644 --- a/tests/ValueObject/AddressTest.php +++ b/tests/ValueObject/AddressTest.php @@ -17,6 +17,9 @@ use Meritoo\Common\ValueObject\Address; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\ValueObject\Address */ class AddressTest extends BaseTestCase { @@ -35,6 +38,15 @@ class AddressTest extends BaseTestCase */ private $addressWithoutStreet; + protected function setUp(): void + { + parent::setUp(); + + $this->address = new Address('New York', '00123', '4th Avenue', '10', '200'); + $this->addressWithoutFlat = new Address('San Francisco', '00456', 'Green Street', '22'); + $this->addressWithoutStreet = new Address('Saint Louis', '00111', '', '1', '300'); + } + public function testConstructor() { static::assertConstructorVisibilityAndArguments( @@ -93,13 +105,4 @@ class AddressTest extends BaseTestCase static::assertSame('Green Street 22, 00456, San Francisco', (string)$this->addressWithoutFlat); static::assertSame('00111, Saint Louis', (string)$this->addressWithoutStreet); } - - protected function setUp(): void - { - parent::setUp(); - - $this->address = new Address('New York', '00123', '4th Avenue', '10', '200'); - $this->addressWithoutFlat = new Address('San Francisco', '00456', 'Green Street', '22'); - $this->addressWithoutStreet = new Address('Saint Louis', '00111', '', '1', '300'); - } } diff --git a/tests/ValueObject/BankAccountTest.php b/tests/ValueObject/BankAccountTest.php index 4b07705..4d48eb7 100644 --- a/tests/ValueObject/BankAccountTest.php +++ b/tests/ValueObject/BankAccountTest.php @@ -17,6 +17,9 @@ use Meritoo\Common\ValueObject\BankAccount; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\ValueObject\BankAccount */ class BankAccountTest extends BaseTestCase { @@ -30,6 +33,17 @@ class BankAccountTest extends BaseTestCase */ private $bankAccount; + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + parent::setUp(); + + $this->emptyBankAccount = new BankAccount('', ''); + $this->bankAccount = new BankAccount('Bank of America', '1234567890'); + } + public function testConstructor() { static::assertConstructorVisibilityAndArguments( @@ -57,15 +71,4 @@ class BankAccountTest extends BaseTestCase static::assertSame('', (string)$this->emptyBankAccount); static::assertSame('Bank of America, 1234567890', (string)$this->bankAccount); } - - /** - * {@inheritdoc} - */ - protected function setUp(): void - { - parent::setUp(); - - $this->emptyBankAccount = new BankAccount('', ''); - $this->bankAccount = new BankAccount('Bank of America', '1234567890'); - } } diff --git a/tests/ValueObject/CompanyTest.php b/tests/ValueObject/CompanyTest.php index 6fcfd99..9edb320 100644 --- a/tests/ValueObject/CompanyTest.php +++ b/tests/ValueObject/CompanyTest.php @@ -19,6 +19,9 @@ use Meritoo\Common\ValueObject\Company; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\ValueObject\Company */ class CompanyTest extends BaseTestCase { @@ -32,6 +35,25 @@ class CompanyTest extends BaseTestCase */ private $companyWithoutBankAccount; + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + parent::setUp(); + + $this->company = new Company( + 'Test 1', + new Address('New York', '00123', '4th Avenue', '10', '200'), + new BankAccount('Bank 1', '12345') + ); + + $this->companyWithoutBankAccount = new Company( + 'Test 2', + new Address('San Francisco', '00456', 'Green Street', '22') + ); + } + public function testConstructor() { static::assertConstructorVisibilityAndArguments( @@ -76,23 +98,4 @@ class CompanyTest extends BaseTestCase static::assertSame('Test 1, 4th Avenue 10/200, 00123, New York, Bank 1, 12345', (string)$this->company); static::assertSame('Test 2, Green Street 22, 00456, San Francisco', (string)$this->companyWithoutBankAccount); } - - /** - * {@inheritdoc} - */ - protected function setUp(): void - { - parent::setUp(); - - $this->company = new Company( - 'Test 1', - new Address('New York', '00123', '4th Avenue', '10', '200'), - new BankAccount('Bank 1', '12345') - ); - - $this->companyWithoutBankAccount = new Company( - 'Test 2', - new Address('San Francisco', '00456', 'Green Street', '22') - ); - } } diff --git a/tests/ValueObject/HumanTest.php b/tests/ValueObject/HumanTest.php index 1a58e35..c5ddbee 100644 --- a/tests/ValueObject/HumanTest.php +++ b/tests/ValueObject/HumanTest.php @@ -17,6 +17,9 @@ use Meritoo\Common\ValueObject\Human; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\ValueObject\Human */ class HumanTest extends BaseTestCase { diff --git a/tests/ValueObject/SizeTest.php b/tests/ValueObject/SizeTest.php index ed52f00..0a75b30 100644 --- a/tests/ValueObject/SizeTest.php +++ b/tests/ValueObject/SizeTest.php @@ -18,6 +18,9 @@ use Meritoo\Common\ValueObject\Size; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\ValueObject\Size */ class SizeTest extends BaseTestCase { @@ -32,12 +35,12 @@ class SizeTest extends BaseTestCase /** * @param string $description Description of test - * @param Size|null $size Size to convert + * @param null|Size $size Size to convert * @param string $expected Expected result * * @dataProvider provideSizeForConvertingToString */ - public function test__toString($description, $size, $expected) + public function testToStringConverting($description, $size, $expected) { static::assertEquals($expected, (string)$size, $description); } @@ -57,7 +60,7 @@ class SizeTest extends BaseTestCase * @param string $description Description of test * @param Size $size Size to get width * @param bool $withUnit If is set to true, width is returned with unit ("px"). Otherwise - without. - * @param string|int $expected Expected width + * @param int|string $expected Expected width * * @dataProvider provideSizeToGetWidth */ @@ -70,7 +73,7 @@ class SizeTest extends BaseTestCase * @param string $description Description of test * @param Size $size Size to set width * @param int|string $width The width - * @param string|int $expected Expected width + * @param int|string $expected Expected width * * @dataProvider provideSizeToSetWidth */ @@ -86,7 +89,7 @@ class SizeTest extends BaseTestCase * @param string $description Description of test * @param Size $size Size to get width * @param bool $withUnit If is set to true, width is returned with unit ("px"). Otherwise - without. - * @param string|int $expected Expected width + * @param int|string $expected Expected width * * @dataProvider provideSizeToGetHeight */ @@ -99,7 +102,7 @@ class SizeTest extends BaseTestCase * @param string $description Description of test * @param Size $size Size to set height * @param int|string $height The height - * @param string|int $expected Expected height + * @param int|string $expected Expected height * * @dataProvider provideSizeToSetHeight */ @@ -167,7 +170,7 @@ class SizeTest extends BaseTestCase * @param string $size The size represented as string (width and height separated by "x") * @param string $unit Unit used when width or height should be returned with unit * @param string $separator Separator used to split width and height - * @param Size|null $expected Expected result + * @param null|Size $expected Expected result * * @dataProvider provideSizeForFromString */ diff --git a/tests/ValueObject/VersionTest.php b/tests/ValueObject/VersionTest.php index fb0e783..4bcdbfb 100644 --- a/tests/ValueObject/VersionTest.php +++ b/tests/ValueObject/VersionTest.php @@ -19,6 +19,9 @@ use Meritoo\Common\ValueObject\Version; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\ValueObject\Version */ class VersionTest extends BaseTestCase { From e05bc2302dc06b41c3b497fc44f7d39ba563b74a Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 6 Apr 2019 08:14:48 +0200 Subject: [PATCH 035/137] PHPUnit > increase code coverage --- src/Utilities/Repository.php | 7 --- tests/Utilities/RepositoryTest.php | 97 ++++++++++++++++++++++++++++++ tests/ValueObject/TemplateTest.php | 31 ++++++++++ 3 files changed, 128 insertions(+), 7 deletions(-) diff --git a/src/Utilities/Repository.php b/src/Utilities/Repository.php index e0b8e2e..6f95902 100644 --- a/src/Utilities/Repository.php +++ b/src/Utilities/Repository.php @@ -204,13 +204,6 @@ class Repository */ private static function isSorted($item) { - // Not sortable? - if (!self::isSortable($item)) { - return false; - } - - // It's an object or it's an array and position has been set? - return (is_object($item) && null !== $item->getPosition()) || diff --git a/tests/Utilities/RepositoryTest.php b/tests/Utilities/RepositoryTest.php index 89f0c0f..dfb85c4 100644 --- a/tests/Utilities/RepositoryTest.php +++ b/tests/Utilities/RepositoryTest.php @@ -72,6 +72,19 @@ class RepositoryTest extends BaseTestCase static::assertEquals($before, $after); } + /** + * @param string $description Description of test + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param array $expected Expected items with positions replenished + * + * @dataProvider provideSortedItems + */ + public function testReplenishPositionsUsingSortedItems(string $description, array $items, array $expected) + { + Repository::replenishPositions($items); + static::assertSame($expected, $items, $description); + } + /** * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays * @dataProvider provideArraysWithoutExtremePosition @@ -833,4 +846,88 @@ class RepositoryTest extends BaseTestCase 'qb.first_name DESC', ]; } + + public function provideSortedItems() + { + $sortable1 = new Sortable(); + $sortable1->setPosition(1); + + $sortable2 = new Sortable(); + $sortable2->setPosition(2); + + $sortable3 = new Sortable(); + $sortable3->setPosition(309); + + yield[ + 'An array with 1 item only', + [ + [ + 'test 1', + 'position' => 1, + ], + ], + [ + [ + 'test 1', + 'position' => 1, + ], + ], + ]; + + yield[ + 'An array with more than 1 item', + [ + [ + 'test 1', + 'position' => 1, + ], + [ + 'test 2', + 'position' => 2, + ], + [ + 'test 3', + 'position' => 309, + ], + ], + [ + [ + 'test 1', + 'position' => 1, + ], + [ + 'test 2', + 'position' => 2, + ], + [ + 'test 3', + 'position' => 309, + ], + ], + ]; + + yield[ + '1 object only', + [ + $sortable1, + ], + [ + $sortable1, + ], + ]; + + yield[ + 'More than 1 object', + [ + $sortable1, + $sortable2, + $sortable3, + ], + [ + $sortable1, + $sortable2, + $sortable3, + ], + ]; + } } diff --git a/tests/ValueObject/TemplateTest.php b/tests/ValueObject/TemplateTest.php index 6de3828..953565d 100644 --- a/tests/ValueObject/TemplateTest.php +++ b/tests/ValueObject/TemplateTest.php @@ -13,6 +13,7 @@ use Meritoo\Common\Exception\ValueObject\Template\InvalidContentException; use Meritoo\Common\Exception\ValueObject\Template\NotEnoughValuesException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; +use Meritoo\Common\Utilities\Reflection; use Meritoo\Common\ValueObject\Template; /** @@ -50,6 +51,18 @@ class TemplateTest extends BaseTestCase new Template($content); } + /** + * @param string $description Description of test + * @param string $content Raw string with placeholders (content of the template) + * + * @dataProvider provideValidContent + */ + public function testIsValidUsingValidContent(string $description, string $content): void + { + $template = new Template($content); + static::assertSame($content, Reflection::getPropertyValue($template, 'content', true), $description); + } + /** * @param Template $template Template to fill * @param array $values Pairs of key-value where: key - name of placeholder, value - value of the @@ -212,4 +225,22 @@ class TemplateTest extends BaseTestCase 'My name is Jane Brown and I live in NY, USA', ]; } + + public function provideValidContent(): ?Generator + { + yield[ + 'Template with 1 placeholder', + '%test%', + ]; + + yield[ + 'Template with 2 placeholders', + 'My name is %name% and I am %profession%', + ]; + + yield[ + 'Template with 2 placeholders that contains space', + 'My name is %first name% %last name% and I live in %current location%', + ]; + } } From 39b0172a8568fb0d695e22623470fe90b495b2f5 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 7 Apr 2019 16:19:12 +0200 Subject: [PATCH 036/137] Travis CI > run many tasks using Phing > update configuration --- .travis-php-config.ini | 3 ++- .travis.yml | 3 +++ CHANGELOG.md | 4 ++++ VERSION | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.travis-php-config.ini b/.travis-php-config.ini index 64adbeb..c0f1249 100644 --- a/.travis-php-config.ini +++ b/.travis-php-config.ini @@ -1 +1,2 @@ -date.timezone = 'Europe/London' +date.timezone = Europe/London +memory_limit = 2G diff --git a/.travis.yml b/.travis.yml index d9ce276..19f4e72 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,3 +18,6 @@ before_script: script: - phing + +after_success: + - travis_retry php vendor/bin/php-coveralls -v diff --git a/CHANGELOG.md b/CHANGELOG.md index f010d85..a79b066 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Common and useful classes, methods, exceptions etc. +# 1.0.3 + +1. Travis CI > run many tasks using Phing > update configuration + # 1.0.2 1. Phing > remove old and unused tools diff --git a/VERSION b/VERSION index 6d7de6e..21e8796 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.2 +1.0.3 From e66cbd54e2f385b25fe579e6dbc0ca0923032b94 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 10 Apr 2019 08:57:33 +0200 Subject: [PATCH 037/137] Template with placeholders > verification of placeholders without values > make stronger and point out which are missing --- CHANGELOG.md | 2 + .../MissingPlaceholdersInValuesException.php | 36 ++++++++ .../Template/NotEnoughValuesException.php | 39 --------- src/ValueObject/Template.php | 14 +-- tests/Collection/CollectionTest.php | 13 +++ ...ssingPlaceholdersInValuesExceptionTest.php | 85 +++++++++++++++++++ .../Template/NotEnoughValuesExceptionTest.php | 85 ------------------- tests/ValueObject/TemplateTest.php | 68 ++++++++++----- 8 files changed, 190 insertions(+), 152 deletions(-) create mode 100644 src/Exception/ValueObject/Template/MissingPlaceholdersInValuesException.php delete mode 100644 src/Exception/ValueObject/Template/NotEnoughValuesException.php create mode 100644 tests/Exception/ValueObject/Template/MissingPlaceholdersInValuesExceptionTest.php delete mode 100644 tests/Exception/ValueObject/Template/NotEnoughValuesExceptionTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index a79b066..de7526b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ Common and useful classes, methods, exceptions etc. # 1.0.3 1. Travis CI > run many tasks using Phing > update configuration +2. Template with placeholders > verification of placeholders without values > make stronger and point out which are +missing # 1.0.2 diff --git a/src/Exception/ValueObject/Template/MissingPlaceholdersInValuesException.php b/src/Exception/ValueObject/Template/MissingPlaceholdersInValuesException.php new file mode 100644 index 0000000..3974583 --- /dev/null +++ b/src/Exception/ValueObject/Template/MissingPlaceholdersInValuesException.php @@ -0,0 +1,36 @@ + + * @copyright Meritoo + */ +class MissingPlaceholdersInValuesException extends Exception +{ + /** + * Creates an exception + * + * @param string $content Content of template + * @param array $missingPlaceholders Missing placeholders in provided values, iow. placeholders without values + * @return MissingPlaceholdersInValuesException + */ + public static function create(string $content, array $missingPlaceholders): MissingPlaceholdersInValuesException + { + $template = 'Cannot fill template \'%s\', because of missing values for placeholder(s): %s. Did you provide all' + . ' required values?'; + $message = sprintf($template, $content, implode(', ', $missingPlaceholders)); + + return new static($message); + } +} diff --git a/src/Exception/ValueObject/Template/NotEnoughValuesException.php b/src/Exception/ValueObject/Template/NotEnoughValuesException.php deleted file mode 100644 index 3ff696b..0000000 --- a/src/Exception/ValueObject/Template/NotEnoughValuesException.php +++ /dev/null @@ -1,39 +0,0 @@ - - * @copyright Meritoo - */ -class NotEnoughValuesException extends Exception -{ - /** - * Creates an exception - * - * @param string $content Invalid content of template - * @param int $valuesCount Count of values - * @param int $placeholdersCount Count of placeholders - * @return NotEnoughValuesException - */ - public static function create(string $content, int $valuesCount, int $placeholdersCount): NotEnoughValuesException - { - $template = 'Not enough values (%d) to fill all placeholders (%d) in template \'%s\'. Did you provide all' - . ' required values?'; - $message = sprintf($template, $valuesCount, $placeholdersCount, $content); - - return new static($message); - } -} diff --git a/src/ValueObject/Template.php b/src/ValueObject/Template.php index f3aa60f..15bcd57 100644 --- a/src/ValueObject/Template.php +++ b/src/ValueObject/Template.php @@ -11,7 +11,7 @@ declare(strict_types=1); namespace Meritoo\Common\ValueObject; use Meritoo\Common\Exception\ValueObject\Template\InvalidContentException; -use Meritoo\Common\Exception\ValueObject\Template\NotEnoughValuesException; +use Meritoo\Common\Exception\ValueObject\Template\MissingPlaceholdersInValuesException; /** * Template with placeholders that may be filled by real data @@ -54,18 +54,18 @@ class Template * Returns content of the template filled with given values (by replacing placeholders with their proper values) * * @param array $values Pairs of key-value where: key - name of placeholder, value - value of the placeholder - * @throws NotEnoughValuesException + * @throws MissingPlaceholdersInValuesException * @return string */ public function fill(array $values): string { $placeholders = static::getPlaceholders($this->content); - $valuesCount = count($values); - $placeholdersCount = count($placeholders[0]); + $providedPlaceholders = array_keys($values); + $missingPlaceholders = array_diff($placeholders[1], $providedPlaceholders); - // Oops, not enough values (iow. more placeholders than values) - if ($placeholdersCount > $valuesCount) { - throw NotEnoughValuesException::create($this->content, $valuesCount, $placeholdersCount); + // Oops, there are placeholders without values (iow. provided values are different than placeholders) + if (!empty($missingPlaceholders)) { + throw MissingPlaceholdersInValuesException::create($this->content, $missingPlaceholders); } $result = $this->content; diff --git a/tests/Collection/CollectionTest.php b/tests/Collection/CollectionTest.php index 4a28dce..222b83c 100644 --- a/tests/Collection/CollectionTest.php +++ b/tests/Collection/CollectionTest.php @@ -455,6 +455,19 @@ class CollectionTest extends BaseTestCase 3 => 'I am 4th', ]), ]; + + yield[ + 'This is test 6', + 'test2', + 4, + 'test2', + new Collection([ + 'test1' => 'I am 1st', + 'test2' => 'I am 2nd', + 2 => 'I am 3rd', + 3 => 'I am 4th', + ]), + ]; } public function provideElementGetByIndex() diff --git a/tests/Exception/ValueObject/Template/MissingPlaceholdersInValuesExceptionTest.php b/tests/Exception/ValueObject/Template/MissingPlaceholdersInValuesExceptionTest.php new file mode 100644 index 0000000..dfcd549 --- /dev/null +++ b/tests/Exception/ValueObject/Template/MissingPlaceholdersInValuesExceptionTest.php @@ -0,0 +1,85 @@ + + * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\ValueObject\Template\MissingPlaceholdersInValuesException + */ +class MissingPlaceholdersInValuesExceptionTest extends BaseTestCase +{ + public function testConstructorVisibilityAndArguments(): void + { + static::assertConstructorVisibilityAndArguments( + MissingPlaceholdersInValuesException::class, + OopVisibilityType::IS_PUBLIC, + 3 + ); + } + + /** + * @param string $description Description of test + * @param string $content Content of template + * @param array $missingPlaceholders Missing placeholders in provided values, iow. placeholders without values + * @param string $expectedMessage Expected exception's message + * + * @dataProvider provideContentAndMissingPlaceholders + */ + public function testCreate( + string $description, + string $content, + array $missingPlaceholders, + string $expectedMessage + ): void { + $exception = MissingPlaceholdersInValuesException::create($content, $missingPlaceholders); + static::assertSame($expectedMessage, $exception->getMessage(), $description); + } + + public function provideContentAndMissingPlaceholders(): ?\Generator + { + $template = 'Cannot fill template \'%s\', because of missing values for placeholder(s): %s. Did you provide all' + . ' required values?'; + + yield[ + 'Missing 2nd placeholder', + '%test1% - %test2%', + [ + 'test2', + ], + sprintf( + $template, + '%test1% - %test2%', + 'test2' + ), + ]; + + yield[ + 'Missing 2nd and 3rd placeholder', + '%test1% / %test2% / %test3%', + [ + 'test2', + 'test3', + ], + sprintf( + $template, + '%test1% / %test2% / %test3%', + 'test2, test3' + ), + ]; + } +} diff --git a/tests/Exception/ValueObject/Template/NotEnoughValuesExceptionTest.php b/tests/Exception/ValueObject/Template/NotEnoughValuesExceptionTest.php deleted file mode 100644 index 533fb55..0000000 --- a/tests/Exception/ValueObject/Template/NotEnoughValuesExceptionTest.php +++ /dev/null @@ -1,85 +0,0 @@ - - * @copyright Meritoo - * - * @internal - * @covers \Meritoo\Common\Exception\ValueObject\Template\NotEnoughValuesException - */ -class NotEnoughValuesExceptionTest extends BaseTestCase -{ - public function testConstructorVisibilityAndArguments(): void - { - static::assertConstructorVisibilityAndArguments( - NotEnoughValuesException::class, - OopVisibilityType::IS_PUBLIC, - 3 - ); - } - - /** - * @param string $description Description of test - * @param string $content Invalid content of template - * @param int $valuesCount Count of values - * @param int $placeholdersCount Count of placeholders - * @param string $expectedMessage Expected exception's message - * - * @dataProvider provideContentAndValuesPlaceholdersCount - */ - public function testCreate( - string $description, - string $content, - int $valuesCount, - int $placeholdersCount, - string $expectedMessage - ): void { - $exception = NotEnoughValuesException::create($content, $valuesCount, $placeholdersCount); - static::assertSame($expectedMessage, $exception->getMessage(), $description); - } - - public function provideContentAndValuesPlaceholdersCount(): ?Generator - { - $template = 'Not enough values (%d) to fill all placeholders (%d) in template \'%s\'. Did you provide all' - . ' required values?'; - - yield[ - 'An empty string', - '', - 3, - 1, - sprintf($template, 3, 1, ''), - ]; - - yield[ - 'Simple string', - 'Lorem ipsum', - 1, - 4, - sprintf($template, 1, 4, 'Lorem ipsum'), - ]; - - yield[ - 'One sentence', - 'Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh.', - 5, - 0, - sprintf($template, 5, 0, 'Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh.'), - ]; - } -} diff --git a/tests/ValueObject/TemplateTest.php b/tests/ValueObject/TemplateTest.php index 953565d..0c97067 100644 --- a/tests/ValueObject/TemplateTest.php +++ b/tests/ValueObject/TemplateTest.php @@ -10,7 +10,7 @@ namespace Meritoo\Test\Common\ValueObject; use Generator; use Meritoo\Common\Exception\ValueObject\Template\InvalidContentException; -use Meritoo\Common\Exception\ValueObject\Template\NotEnoughValuesException; +use Meritoo\Common\Exception\ValueObject\Template\MissingPlaceholdersInValuesException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; use Meritoo\Common\Utilities\Reflection; @@ -69,11 +69,11 @@ class TemplateTest extends BaseTestCase * placeholder * @param string $exceptionMessage Expected message of exception * - * @dataProvider provideTemplateToFillUsingNotEnoughValues + * @dataProvider provideTemplateToFillUsingIncorrectValues */ - public function testFillUsingNotEnoughValues(Template $template, array $values, string $exceptionMessage): void + public function testFillUsingIncorrectValues(Template $template, array $values, string $exceptionMessage): void { - $this->expectException(NotEnoughValuesException::class); + $this->expectException(MissingPlaceholdersInValuesException::class); $this->expectExceptionMessage($exceptionMessage); $template->fill($values); @@ -118,19 +118,30 @@ class TemplateTest extends BaseTestCase ]; } - public function provideTemplateToFillUsingNotEnoughValues(): ?Generator + public function provideTemplateToFillUsingIncorrectValues(): ?Generator { - $template = 'Not enough values (%d) to fill all placeholders (%d) in template \'%s\'. Did you provide all' + $template = 'Cannot fill template \'%s\', because of missing values for placeholder(s): %s. Did you provide all' . ' required values?'; + yield[ + new Template('%test%'), + [ + 'something' => 123, + ], + sprintf( + $template, + '%test%', + 'test' + ), + ]; + yield[ new Template('%test%'), [], sprintf( $template, - 0, - 1, - '%test%' + '%test%', + 'test' ), ]; @@ -141,24 +152,39 @@ class TemplateTest extends BaseTestCase ], sprintf( $template, - 1, - 2, - '%test1% - %test2%' + '%test1% - %test2%', + 'test2' + ), + ]; + + yield[ + new Template('%test1% - %test2%'), + [ + 'test1' => 123, + 'test3' => 456, + ], + sprintf( + $template, + '%test1% - %test2%', + 'test2' + ), + ]; + + yield[ + new Template('%test1% / %test2% / %test3%'), + [ + 'test1' => 123, + ], + sprintf( + $template, + '%test1% / %test2% / %test3%', + 'test2, test3' ), ]; } public function provideTemplateToFill(): ?Generator { - yield[ - 'Template with 1 placeholder, but incorrect values', - new Template('%test%'), - [ - 'something' => 123, - ], - '%test%', - ]; - yield[ 'Template with 1 placeholder', new Template('%test%'), From 2bbd0a4ef342a088cc477eb2d57752712689f175 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 10 Apr 2019 09:09:44 +0200 Subject: [PATCH 038/137] PHPUnit > increase code coverage --- tests/Type/OopVisibilityTypeTest.php | 86 ++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 tests/Type/OopVisibilityTypeTest.php diff --git a/tests/Type/OopVisibilityTypeTest.php b/tests/Type/OopVisibilityTypeTest.php new file mode 100644 index 0000000..f501dcd --- /dev/null +++ b/tests/Type/OopVisibilityTypeTest.php @@ -0,0 +1,86 @@ + + * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Type\OopVisibilityType + */ +class OopVisibilityTypeTest extends BaseTypeTestCase +{ + /** + * {@inheritdoc} + */ + protected function getAllExpectedTypes(): array + { + return [ + 'IS_PRIVATE' => 3, + 'IS_PROTECTED' => 2, + 'IS_PUBLIC' => 1, + ]; + } + + /** + *{@inheritdoc} + */ + protected function getTestedTypeInstance(): BaseType + { + return new OopVisibilityType(); + } + + /** + * {@inheritdoc} + */ + public function provideTypeToVerify(): ?\Generator + { + yield[ + '', + false, + ]; + + yield[ + null, + false, + ]; + + yield[ + -1, + false, + ]; + + yield[ + true, + false, + ]; + + yield[ + 1, + true, + ]; + + yield[ + 2, + true, + ]; + + yield[ + 3, + true, + ]; + } +} From 6f90f5a249a7d1c3023b8ee2ea4c884cc81fd624 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 13 Apr 2019 17:27:06 +0200 Subject: [PATCH 039/137] Reflection > fix deprecations --- src/Utilities/Reflection.php | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index 23c9d65..d783cb7 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -8,8 +8,8 @@ namespace Meritoo\Common\Utilities; -use Doctrine\Common\Util\ClassUtils; -use Doctrine\Common\Util\Inflector; +use Doctrine\Common\Inflector\Inflector; +use Doctrine\Common\Persistence\Proxy; use Meritoo\Common\Collection\Collection; use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException; use Meritoo\Common\Exception\Reflection\MissingChildClassesException; @@ -368,7 +368,7 @@ class Reflection return $name; } - return ClassUtils::getRealClass($name); + return static::getRealClass($name); } /** @@ -514,14 +514,14 @@ class Reflection foreach ($allClasses as $oneClass) { if (self::isChildOfClass($oneClass, $className)) { /* - * Attention. I have to use ClassUtils::getRealClass() method to avoid problem with the proxy / cache + * Attention. I have to use static::getRealClass() method to avoid problem with the proxy / cache * classes. Example: * - My\ExtraBundle\Entity\MyEntity * - Proxies\__CG__\My\ExtraBundle\Entity\MyEntity * * It's actually the same class, so I have to skip it. */ - $realClass = ClassUtils::getRealClass($oneClass); + $realClass = static::getRealClass($oneClass); if (in_array($realClass, $childClasses, true)) { continue; @@ -704,4 +704,19 @@ class Reflection static::setPropertyValue($object, $property, $value); } } + + /** + * Returns the real class name of a class name that could be a proxy + * + * @param string $class Class to verify + * @return string + */ + private static function getRealClass($class): string + { + if (false === $pos = strrpos($class, '\\' . Proxy::MARKER . '\\')) { + return $class; + } + + return substr($class, $pos + Proxy::MARKER_LENGTH + 2); + } } From eb8fa110ad700274598691143ca0899df549744c Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 13 Apr 2019 18:28:53 +0200 Subject: [PATCH 040/137] Reflection > getPropertyValue() method > look for the property in parent classes --- CHANGELOG.md | 1 + src/Utilities/Reflection.php | 100 ++++++++++++++++++----------- tests/Utilities/ReflectionTest.php | 6 ++ 3 files changed, 68 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de7526b..7cf80c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Common and useful classes, methods, exceptions etc. 1. Travis CI > run many tasks using Phing > update configuration 2. Template with placeholders > verification of placeholders without values > make stronger and point out which are missing +3. Reflection > getPropertyValue() method > look for the property in parent classes # 1.0.2 diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index d783cb7..3336cf2 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -217,54 +217,76 @@ class Reflection } catch (\ReflectionException $exception) { /* * 2nd try: - * Look for the get / has / is methods + * Look for the property in parent classes */ - $class = new \ReflectionObject($object); - $valueFound = false; - - if ($force || $class->hasProperty($property)) { - $property = Inflector::classify($property); - - $getterPrefixes = [ - 'get', - 'has', - 'is', - ]; - - foreach ($getterPrefixes as $prefix) { - $getterName = sprintf('%s%s', $prefix, $property); - - if ($class->hasMethod($getterName)) { - $method = new \ReflectionMethod($object, $getterName); - - /* - * Getter is not accessible publicly? - * I have to skip it, to avoid an error like this: - * - * Call to protected method My\ExtraClass::getExtraProperty() from context 'My\ExtraClass' - */ - if ($method->isProtected() || $method->isPrivate()) { - continue; - } - - $value = $object->{$getterName}(); - $valueFound = true; + if (null === $reflectionProperty) { + $propertyFound = false; + $reflectionProperties = self::getProperties($object, null, true); + foreach ($reflectionProperties as $reflectionProperty) { + if ($reflectionProperty->getName() === $property) { + $propertyFound = true; break; } } - } - if (!$valueFound && null !== $reflectionProperty) { + if ($propertyFound && null !== $reflectionProperty) { + $reflectionProperty->setAccessible(true); + $value = $reflectionProperty->getValue($object); + $reflectionProperty->setAccessible(false); + } + } else { /* - * Oops, value of the property is still unknown - * * 3rd try: - * Let's modify accessibility of the property and try again to get value + * Look for the get / has / is methods */ - $reflectionProperty->setAccessible(true); - $value = $reflectionProperty->getValue($object); - $reflectionProperty->setAccessible(false); + $class = new \ReflectionObject($object); + $valueFound = false; + + if ($force || $class->hasProperty($property)) { + $property = Inflector::classify($property); + + $getterPrefixes = [ + 'get', + 'has', + 'is', + ]; + + foreach ($getterPrefixes as $prefix) { + $getterName = sprintf('%s%s', $prefix, $property); + + if ($class->hasMethod($getterName)) { + $method = new \ReflectionMethod($object, $getterName); + + /* + * Getter is not accessible publicly? + * I have to skip it, to avoid an error like this: + * + * Call to protected method My\ExtraClass::getExtraProperty() from context 'My\ExtraClass' + */ + if ($method->isProtected() || $method->isPrivate()) { + continue; + } + + $value = $object->{$getterName}(); + $valueFound = true; + + break; + } + } + } + + if (!$valueFound) { + /* + * Oops, value of the property is still unknown + * + * 4th try: + * Let's modify accessibility of the property and try again to get value + */ + $reflectionProperty->setAccessible(true); + $value = $reflectionProperty->getValue($object); + $reflectionProperty->setAccessible(false); + } } } } diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 9b136e9..2d1770c 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -309,6 +309,12 @@ class ReflectionTest extends BaseTestCase self::assertEquals($username, Reflection::getPropertyValue($f, 'username')); } + public function testGetPropertyValueFromParentClass(): void + { + $c = new C(); + self::assertEquals(1, Reflection::getPropertyValue($c, 'count', true)); + } + public function testGetPropertyValuesFromEmptySource() { self::assertEquals([], Reflection::getPropertyValues([], 'something')); From a56b325307c4007790c26bf5b2dcbcc405229861 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 13 Apr 2019 18:32:44 +0200 Subject: [PATCH 041/137] Minor refactoring --- src/Utilities/Reflection.php | 4 ++-- tests/Utilities/Reflection/F.php | 4 ++-- tests/Utilities/ReflectionTest.php | 18 +++++++++--------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index 3336cf2..66d5e28 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -322,8 +322,8 @@ class Reflection $values = []; $objects = Arrays::makeArray($objects); - foreach ($objects as $entity) { - $value = self::getPropertyValue($entity, $property, $force); + foreach ($objects as $object) { + $value = self::getPropertyValue($object, $property, $force); if (null !== $value) { $values[] = $value; diff --git a/tests/Utilities/Reflection/F.php b/tests/Utilities/Reflection/F.php index 574a4d2..de53f7b 100644 --- a/tests/Utilities/Reflection/F.php +++ b/tests/Utilities/Reflection/F.php @@ -21,7 +21,7 @@ class F private $accountBalance; private $city; private $country; - private $gInstance; + private $g; public function __construct($accountBalance, $city, $country, $username, $firstName = 'John', $lastName = 'Scott') { @@ -29,7 +29,7 @@ class F $this->city = $city; $this->country = $country; $this->username = $username; - $this->gInstance = new G($firstName, $lastName); + $this->g = new G($firstName, $lastName); // Called to avoid "Unused private method getAccountBalance" warning only $this->getAccountBalance(); diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 2d1770c..86810d2 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -35,7 +35,7 @@ use ReflectionProperty; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Utilities\Reflection + * @covers \Meritoo\Common\Utilities\Reflection */ class ReflectionTest extends BaseTestCase { @@ -274,7 +274,7 @@ class ReflectionTest extends BaseTestCase public function testGetPropertyValueFromChain() { $f = new F(1000, 'New York', 'USA', 'john.scott'); - self::assertEquals('John', Reflection::getPropertyValue($f, 'gInstance.firstName')); + self::assertEquals('John', Reflection::getPropertyValue($f, 'g.firstName')); } public function testGetPropertyValueWithPublicGetter() @@ -381,8 +381,8 @@ class ReflectionTest extends BaseTestCase { $f = new F(1000, 'New York', 'USA', 'john.scott'); - self::assertEquals(['John'], Reflection::getPropertyValues($f, 'gInstance.firstName')); - self::assertEquals(['John'], Reflection::getPropertyValues($f, 'gInstance.firstName', true)); + self::assertEquals(['John'], Reflection::getPropertyValues($f, 'g.firstName')); + self::assertEquals(['John'], Reflection::getPropertyValues($f, 'g.firstName', true)); } public function testGetPropertyValuesFromChainAndMultipleObjects() @@ -399,13 +399,13 @@ class ReflectionTest extends BaseTestCase new F(3000, 'Tokyo', 'Japan', 'john.scott', 'Peter', 'Brown'), ]; - self::assertEquals($expected, Reflection::getPropertyValues($objects, 'gInstance.firstName')); - self::assertEquals($expected, Reflection::getPropertyValues($objects, 'gInstance.firstName', true)); + self::assertEquals($expected, Reflection::getPropertyValues($objects, 'g.firstName')); + self::assertEquals($expected, Reflection::getPropertyValues($objects, 'g.firstName', true)); $collection = new Collection($objects); - self::assertEquals($expected, Reflection::getPropertyValues($collection, 'gInstance.firstName')); - self::assertEquals($expected, Reflection::getPropertyValues($collection, 'gInstance.firstName', true)); + self::assertEquals($expected, Reflection::getPropertyValues($collection, 'g.firstName')); + self::assertEquals($expected, Reflection::getPropertyValues($collection, 'g.firstName', true)); } public function testGetMaxNumberConstantUsingClassWithoutConstants() @@ -730,7 +730,7 @@ class ReflectionTest extends BaseTestCase 'UnKnown' ), [ - 'gInstance' => new G(), + 'g' => new G(), ], ]; From fa370be08a6380647c4b367c472a694f8524786b Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 13 Apr 2019 19:03:23 +0200 Subject: [PATCH 042/137] Tests > Reflection > getPropertyValues() method > make stronger verification of the dot-separated properties (get values of the chain) --- tests/Utilities/Reflection/J.php | 29 +++++++++++++++++++++++++++++ tests/Utilities/ReflectionTest.php | 5 +++++ 2 files changed, 34 insertions(+) create mode 100644 tests/Utilities/Reflection/J.php diff --git a/tests/Utilities/Reflection/J.php b/tests/Utilities/Reflection/J.php new file mode 100644 index 0000000..b646551 --- /dev/null +++ b/tests/Utilities/Reflection/J.php @@ -0,0 +1,29 @@ + + * @copyright Meritoo + */ +class J +{ + private $f; + + /** + * Class constructor + */ + public function __construct() + { + $this->f = new F(1000, 'New York', 'USA', 'john.scott'); + } +} diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 86810d2..1862ee3 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -26,6 +26,7 @@ use Meritoo\Test\Common\Utilities\Reflection\F; use Meritoo\Test\Common\Utilities\Reflection\G; use Meritoo\Test\Common\Utilities\Reflection\H; use Meritoo\Test\Common\Utilities\Reflection\I; +use Meritoo\Test\Common\Utilities\Reflection\J; use ReflectionProperty; /** @@ -380,9 +381,13 @@ class ReflectionTest extends BaseTestCase public function testGetPropertyValuesFromChainAndSingleObject() { $f = new F(1000, 'New York', 'USA', 'john.scott'); + $j = new J(); self::assertEquals(['John'], Reflection::getPropertyValues($f, 'g.firstName')); self::assertEquals(['John'], Reflection::getPropertyValues($f, 'g.firstName', true)); + + self::assertEquals(['John'], Reflection::getPropertyValues($j, 'f.g.firstName')); + self::assertEquals(['John'], Reflection::getPropertyValues($j, 'f.g.firstName', true)); } public function testGetPropertyValuesFromChainAndMultipleObjects() From 414ce0fd06461d26987719c3f29b6414f3a56119 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 13 Apr 2019 21:38:06 +0200 Subject: [PATCH 043/137] Reflection > getPropertyValue() method > refactoring --- src/Utilities/Reflection.php | 333 ++++++++++++++++++++++------------- 1 file changed, 208 insertions(+), 125 deletions(-) diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index 66d5e28..d675b72 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -156,139 +156,43 @@ class Reflection } /** - * Returns value of given property. - * Looks for proper getter for the property. + * Returns value of given property * - * @param mixed $object Object that should contains given property + * @param mixed $source Object that should contains given property * @param string $property Name of the property that contains a value. It may be also multiple properties * dot-separated, e.g. "invoice.user.email". * @param bool $force (optional) If is set to true, try to retrieve value even if the object doesn't have * property. Otherwise - not. * @return mixed */ - public static function getPropertyValue($object, $property, $force = false) + public static function getPropertyValue($source, $property, $force = false) { - $value = null; - - /* - * Property is a dot-separated string? - * Let's find all values of the chain, of the dot-separated properties - */ if (Regex::contains($property, '.')) { - $exploded = explode('.', $property); + return self::getPropertyValueByPropertiesChain($source, $property, $force); + } - $property = $exploded[0]; - $object = self::getPropertyValue($object, $property, $force); + [ + $value, + $valueFound, + ] = self::getPropertyValueByReflectionProperty($source, $property); - /* - * Value of processed property from the chain is not null? - * Let's dig more and get proper value - * - * Required to avoid bug: - * \ReflectionObject::__construct() expects parameter 1 to be object, null given - * (...) - * 4. at \ReflectionObject->__construct (null) - * 5. at Reflection ::getPropertyValue (null, 'name', true) - * 6. at ListService->getItemValue (object(Deal), 'project.name', '0') - * - * while using "project.name" as property - $project has $name property ($project exists in the Deal class) - * and the $project equals null - * - * Meritoo - * 2016-11-07 - */ - if (null !== $object) { - unset($exploded[0]); + if (!$valueFound) { + [ + $value, + $valueFound, + ] = self::getPropertyValueByParentClasses($source, $property); + } - $property = implode('.', $exploded); - $value = self::getPropertyValue($object, $property, $force); - } - } else { - $className = self::getClassName($object); - $reflectionProperty = null; + if (!$valueFound && ($force || self::hasProperty($source, $property))) { + [ + $value, + $valueFound, + ] = self::getPropertyValueByGetter($source, $property); + } - /* - * 1st try: - * Use \ReflectionObject class - */ - try { - $reflectionProperty = new \ReflectionProperty($className, $property); - $value = $reflectionProperty->getValue($object); - } catch (\ReflectionException $exception) { - /* - * 2nd try: - * Look for the property in parent classes - */ - if (null === $reflectionProperty) { - $propertyFound = false; - $reflectionProperties = self::getProperties($object, null, true); - - foreach ($reflectionProperties as $reflectionProperty) { - if ($reflectionProperty->getName() === $property) { - $propertyFound = true; - break; - } - } - - if ($propertyFound && null !== $reflectionProperty) { - $reflectionProperty->setAccessible(true); - $value = $reflectionProperty->getValue($object); - $reflectionProperty->setAccessible(false); - } - } else { - /* - * 3rd try: - * Look for the get / has / is methods - */ - $class = new \ReflectionObject($object); - $valueFound = false; - - if ($force || $class->hasProperty($property)) { - $property = Inflector::classify($property); - - $getterPrefixes = [ - 'get', - 'has', - 'is', - ]; - - foreach ($getterPrefixes as $prefix) { - $getterName = sprintf('%s%s', $prefix, $property); - - if ($class->hasMethod($getterName)) { - $method = new \ReflectionMethod($object, $getterName); - - /* - * Getter is not accessible publicly? - * I have to skip it, to avoid an error like this: - * - * Call to protected method My\ExtraClass::getExtraProperty() from context 'My\ExtraClass' - */ - if ($method->isProtected() || $method->isPrivate()) { - continue; - } - - $value = $object->{$getterName}(); - $valueFound = true; - - break; - } - } - } - - if (!$valueFound) { - /* - * Oops, value of the property is still unknown - * - * 4th try: - * Let's modify accessibility of the property and try again to get value - */ - $reflectionProperty->setAccessible(true); - $value = $reflectionProperty->getValue($object); - $reflectionProperty->setAccessible(false); - } - } - } + if (!$valueFound) { + $byReflectionProperty = self::getPropertyValueByReflectionProperty($source, $property); + $value = $byReflectionProperty[0]; } return $value; @@ -460,9 +364,9 @@ class Reflection * constants. By default all properties are returned. * @param bool $includeParents (optional) If is set to true, properties of parent classes are * included (recursively). Otherwise - not. - * @return array|\ReflectionProperty + * @return \ReflectionProperty[] */ - public static function getProperties($source, $filter = null, $includeParents = false) + public static function getProperties($source, $filter = null, $includeParents = false): array { $className = self::getClassName($source); $reflection = new \ReflectionClass($className); @@ -693,15 +597,15 @@ class Reflection throw NotExistingPropertyException::create($object, $property); } - $notAccessible = $reflectionProperty->isPrivate() || $reflectionProperty->isProtected(); + $isPublic = $reflectionProperty->isPublic(); - if ($notAccessible) { + if (!$isPublic) { $reflectionProperty->setAccessible(true); } $reflectionProperty->setValue($object, $value); - if ($notAccessible) { + if (!$isPublic) { $reflectionProperty->setAccessible(false); } } @@ -741,4 +645,183 @@ class Reflection return substr($class, $pos + Proxy::MARKER_LENGTH + 2); } + + /** + * Returns value of given property using the property represented by reflection. + * If value cannot be fetched, makes the property accessible temporarily. + * + * @param mixed $object Object that should contains given property + * @param string $property Name of the property that contains a value + * @param null|\ReflectionProperty $reflectionProperty (optional) Property represented by reflection + * @return mixed + */ + private static function getPropertyValueByReflectionProperty( + $object, + string $property, + ?\ReflectionProperty $reflectionProperty = null + ) { + $value = null; + $valueFound = false; + $className = self::getClassName($object); + + try { + if (null === $reflectionProperty) { + $reflectionProperty = new \ReflectionProperty($className, $property); + } + + $value = $reflectionProperty->getValue($object); + $valueFound = true; + } catch (\ReflectionException $exception) { + } + + if (null !== $reflectionProperty) { + $reflectionProperty->setAccessible(true); + + $value = $reflectionProperty->getValue($object); + $valueFound = true; + + $reflectionProperty->setAccessible(false); + } + + return [ + $value, + $valueFound, + ]; + } + + /** + * Returns value of given property using getter of the property + * + * An array with 2 elements is returned: + * - value of given property + * - information if the value was found (because null may be returned) + * + * @param mixed $source Object that should contains given property + * @param string $property Name of the property that contains a value + * @return array + */ + private static function getPropertyValueByGetter($source, string $property): array + { + $value = null; + $valueFound = false; + + $reflectionObject = new \ReflectionObject($source); + $property = Inflector::classify($property); + + $gettersPrefixes = [ + 'get', + 'has', + 'is', + ]; + + foreach ($gettersPrefixes as $prefix) { + $getter = sprintf('%s%s', $prefix, $property); + + if ($reflectionObject->hasMethod($getter)) { + $method = new \ReflectionMethod($source, $getter); + + /* + * Getter is not accessible publicly? + * I have to skip it, to avoid an error like this: + * + * Call to protected method My\ExtraClass::getExtraProperty() from context 'My\ExtraClass' + */ + if ($method->isProtected() || $method->isPrivate()) { + continue; + } + + $value = $source->{$getter}(); + $valueFound = true; + + break; + } + } + + return [ + $value, + $valueFound, + ]; + } + + /** + * Returns value of given property using parent classes + * + * @param mixed $source Object that should contains given property + * @param string $property Name of the property that contains a value + * @return array + */ + private static function getPropertyValueByParentClasses($source, string $property): array + { + $properties = self::getProperties($source, null, true); + + if (empty($properties)) { + return [ + null, + false, + ]; + } + + foreach ($properties as $reflectionProperty) { + if ($reflectionProperty->getName() === $property) { + $byReflectionProperty = self::getPropertyValueByReflectionProperty( + $source, + $property, + $reflectionProperty + ); + + return [ + $byReflectionProperty[0], + true, + ]; + } + } + + return [ + null, + false, + ]; + } + + /** + * Returns value of given property represented as chain of properties + * + * @param mixed $source Object that should contains given property + * @param string $property Dot-separated properties, e.g. "invoice.user.email" + * @param bool $force (optional) If is set to true, try to retrieve value even if the object doesn't have + * property. Otherwise - not. + * @return mixed + */ + private static function getPropertyValueByPropertiesChain($source, $property, $force) + { + $exploded = explode('.', $property); + + $property = $exploded[0]; + $source = self::getPropertyValue($source, $property, $force); + + /* + * Value of processed property from the chain is not null? + * Let's dig more and get proper value + * + * Required to avoid bug: + * \ReflectionObject::__construct() expects parameter 1 to be object, null given + * (...) + * 4. at \ReflectionObject->__construct (null) + * 5. at Reflection ::getPropertyValue (null, 'name', true) + * 6. at ListService->getItemValue (object(Deal), 'project.name', '0') + * + * while using "project.name" as property - $project has $name property ($project exists in the Deal class) + * and the $project equals null + * + * Meritoo + * 2016-11-07 + */ + if (null !== $source) { + unset($exploded[0]); + $property = implode('.', $exploded); + + return self::getPropertyValue($source, $property, $force); + } + + return null; + } } From b166b8b805ae97c15688d27323cae8976bd0f6dc Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 13 Apr 2019 21:47:49 +0200 Subject: [PATCH 044/137] PHP Coding Standards Fixer > fix coding standard --- tests/Type/OopVisibilityTypeTest.php | 40 ++++++++++++++-------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/Type/OopVisibilityTypeTest.php b/tests/Type/OopVisibilityTypeTest.php index f501dcd..9f5ee5f 100644 --- a/tests/Type/OopVisibilityTypeTest.php +++ b/tests/Type/OopVisibilityTypeTest.php @@ -23,26 +23,6 @@ use Meritoo\Common\Type\OopVisibilityType; */ class OopVisibilityTypeTest extends BaseTypeTestCase { - /** - * {@inheritdoc} - */ - protected function getAllExpectedTypes(): array - { - return [ - 'IS_PRIVATE' => 3, - 'IS_PROTECTED' => 2, - 'IS_PUBLIC' => 1, - ]; - } - - /** - *{@inheritdoc} - */ - protected function getTestedTypeInstance(): BaseType - { - return new OopVisibilityType(); - } - /** * {@inheritdoc} */ @@ -83,4 +63,24 @@ class OopVisibilityTypeTest extends BaseTypeTestCase true, ]; } + + /** + * {@inheritdoc} + */ + protected function getAllExpectedTypes(): array + { + return [ + 'IS_PRIVATE' => 3, + 'IS_PROTECTED' => 2, + 'IS_PUBLIC' => 1, + ]; + } + + /** + *{@inheritdoc} + */ + protected function getTestedTypeInstance(): BaseType + { + return new OopVisibilityType(); + } } From 4c6fb569bc541c894e4edb7b108b4dca1a68d296 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 15 Apr 2019 21:23:05 +0200 Subject: [PATCH 045/137] PHP Coding Standards Fixer > update configuration --- .php_cs.dist | 17 +++++++++++++++++ CHANGELOG.md | 4 ++++ VERSION | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/.php_cs.dist b/.php_cs.dist index 3b7d3f1..e787c8a 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -20,6 +20,23 @@ return PhpCsFixer\Config::create() 'concat_space' => [ 'spacing' => 'one', ], + 'ordered_class_elements' => [ + 'order' => [ + 'use_trait', + 'constant_public', + 'constant_protected', + 'constant_private', + 'property_public', + 'property_protected', + 'property_private', + 'construct', + 'destruct', + 'magic', + 'method_public', + 'method_protected', + 'method_private', + ], + ], 'phpdoc_add_missing_param_annotation' => true, 'phpdoc_align' => false, 'phpdoc_order' => true, diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cf80c0..7bd2df2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Common and useful classes, methods, exceptions etc. +# 1.0.4 + +1. PHP Coding Standards Fixer > update configuration + # 1.0.3 1. Travis CI > run many tasks using Phing > update configuration diff --git a/VERSION b/VERSION index 21e8796..ee90284 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.3 +1.0.4 From c7c96daaaf148bbad415aaf85c0fbd32f1d340ef Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 15 Apr 2019 21:23:49 +0200 Subject: [PATCH 046/137] PHP Coding Standards Fixer > fix coding standard --- tests/Collection/CollectionTest.php | 36 ++-- tests/Utilities/ArraysTest.php | 252 +++++++++++++------------- tests/Utilities/ComposerTest.php | 20 +- tests/Utilities/MiscellaneousTest.php | 44 ++--- tests/Utilities/RegexTest.php | 42 ++--- tests/Utilities/XmlTest.php | 44 ++--- tests/ValueObject/AddressTest.php | 18 +- tests/ValueObject/BankAccountTest.php | 22 +-- tests/ValueObject/CompanyTest.php | 38 ++-- 9 files changed, 258 insertions(+), 258 deletions(-) diff --git a/tests/Collection/CollectionTest.php b/tests/Collection/CollectionTest.php index 222b83c..b2d90b2 100644 --- a/tests/Collection/CollectionTest.php +++ b/tests/Collection/CollectionTest.php @@ -46,24 +46,6 @@ class CollectionTest extends BaseTestCase */ private $simpleElements; - /** - * {@inheritdoc} - */ - protected function setUp(): void - { - parent::setUp(); - - $this->simpleElements = [ - 'lorem', - 'ipsum', - 123 => 'dolor', - 345 => 'sit', - ]; - - $this->emptyCollection = new Collection(); - $this->simpleCollection = new Collection($this->simpleElements); - } - public function testEmptyCollection() { static::assertSame(0, $this->emptyCollection->count()); @@ -536,4 +518,22 @@ class CollectionTest extends BaseTestCase new \DateTime('2001-01-01'), ]; } + + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + parent::setUp(); + + $this->simpleElements = [ + 'lorem', + 'ipsum', + 123 => 'dolor', + 345 => 'sit', + ]; + + $this->emptyCollection = new Collection(); + $this->simpleCollection = new Collection($this->simpleElements); + } } diff --git a/tests/Utilities/ArraysTest.php b/tests/Utilities/ArraysTest.php index 3882298..c553f73 100644 --- a/tests/Utilities/ArraysTest.php +++ b/tests/Utilities/ArraysTest.php @@ -30,132 +30,6 @@ class ArraysTest extends BaseTestCase private $complexArray; private $superComplexArray; - /** - * {@inheritdoc} - */ - protected function setUp(): void - { - parent::setUp(); - - $this->simpleArray = [ - 'Lorem', - 'ipsum', - 'dolor', - 'sit', - 'amet', - ]; - - $this->simpleArrayWithKeys = [ - 'Lorem' => 'ipsum', - 'dolor' => 'sit', - 'amet' => 'consectetur', - ]; - - $this->twoDimensionsArray = [ - [ - 'lorem', - 'ipsum', - 'dolor', - 'sit', - 'amet', - ], - [ - 'consectetur', - 'adipiscing', - 'elit', - ], - [ - 'donec', - 'sagittis', - 'fringilla', - 'eleifend', - ], - ]; - - $this->complexArray = [ - 'lorem' => [ - 'ipsum' => [ - 'dolor' => 'sit', - 'diam' => [ - 'non' => 'egestas', - ], - ], - ], - 'consectetur' => 'adipiscing', - 'mollis' => 1234, - 2 => [], - 'sit' => [ - 'nullam' => 'donec', - 'aliquet' => [ - 'vitae' => [ - 'ligula' => 'quis', - ], - ], - 'elit', - ], - 'amet' => [ - 'iaculis', - 'primis', - ], - ]; - - $this->superComplexArray = [ - 'ipsum' => [ - 'quis' => [ - 'vestibulum' => [ - 'porta-1' => [ - 'turpis', - 'urna', - ], - 'porta-2' => [ - 'tortor' => [ - 'in' => [ - 'dui', - 'dolor' => [ - 'aliquam', - ], - ], - ], - ], - 'porta-3' => [ - 1, - 2, - 3, - ], - ], - ], - ], - 'primis' => [ - [ - 'in', - 'faucibus', - 'orci', - ], - [ - 'luctus', - 'et', - 'ultrices', - ], - ], - ]; - } - - /** - * {@inheritdoc} - */ - protected function tearDown(): void - { - parent::tearDown(); - - unset( - $this->simpleArray, - $this->simpleArrayWithKeys, - $this->twoDimensionsArray, - $this->complexArray, - $this->superComplexArray - ); - } - public function testConstructor() { static::assertHasNoConstructor(Arrays::class); @@ -2679,4 +2553,130 @@ letsTest[2] = value_2;'; ], ]; } + + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + parent::setUp(); + + $this->simpleArray = [ + 'Lorem', + 'ipsum', + 'dolor', + 'sit', + 'amet', + ]; + + $this->simpleArrayWithKeys = [ + 'Lorem' => 'ipsum', + 'dolor' => 'sit', + 'amet' => 'consectetur', + ]; + + $this->twoDimensionsArray = [ + [ + 'lorem', + 'ipsum', + 'dolor', + 'sit', + 'amet', + ], + [ + 'consectetur', + 'adipiscing', + 'elit', + ], + [ + 'donec', + 'sagittis', + 'fringilla', + 'eleifend', + ], + ]; + + $this->complexArray = [ + 'lorem' => [ + 'ipsum' => [ + 'dolor' => 'sit', + 'diam' => [ + 'non' => 'egestas', + ], + ], + ], + 'consectetur' => 'adipiscing', + 'mollis' => 1234, + 2 => [], + 'sit' => [ + 'nullam' => 'donec', + 'aliquet' => [ + 'vitae' => [ + 'ligula' => 'quis', + ], + ], + 'elit', + ], + 'amet' => [ + 'iaculis', + 'primis', + ], + ]; + + $this->superComplexArray = [ + 'ipsum' => [ + 'quis' => [ + 'vestibulum' => [ + 'porta-1' => [ + 'turpis', + 'urna', + ], + 'porta-2' => [ + 'tortor' => [ + 'in' => [ + 'dui', + 'dolor' => [ + 'aliquam', + ], + ], + ], + ], + 'porta-3' => [ + 1, + 2, + 3, + ], + ], + ], + ], + 'primis' => [ + [ + 'in', + 'faucibus', + 'orci', + ], + [ + 'luctus', + 'et', + 'ultrices', + ], + ], + ]; + } + + /** + * {@inheritdoc} + */ + protected function tearDown(): void + { + parent::tearDown(); + + unset( + $this->simpleArray, + $this->simpleArrayWithKeys, + $this->twoDimensionsArray, + $this->complexArray, + $this->superComplexArray + ); + } } diff --git a/tests/Utilities/ComposerTest.php b/tests/Utilities/ComposerTest.php index 9980e62..7bf6602 100644 --- a/tests/Utilities/ComposerTest.php +++ b/tests/Utilities/ComposerTest.php @@ -30,16 +30,6 @@ class ComposerTest extends BaseTestCase */ private $composerJsonPath; - /** - * {@inheritdoc} - */ - protected function setUp(): void - { - parent::setUp(); - - $this->composerJsonPath = $this->getFilePathForTesting(Composer::FILE_NAME_MAIN); - } - public function testConstructor() { static::assertHasNoConstructor(Composer::class); @@ -93,4 +83,14 @@ class ComposerTest extends BaseTestCase '1.0.2', ]; } + + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + parent::setUp(); + + $this->composerJsonPath = $this->getFilePathForTesting(Composer::FILE_NAME_MAIN); + } } diff --git a/tests/Utilities/MiscellaneousTest.php b/tests/Utilities/MiscellaneousTest.php index 15e33cc..7f48d98 100644 --- a/tests/Utilities/MiscellaneousTest.php +++ b/tests/Utilities/MiscellaneousTest.php @@ -32,28 +32,6 @@ class MiscellaneousTest extends BaseTestCase private $stringDotSeparated; private $stringWithoutSpaces; - /** - * {@inheritdoc} - */ - protected function setUp(): void - { - parent::setUp(); - - $this->stringSmall = 'Lorem ipsum dolor sit amet.'; - $this->stringCommaSeparated = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit'; - $this->stringDotSeparated = 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis.'; - $this->stringWithoutSpaces = 'LoremIpsumDolorSitAmetConsecteturAdipiscingElit'; - } - - /** - * {@inheritdoc} - */ - protected function tearDown(): void - { - parent::tearDown(); - unset($this->stringSmall, $this->stringCommaSeparated, $this->stringDotSeparated, $this->stringWithoutSpaces); - } - public function testConstructor() { static::assertHasNoConstructor(Miscellaneous::class); @@ -1464,4 +1442,26 @@ class MiscellaneousTest extends BaseTestCase 'Lorem \'commodo\' dolor sit \'egestas\'', ]; } + + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + parent::setUp(); + + $this->stringSmall = 'Lorem ipsum dolor sit amet.'; + $this->stringCommaSeparated = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit'; + $this->stringDotSeparated = 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis.'; + $this->stringWithoutSpaces = 'LoremIpsumDolorSitAmetConsecteturAdipiscingElit'; + } + + /** + * {@inheritdoc} + */ + protected function tearDown(): void + { + parent::tearDown(); + unset($this->stringSmall, $this->stringCommaSeparated, $this->stringDotSeparated, $this->stringWithoutSpaces); + } } diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index 9af9937..df9b925 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -28,27 +28,6 @@ class RegexTest extends BaseTestCase private $simpleText; private $camelCaseText; - /** - * {@inheritdoc} - */ - protected function setUp(): void - { - parent::setUp(); - - $this->simpleText = 'lorem ipsum dolor sit'; - $simpleUppercase = ucwords($this->simpleText); - $this->camelCaseText = str_replace(' ', '', lcfirst($simpleUppercase)); // 'loremIpsumDolorSit' - } - - /** - * {@inheritdoc} - */ - protected function tearDown(): void - { - parent::tearDown(); - unset($this->simpleText, $this->camelCaseText); - } - public function testConstructor() { static::assertHasNoConstructor(Regex::class); @@ -2003,4 +1982,25 @@ class RegexTest extends BaseTestCase true, ]; } + + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + parent::setUp(); + + $this->simpleText = 'lorem ipsum dolor sit'; + $simpleUppercase = ucwords($this->simpleText); + $this->camelCaseText = str_replace(' ', '', lcfirst($simpleUppercase)); // 'loremIpsumDolorSit' + } + + /** + * {@inheritdoc} + */ + protected function tearDown(): void + { + parent::tearDown(); + unset($this->simpleText, $this->camelCaseText); + } } diff --git a/tests/Utilities/XmlTest.php b/tests/Utilities/XmlTest.php index 3d09c50..90bd348 100644 --- a/tests/Utilities/XmlTest.php +++ b/tests/Utilities/XmlTest.php @@ -26,6 +26,28 @@ class XmlTest extends BaseTestCase private $simpleXml; private $advancedXml; + public function testConstructor() + { + static::assertHasNoConstructor(Xml::class); + } + + public function testMergeNodes() + { + // An empty XMLs + $element1 = new SimpleXMLElement(''); + $element2 = new SimpleXMLElement(''); + + $merged = Xml::mergeNodes($element1, $element2); + self::assertEquals('', (string)$merged); + + // XMLs with data + $element1 = new SimpleXMLElement($this->simpleXml); + $element2 = new SimpleXMLElement($this->advancedXml); + + $merged = Xml::mergeNodes($element1, $element2); + self::assertEquals('John', (string)$merged->author[0]->first_name); + } + /** * {@inheritdoc} */ @@ -69,26 +91,4 @@ class XmlTest extends BaseTestCase unset($this->simpleXml, $this->advancedXml); } - - public function testConstructor() - { - static::assertHasNoConstructor(Xml::class); - } - - public function testMergeNodes() - { - // An empty XMLs - $element1 = new SimpleXMLElement(''); - $element2 = new SimpleXMLElement(''); - - $merged = Xml::mergeNodes($element1, $element2); - self::assertEquals('', (string)$merged); - - // XMLs with data - $element1 = new SimpleXMLElement($this->simpleXml); - $element2 = new SimpleXMLElement($this->advancedXml); - - $merged = Xml::mergeNodes($element1, $element2); - self::assertEquals('John', (string)$merged->author[0]->first_name); - } } diff --git a/tests/ValueObject/AddressTest.php b/tests/ValueObject/AddressTest.php index e70895f..acee74c 100644 --- a/tests/ValueObject/AddressTest.php +++ b/tests/ValueObject/AddressTest.php @@ -38,15 +38,6 @@ class AddressTest extends BaseTestCase */ private $addressWithoutStreet; - protected function setUp(): void - { - parent::setUp(); - - $this->address = new Address('New York', '00123', '4th Avenue', '10', '200'); - $this->addressWithoutFlat = new Address('San Francisco', '00456', 'Green Street', '22'); - $this->addressWithoutStreet = new Address('Saint Louis', '00111', '', '1', '300'); - } - public function testConstructor() { static::assertConstructorVisibilityAndArguments( @@ -105,4 +96,13 @@ class AddressTest extends BaseTestCase static::assertSame('Green Street 22, 00456, San Francisco', (string)$this->addressWithoutFlat); static::assertSame('00111, Saint Louis', (string)$this->addressWithoutStreet); } + + protected function setUp(): void + { + parent::setUp(); + + $this->address = new Address('New York', '00123', '4th Avenue', '10', '200'); + $this->addressWithoutFlat = new Address('San Francisco', '00456', 'Green Street', '22'); + $this->addressWithoutStreet = new Address('Saint Louis', '00111', '', '1', '300'); + } } diff --git a/tests/ValueObject/BankAccountTest.php b/tests/ValueObject/BankAccountTest.php index 4d48eb7..436d3e0 100644 --- a/tests/ValueObject/BankAccountTest.php +++ b/tests/ValueObject/BankAccountTest.php @@ -33,17 +33,6 @@ class BankAccountTest extends BaseTestCase */ private $bankAccount; - /** - * {@inheritdoc} - */ - protected function setUp(): void - { - parent::setUp(); - - $this->emptyBankAccount = new BankAccount('', ''); - $this->bankAccount = new BankAccount('Bank of America', '1234567890'); - } - public function testConstructor() { static::assertConstructorVisibilityAndArguments( @@ -71,4 +60,15 @@ class BankAccountTest extends BaseTestCase static::assertSame('', (string)$this->emptyBankAccount); static::assertSame('Bank of America, 1234567890', (string)$this->bankAccount); } + + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + parent::setUp(); + + $this->emptyBankAccount = new BankAccount('', ''); + $this->bankAccount = new BankAccount('Bank of America', '1234567890'); + } } diff --git a/tests/ValueObject/CompanyTest.php b/tests/ValueObject/CompanyTest.php index 9edb320..b63dac0 100644 --- a/tests/ValueObject/CompanyTest.php +++ b/tests/ValueObject/CompanyTest.php @@ -35,25 +35,6 @@ class CompanyTest extends BaseTestCase */ private $companyWithoutBankAccount; - /** - * {@inheritdoc} - */ - protected function setUp(): void - { - parent::setUp(); - - $this->company = new Company( - 'Test 1', - new Address('New York', '00123', '4th Avenue', '10', '200'), - new BankAccount('Bank 1', '12345') - ); - - $this->companyWithoutBankAccount = new Company( - 'Test 2', - new Address('San Francisco', '00456', 'Green Street', '22') - ); - } - public function testConstructor() { static::assertConstructorVisibilityAndArguments( @@ -98,4 +79,23 @@ class CompanyTest extends BaseTestCase static::assertSame('Test 1, 4th Avenue 10/200, 00123, New York, Bank 1, 12345', (string)$this->company); static::assertSame('Test 2, Green Street 22, 00456, San Francisco', (string)$this->companyWithoutBankAccount); } + + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + parent::setUp(); + + $this->company = new Company( + 'Test 1', + new Address('New York', '00123', '4th Avenue', '10', '200'), + new BankAccount('Bank 1', '12345') + ); + + $this->companyWithoutBankAccount = new Company( + 'Test 2', + new Address('San Francisco', '00456', 'Green Street', '22') + ); + } } From f5e8c8c740a9631e0d6f59d77adb539d18509494 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 16 Apr 2019 11:44:36 +0200 Subject: [PATCH 047/137] Readme > badge with required PHP version > update & get from Packagist --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1b83a0c..c823bbe 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Common and useful classes, methods, exceptions etc. -[![PHP Version](https://img.shields.io/badge/php-%3E%3D5.6-blue.svg)](https://img.shields.io/badge/php-%3E%3D5.6-blue.svg) [![Travis](https://img.shields.io/travis/rust-lang/rust.svg?style=flat-square)](https://travis-ci.org/meritoo/common-library) [![Packagist](https://img.shields.io/packagist/v/meritoo/common-library.svg?style=flat-square)](https://packagist.org/packages/meritoo/common-library) [![license](https://img.shields.io/github/license/meritoo/common-library.svg?style=flat-square)](https://github.com/meritoo/common-library) [![GitHub commits](https://img.shields.io/github/commits-since/meritoo/common-library/0.0.1.svg?style=flat-square)](https://github.com/meritoo/common-library) [![Coverage Status](https://coveralls.io/repos/github/meritoo/common-library/badge.svg?branch=master)](https://coveralls.io/github/meritoo/common-library?branch=master) +![PHP from Packagist](https://img.shields.io/packagist/php-v/meritoo/common-library.svg) [![Travis](https://img.shields.io/travis/rust-lang/rust.svg?style=flat-square)](https://travis-ci.org/meritoo/common-library) [![Packagist](https://img.shields.io/packagist/v/meritoo/common-library.svg?style=flat-square)](https://packagist.org/packages/meritoo/common-library) [![license](https://img.shields.io/github/license/meritoo/common-library.svg?style=flat-square)](https://github.com/meritoo/common-library) [![GitHub commits](https://img.shields.io/github/commits-since/meritoo/common-library/0.0.1.svg?style=flat-square)](https://github.com/meritoo/common-library) [![Coverage Status](https://coveralls.io/repos/github/meritoo/common-library/badge.svg?branch=master)](https://coveralls.io/github/meritoo/common-library?branch=master) # Installation From 0f2c6bb0995df2969214d8c2923a53c7624d7ea0 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 18 Apr 2019 14:31:31 +0200 Subject: [PATCH 048/137] Phing > tests > add task for Psalm (https://psalm.dev) --- CHANGELOG.md | 1 + phing/properties.dist | 1 + phing/tests.xml | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bd2df2..2987754 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Common and useful classes, methods, exceptions etc. # 1.0.4 1. PHP Coding Standards Fixer > update configuration +2. Phing > tests > add task for Psalm (https://psalm.dev) # 1.0.3 diff --git a/phing/properties.dist b/phing/properties.dist index 436cec5..74bdba4 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -67,6 +67,7 @@ dir.docker.logs = ${dir.docker}/logs/nginx # - PHPStan # check.phpstan.command = ./vendor/bin/phpstan analyse +check.psalm.command = ./vendor/bin/psalm --report=build/reports/psalm.json check.php_coveralls.command = ./vendor/bin/php-coveralls --ansi -v # -------------------------------------------------------------------------------- diff --git a/phing/tests.xml b/phing/tests.xml index 4ea22f7..1edeb2c 100644 --- a/phing/tests.xml +++ b/phing/tests.xml @@ -45,6 +45,7 @@ depends="check:cs, check:cpd, check:phpstan, + check:psalm, check:coveralls" /> @@ -77,6 +78,11 @@ + + + + + From 8b5cbd6f2e2441912d455acd7479283a0a7e1989 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 19 Apr 2019 22:07:25 +0200 Subject: [PATCH 049/137] Composer.json > update PHP version constraints --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f010981..776b25d 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "php": ">=7.2", + "php": "^7.2", "ext-dom": "*", "ext-fileinfo": "*", "ext-intl": "*", From 421d19ff10741005794fa75e8e163b28c7672911 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 2 May 2019 22:51:26 +0200 Subject: [PATCH 050/137] Readme > review and fix "unknown" badges --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c823bbe..6eddebb 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,12 @@ Common and useful classes, methods, exceptions etc. -![PHP from Packagist](https://img.shields.io/packagist/php-v/meritoo/common-library.svg) [![Travis](https://img.shields.io/travis/rust-lang/rust.svg?style=flat-square)](https://travis-ci.org/meritoo/common-library) [![Packagist](https://img.shields.io/packagist/v/meritoo/common-library.svg?style=flat-square)](https://packagist.org/packages/meritoo/common-library) [![license](https://img.shields.io/github/license/meritoo/common-library.svg?style=flat-square)](https://github.com/meritoo/common-library) [![GitHub commits](https://img.shields.io/github/commits-since/meritoo/common-library/0.0.1.svg?style=flat-square)](https://github.com/meritoo/common-library) [![Coverage Status](https://coveralls.io/repos/github/meritoo/common-library/badge.svg?branch=master)](https://coveralls.io/github/meritoo/common-library?branch=master) +![PHP from Packagist](https://img.shields.io/packagist/php-v/meritoo/common-library.svg?style=flat-square) +[![Build Status](https://travis-ci.com/meritoo/common-library.svg?branch=master&style=flat-square)](https://travis-ci.com/meritoo/common-library) +[![Packagist](https://img.shields.io/packagist/v/meritoo/common-library.svg?style=flat-square)](https://packagist.org/packages/meritoo/common-library) +[![license](https://img.shields.io/github/license/meritoo/common-library.svg?style=flat-square)](https://github.com/meritoo/common-library) +[![GitHub commits](https://img.shields.io/github/commits-since/meritoo/common-library/0.0.1.svg?style=flat-square)](https://github.com/meritoo/common-library) +[![Coverage Status](https://coveralls.io/repos/github/meritoo/common-library/badge.svg?branch=master&style=flat-square)](https://coveralls.io/github/meritoo/common-library) # Installation From dd5ac0f7e6d0b2fe994303554f67210b85cc22a5 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 5 May 2019 09:49:03 +0200 Subject: [PATCH 051/137] Fix code pointed by Psalm --- src/Exception/Base/UnknownTypeException.php | 4 +- src/Exception/File/EmptyFilePathException.php | 4 +- .../CannotResolveClassNameException.php | 2 +- .../ClassWithoutConstructorException.php | 34 ++ .../MissingChildClassesException.php | 4 +- .../NotExistingPropertyException.php | 6 +- .../TooManyChildClassesException.php | 4 +- .../Type/UnknownDatePartTypeException.php | 2 +- .../UnknownOopVisibilityTypeException.php | 2 +- src/Traits/Test/Base/BaseTestCaseTrait.php | 80 ++-- .../Test/Base/BaseTypeTestCaseTrait.php | 14 +- src/Traits/ValueObject/HumanTrait.php | 35 +- src/Type/Base/BaseType.php | 8 +- src/Type/DatePeriod.php | 64 +-- src/Type/OopVisibilityType.php | 12 +- src/Utilities/Arrays.php | 314 ++++++------ src/Utilities/Miscellaneous.php | 23 +- src/Utilities/Reflection.php | 103 ++-- tests/Collection/CollectionTest.php | 14 +- .../IncorrectBundleNameExceptionTest.php | 13 +- .../CannotResolveClassNameExceptionTest.php | 19 +- .../ClassWithoutConstructorExceptionTest.php | 66 +++ .../MissingChildClassesExceptionTest.php | 14 +- .../NotExistingPropertyExceptionTest.php | 16 +- .../TooManyChildClassesExceptionTest.php | 14 +- .../UnknownOopVisibilityTypeExceptionTest.php | 14 +- tests/Type/DatePartTypeTest.php | 24 +- tests/Type/DatePeriodTest.php | 67 ++- tests/Type/OopVisibilityTypeTest.php | 16 +- tests/Utilities/ArraysTest.php | 450 +++++++++++++++--- tests/Utilities/DateTest.php | 82 ++-- tests/Utilities/MiscellaneousTest.php | 71 ++- tests/Utilities/ReflectionTest.php | 14 +- 33 files changed, 1085 insertions(+), 524 deletions(-) create mode 100644 src/Exception/Reflection/ClassWithoutConstructorException.php create mode 100644 tests/Exception/Reflection/ClassWithoutConstructorExceptionTest.php diff --git a/src/Exception/Base/UnknownTypeException.php b/src/Exception/Base/UnknownTypeException.php index 43abda2..d42571b 100644 --- a/src/Exception/Base/UnknownTypeException.php +++ b/src/Exception/Base/UnknownTypeException.php @@ -28,13 +28,13 @@ abstract class UnknownTypeException extends Exception * @param string $typeName Name of the something * @return UnknownTypeException */ - public static function create($unknownType, BaseType $typeInstance, $typeName) + public static function create($unknownType, BaseType $typeInstance, string $typeName): UnknownTypeException { $template = 'The \'%s\' type of %s is unknown. Probably doesn\'t exist or there is a typo. You should use one' . ' of these types: %s.'; $allTypes = $typeInstance->getAll(); - $types = Arrays::values2string($allTypes, '', ', '); + $types = Arrays::values2string($allTypes, '', ', ') ?? '[types not found]'; $message = sprintf($template, $unknownType, $typeName, $types); return new static($message); diff --git a/src/Exception/File/EmptyFilePathException.php b/src/Exception/File/EmptyFilePathException.php index 33333f5..f4386f7 100644 --- a/src/Exception/File/EmptyFilePathException.php +++ b/src/Exception/File/EmptyFilePathException.php @@ -18,8 +18,10 @@ class EmptyFilePathException extends \Exception { /** * Creates exception + * + * @return EmptyFilePathException */ - public static function create() + public static function create(): EmptyFilePathException { return new static('Path of the file is empty. Did you provide path of proper file?'); } diff --git a/src/Exception/Reflection/CannotResolveClassNameException.php b/src/Exception/Reflection/CannotResolveClassNameException.php index dee9dde..ff5191f 100644 --- a/src/Exception/Reflection/CannotResolveClassNameException.php +++ b/src/Exception/Reflection/CannotResolveClassNameException.php @@ -27,7 +27,7 @@ class CannotResolveClassNameException extends Exception * prepared. Otherwise - for trait. * @return CannotResolveClassNameException */ - public static function create($source, $forClass = true) + public static function create($source, bool $forClass = true): CannotResolveClassNameException { $forWho = 'trait'; $value = ''; diff --git a/src/Exception/Reflection/ClassWithoutConstructorException.php b/src/Exception/Reflection/ClassWithoutConstructorException.php new file mode 100644 index 0000000..b67a44a --- /dev/null +++ b/src/Exception/Reflection/ClassWithoutConstructorException.php @@ -0,0 +1,34 @@ + + * @copyright Meritoo + */ +class ClassWithoutConstructorException extends Exception +{ + /** + * Creates exception + * + * @param string $className Fully-qualified name of class that hasn't constructor + * @return ClassWithoutConstructorException + */ + public static function create(string $className): ClassWithoutConstructorException + { + $template = 'Oops, class \'%s\' hasn\'t constructor. Did you use proper class?'; + $message = sprintf($template, $className); + + return new static($message); + } +} diff --git a/src/Exception/Reflection/MissingChildClassesException.php b/src/Exception/Reflection/MissingChildClassesException.php index 27183ff..8a51e09 100644 --- a/src/Exception/Reflection/MissingChildClassesException.php +++ b/src/Exception/Reflection/MissingChildClassesException.php @@ -26,12 +26,12 @@ class MissingChildClassesException extends Exception * strings, object or string. * @return MissingChildClassesException */ - public static function create($parentClass) + public static function create($parentClass): MissingChildClassesException { $template = 'The \'%s\' class requires one child class at least who will extend her (maybe is an abstract' . ' class), but the child classes are missing. Did you forget to extend this class?'; - $parentClassName = Reflection::getClassName($parentClass); + $parentClassName = Reflection::getClassName($parentClass) ?? '[unknown class]'; $message = sprintf($template, $parentClassName); return new static($message); diff --git a/src/Exception/Reflection/NotExistingPropertyException.php b/src/Exception/Reflection/NotExistingPropertyException.php index 4b7484f..35723a4 100644 --- a/src/Exception/Reflection/NotExistingPropertyException.php +++ b/src/Exception/Reflection/NotExistingPropertyException.php @@ -19,11 +19,11 @@ class NotExistingPropertyException extends \Exception /** * Creates exception * - * @param mixed $object Object that should contains given property - * @param string $property Name of the property + * @param mixed $object Object that should contains given property + * @param null|string $property Name of the property * @return NotExistingPropertyException */ - public static function create($object, $property) + public static function create($object, ?string $property): NotExistingPropertyException { $template = 'Property \'%s\' does not exist in instance of class \'%s\'. Did you use proper name of property?'; $message = sprintf($template, $property, get_class($object)); diff --git a/src/Exception/Reflection/TooManyChildClassesException.php b/src/Exception/Reflection/TooManyChildClassesException.php index f06dab2..19967dc 100644 --- a/src/Exception/Reflection/TooManyChildClassesException.php +++ b/src/Exception/Reflection/TooManyChildClassesException.php @@ -27,12 +27,12 @@ class TooManyChildClassesException extends Exception * @param array $childClasses Child classes * @return TooManyChildClassesException */ - public static function create($parentClass, array $childClasses) + public static function create($parentClass, array $childClasses): TooManyChildClassesException { $template = "The '%s' class requires one child class at most who will extend her, but more than one child" . " class was found:\n- %s\n\nWhy did you create more than one classes that extend '%s' class?"; - $parentClassName = Reflection::getClassName($parentClass); + $parentClassName = Reflection::getClassName($parentClass) ?? '[unknown class]'; $message = sprintf($template, $parentClassName, implode("\n- ", $childClasses), $parentClassName); return new static($message); diff --git a/src/Exception/Type/UnknownDatePartTypeException.php b/src/Exception/Type/UnknownDatePartTypeException.php index 2a85b2b..29e1d5a 100644 --- a/src/Exception/Type/UnknownDatePartTypeException.php +++ b/src/Exception/Type/UnknownDatePartTypeException.php @@ -26,7 +26,7 @@ class UnknownDatePartTypeException extends UnknownTypeException * @param string $value Incorrect value * @return UnknownDatePartTypeException */ - public static function createException($unknownDatePart, $value) + public static function createException(string $unknownDatePart, string $value): UnknownDatePartTypeException { return parent::create($unknownDatePart, new DatePartType(), sprintf('date part (with value %s)', $value)); } diff --git a/src/Exception/Type/UnknownOopVisibilityTypeException.php b/src/Exception/Type/UnknownOopVisibilityTypeException.php index 6f4ef01..6463362 100644 --- a/src/Exception/Type/UnknownOopVisibilityTypeException.php +++ b/src/Exception/Type/UnknownOopVisibilityTypeException.php @@ -25,7 +25,7 @@ class UnknownOopVisibilityTypeException extends UnknownTypeException * @param string $unknownType Unknown visibility of a property, a method or (as of PHP 7.1.0) a constant * @return UnknownOopVisibilityTypeException */ - public static function createException($unknownType) + public static function createException(string $unknownType): UnknownOopVisibilityTypeException { return parent::create($unknownType, new OopVisibilityType(), 'OOP-related visibility'); } diff --git a/src/Traits/Test/Base/BaseTestCaseTrait.php b/src/Traits/Test/Base/BaseTestCaseTrait.php index 30bffcd..dfb5452 100644 --- a/src/Traits/Test/Base/BaseTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTestCaseTrait.php @@ -10,11 +10,13 @@ namespace Meritoo\Common\Traits\Test\Base; use DateTime; use Generator; +use Meritoo\Common\Exception\Reflection\ClassWithoutConstructorException; use Meritoo\Common\Exception\Type\UnknownOopVisibilityTypeException; use Meritoo\Common\Type\OopVisibilityType; use Meritoo\Common\Utilities\Miscellaneous; use ReflectionClass; use ReflectionMethod; +use RuntimeException; use stdClass; /** @@ -37,7 +39,7 @@ trait BaseTestCaseTrait * * @return Generator */ - public function provideEmptyValue() + public function provideEmptyValue(): ?Generator { yield['']; yield[' ']; @@ -52,7 +54,7 @@ trait BaseTestCaseTrait * * @return Generator */ - public function provideEmptyScalarValue() + public function provideEmptyScalarValue(): ?Generator { yield['']; yield[' ']; @@ -66,7 +68,7 @@ trait BaseTestCaseTrait * * @return Generator */ - public function provideBooleanValue() + public function provideBooleanValue(): ?Generator { yield[false]; yield[true]; @@ -77,7 +79,7 @@ trait BaseTestCaseTrait * * @return Generator */ - public function provideDateTimeInstance() + public function provideDateTimeInstance(): ?Generator { yield[new DateTime()]; yield[new DateTime('yesterday')]; @@ -90,7 +92,7 @@ trait BaseTestCaseTrait * * @return Generator */ - public function provideDateTimeRelativeFormat() + public function provideDateTimeRelativeFormat(): ?Generator { yield['now']; yield['yesterday']; @@ -110,7 +112,7 @@ trait BaseTestCaseTrait * * @return Generator */ - public function provideNotExistingFilePath() + public function provideNotExistingFilePath(): ?Generator { yield['lets-test.doc']; yield['lorem/ipsum.jpg']; @@ -122,7 +124,7 @@ trait BaseTestCaseTrait * * @return Generator */ - public function provideNonScalarValue() + public function provideNonScalarValue(): ?Generator { yield[ [], @@ -145,7 +147,7 @@ trait BaseTestCaseTrait * @param string $directoryPath (optional) Path of directory containing the file * @return string */ - public function getFilePathForTesting($fileName, $directoryPath = '') + public function getFilePathForTesting(string $fileName, string $directoryPath = ''): string { $rootPath = Miscellaneous::getProjectRootPath(); @@ -162,33 +164,34 @@ trait BaseTestCaseTrait /** * Verifies visibility and arguments of method * - * @param string $classNamespace Namespace of class that contains method to verify - * @param ReflectionMethod|string $method Name of method or just the method to verify - * @param string $visibilityType Expected visibility of verified method. One of - * OopVisibilityType class constants. - * @param int $argumentsCount (optional) Expected count/amount of arguments of the - * verified method - * @param int $requiredArgumentsCount (optional) Expected count/amount of required arguments - * of the verified method + * @param string $className Fully-qualified name of class that contains method to verify + * @param ReflectionMethod $method Name of method or just the method to verify + * @param string $visibilityType Expected visibility of verified method. One of OopVisibilityType + * class constants. + * @param int $argumentsCount (optional) Expected count/amount of arguments of the verified + * method + * @param int $requiredArgumentsCount (optional) Expected count/amount of required arguments of the + * verified method * @throws UnknownOopVisibilityTypeException + * @throws RuntimeException * * Attention. 2nd argument, the $method, may be: * - string - name of the method * - instance of ReflectionMethod - just the method (provided by ReflectionClass::getMethod() method) */ protected static function assertMethodVisibilityAndArguments( - $classNamespace, - $method, - $visibilityType, - $argumentsCount = 0, - $requiredArgumentsCount = 0 - ) { + string $className, + ReflectionMethod $method, + string $visibilityType, + int $argumentsCount = 0, + int $requiredArgumentsCount = 0 + ): void { // Type of visibility is not correct? if (!(new OopVisibilityType())->isCorrectType($visibilityType)) { - throw new UnknownOopVisibilityTypeException($visibilityType); + throw UnknownOopVisibilityTypeException::createException($visibilityType); } - $reflection = new ReflectionClass($classNamespace); + $reflection = new ReflectionClass($className); // Name of method provided only? // Let's find instance of the method (based on reflection) @@ -218,24 +221,29 @@ trait BaseTestCaseTrait /** * Verifies visibility and arguments of class constructor * - * @param string $classNamespace Namespace of class that contains constructor to verify + * @param string $className Fully-qualified name of class that contains constructor to verify * @param string $visibilityType Expected visibility of verified method. One of OopVisibilityType class * constants. * @param int $argumentsCount (optional) Expected count/amount of arguments of the verified method * @param int $requiredArgumentsCount (optional) Expected count/amount of required arguments of the verified * method + * @throws ClassWithoutConstructorException */ protected static function assertConstructorVisibilityAndArguments( - $classNamespace, - $visibilityType, - $argumentsCount = 0, - $requiredArgumentsCount = 0 - ) { - $reflection = new ReflectionClass($classNamespace); + string $className, + string $visibilityType, + int $argumentsCount = 0, + int $requiredArgumentsCount = 0 + ): void { + $reflection = new ReflectionClass($className); $method = $reflection->getConstructor(); + if (null === $method) { + throw ClassWithoutConstructorException::create($className); + } + static::assertMethodVisibilityAndArguments( - $classNamespace, + $className, $method, $visibilityType, $argumentsCount, @@ -246,11 +254,11 @@ trait BaseTestCaseTrait /** * Asserts that class with given namespace has no constructor * - * @param string $classNamespace Namespace of class that contains constructor to verify + * @param string $className Fully-qualified name of class that contains constructor to verify */ - protected static function assertHasNoConstructor($classNamespace) + protected static function assertHasNoConstructor(string $className): void { - $reflection = new ReflectionClass($classNamespace); + $reflection = new ReflectionClass($className); $constructor = $reflection->getConstructor(); static::assertNull($constructor); @@ -261,7 +269,7 @@ trait BaseTestCaseTrait * * @param string $testsDataDirPath Path of directory with data used by test cases */ - protected static function setTestsDataDirPath($testsDataDirPath) + protected static function setTestsDataDirPath(string $testsDataDirPath): void { static::$testsDataDirPath = $testsDataDirPath; } diff --git a/src/Traits/Test/Base/BaseTypeTestCaseTrait.php b/src/Traits/Test/Base/BaseTypeTestCaseTrait.php index 5633c8d..4fc2f1a 100644 --- a/src/Traits/Test/Base/BaseTypeTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTypeTestCaseTrait.php @@ -22,7 +22,7 @@ trait BaseTypeTestCaseTrait /** * Verifies availability of all types */ - public function testAvailabilityOfAllTypes() + public function testAvailabilityOfAllTypes(): void { $available = $this->getTestedTypeInstance()->getAll(); $all = $this->getAllExpectedTypes(); @@ -33,12 +33,12 @@ trait BaseTypeTestCaseTrait /** * Verifies whether given type is correct or not * - * @param string $type Type to verify - * @param bool $expected Information if given type is correct or not + * @param null|string $type Type to verify + * @param bool $expected Information if given type is correct or not * * @dataProvider provideTypeToVerify */ - public function testIfGivenTypeIsCorrect($type, $expected) + public function testIfGivenTypeIsCorrect(?string $type, bool $expected): void { static::assertEquals($expected, $this->getTestedTypeInstance()->isCorrectType($type)); } @@ -48,19 +48,19 @@ trait BaseTypeTestCaseTrait * * @return Generator */ - abstract public function provideTypeToVerify(); + abstract public function provideTypeToVerify(): Generator; /** * Returns instance of the tested type * * @return BaseType */ - abstract protected function getTestedTypeInstance(); + abstract protected function getTestedTypeInstance(): BaseType; /** * Returns all expected types of the tested type * * @return array */ - abstract protected function getAllExpectedTypes(); + abstract protected function getAllExpectedTypes(): array; } diff --git a/src/Traits/ValueObject/HumanTrait.php b/src/Traits/ValueObject/HumanTrait.php index e0eb795..a75bfa6 100644 --- a/src/Traits/ValueObject/HumanTrait.php +++ b/src/Traits/ValueObject/HumanTrait.php @@ -8,6 +8,8 @@ namespace Meritoo\Common\Traits\ValueObject; +use DateTime; + /** * Methods and properties related to human * @@ -33,26 +35,26 @@ trait HumanTrait /** * Email address * - * @var string + * @var null|string */ protected $email; /** * Birth date * - * @var \DateTime + * @var null|DateTime */ protected $birthDate; /** * Class constructor * - * @param string $firstName First name - * @param string $lastName Last name - * @param string $email (optional) Email address - * @param \DateTime $birthDate (optional) Birth date + * @param string $firstName First name + * @param string $lastName Last name + * @param null|string $email (optional) Email address. Default: null. + * @param null|DateTime $birthDate (optional) Birth date. Default: null. */ - public function __construct($firstName, $lastName, $email = null, \DateTime $birthDate = null) + public function __construct(string $firstName, string $lastName, ?string $email = null, ?DateTime $birthDate = null) { $this->firstName = $firstName; $this->lastName = $lastName; @@ -68,12 +70,14 @@ trait HumanTrait public function __toString() { $template = '%s'; + $email = ''; if ('' !== $this->email && null !== $this->email) { $template .= ' <%s>'; + $email = $this->email; } - return sprintf($template, $this->getFullName(), $this->email); + return sprintf($template, $this->getFullName(), $email); } /** @@ -81,7 +85,7 @@ trait HumanTrait * * @return string */ - public function getFirstName() + public function getFirstName(): string { return $this->firstName; } @@ -91,7 +95,7 @@ trait HumanTrait * * @return string */ - public function getLastName() + public function getLastName(): string { return $this->lastName; } @@ -101,7 +105,7 @@ trait HumanTrait * * @return null|string */ - public function getEmail() + public function getEmail(): ?string { return $this->email; } @@ -109,9 +113,9 @@ trait HumanTrait /** * Returns birth date * - * @return null|\DateTime + * @return null|DateTime */ - public function getBirthDate() + public function getBirthDate(): ?DateTime { return $this->birthDate; } @@ -119,10 +123,11 @@ trait HumanTrait /** * Returns the full name * - * @param bool $firstNameFirst (optional) If is set to true, first name is the first part. Otherwise - last name. + * @param bool $firstNameFirst (optional) If is set to true, first name is the first part (default behaviour). + * Otherwise - name. * @return string */ - public function getFullName($firstNameFirst = true) + public function getFullName(bool $firstNameFirst = true): string { $beginning = $this->lastName; $finish = $this->firstName; diff --git a/src/Type/Base/BaseType.php b/src/Type/Base/BaseType.php index ec8dafa..fa3f6c7 100644 --- a/src/Type/Base/BaseType.php +++ b/src/Type/Base/BaseType.php @@ -22,7 +22,7 @@ abstract class BaseType /** * All types * - * @var array + * @var null|array */ private $all; @@ -31,7 +31,7 @@ abstract class BaseType * * @return array */ - public function getAll() + public function getAll(): array { if (null === $this->all) { $this->all = Reflection::getConstants($this); @@ -43,10 +43,10 @@ abstract class BaseType /** * Returns information if given type is correct * - * @param mixed $type The type to check + * @param null|string $type The type to check * @return bool */ - public function isCorrectType($type) + public function isCorrectType(?string $type): bool { return in_array($type, $this->getAll(), true); } diff --git a/src/Type/DatePeriod.php b/src/Type/DatePeriod.php index 590e8ff..d25985c 100644 --- a/src/Type/DatePeriod.php +++ b/src/Type/DatePeriod.php @@ -24,87 +24,87 @@ class DatePeriod extends BaseType /** * The period constant: last month * - * @var int + * @var string */ - public const LAST_MONTH = 4; + public const LAST_MONTH = '4'; /** * The period constant: last week * - * @var int + * @var string */ - public const LAST_WEEK = 1; + public const LAST_WEEK = '1'; /** * The period constant: last year * - * @var int + * @var string */ - public const LAST_YEAR = 7; + public const LAST_YEAR = '7'; /** * The period constant: next month * - * @var int + * @var string */ - public const NEXT_MONTH = 6; + public const NEXT_MONTH = '6'; /** * The period constant: next week * - * @var int + * @var string */ - public const NEXT_WEEK = 3; + public const NEXT_WEEK = '3'; /** * The period constant: next year * - * @var int + * @var string */ - public const NEXT_YEAR = 9; + public const NEXT_YEAR = '9'; /** * The period constant: this month * - * @var int + * @var string */ - public const THIS_MONTH = 5; + public const THIS_MONTH = '5'; /** * The period constant: this week * - * @var int + * @var string */ - public const THIS_WEEK = 2; + public const THIS_WEEK = '2'; /** * The period constant: this year * - * @var int + * @var string */ - public const THIS_YEAR = 8; + public const THIS_YEAR = '8'; /** * The start date of period * - * @var DateTime + * @var null|DateTime */ private $startDate; /** * The end date of period * - * @var DateTime + * @var null|DateTime */ private $endDate; /** * Class constructor * - * @param DateTime $startDate (optional) The start date of period - * @param DateTime $endDate (optional) The end date of period + * @param null|DateTime $startDate (optional) The start date of period + * @param null|DateTime $endDate (optional) The end date of period */ - public function __construct(DateTime $startDate = null, DateTime $endDate = null) + public function __construct(?DateTime $startDate = null, ?DateTime $endDate = null) { $this->startDate = $startDate; $this->endDate = $endDate; @@ -117,7 +117,7 @@ class DatePeriod extends BaseType * @param bool $startDate (optional) If is set to true, start date will be formatted. Otherwise - end date. * @return string */ - public function getFormattedDate($format, $startDate = true) + public function getFormattedDate(string $format, bool $startDate = true): string { $date = $this->getEndDate(); @@ -138,9 +138,9 @@ class DatePeriod extends BaseType /** * Returns the end date of period * - * @return DateTime + * @return null|DateTime */ - public function getEndDate() + public function getEndDate(): ?DateTime { return $this->endDate; } @@ -148,10 +148,10 @@ class DatePeriod extends BaseType /** * Sets the end date of period * - * @param DateTime $endDate (optional) The end date of period + * @param null|DateTime $endDate (optional) The end date of period. Default: null. * @return $this */ - public function setEndDate(DateTime $endDate = null) + public function setEndDate(?DateTime $endDate = null): self { $this->endDate = $endDate; @@ -161,9 +161,9 @@ class DatePeriod extends BaseType /** * Returns the start date of period * - * @return DateTime + * @return null|DateTime */ - public function getStartDate() + public function getStartDate(): ?DateTime { return $this->startDate; } @@ -171,10 +171,10 @@ class DatePeriod extends BaseType /** * Sets the start date of period * - * @param DateTime $startDate (optional) The start date of period + * @param null|DateTime $startDate (optional) The start date of period. Default: null. * @return $this */ - public function setStartDate(DateTime $startDate = null) + public function setStartDate(?DateTime $startDate = null): self { $this->startDate = $startDate; diff --git a/src/Type/OopVisibilityType.php b/src/Type/OopVisibilityType.php index 95eb52a..1299eea 100644 --- a/src/Type/OopVisibilityType.php +++ b/src/Type/OopVisibilityType.php @@ -17,21 +17,21 @@ class OopVisibilityType extends BaseType /** * The "private" visibility of OOP * - * @var int + * @var string */ - public const IS_PRIVATE = 3; + public const IS_PRIVATE = '3'; /** * The "protected" visibility of OOP * - * @var int + * @var string */ - public const IS_PROTECTED = 2; + public const IS_PROTECTED = '2'; /** * The "public" visibility of OOP * - * @var int + * @var string */ - public const IS_PUBLIC = 1; + public const IS_PUBLIC = '1'; } diff --git a/src/Utilities/Arrays.php b/src/Utilities/Arrays.php index b20fba7..3652ebb 100644 --- a/src/Utilities/Arrays.php +++ b/src/Utilities/Arrays.php @@ -335,7 +335,7 @@ class Arrays * The last row is not an array or it's an empty array? * Let's use the previous candidate */ - if (!is_array($effect) || (is_array($effect) && empty($effect))) { + if (!is_array($effect) || self::isEmptyArray($effect)) { $effect = $last; } } @@ -346,27 +346,29 @@ class Arrays /** * Replaces array keys that match given pattern with new key name * - * @param array $dataArray The array - * @param string $oldKeyPattern Old key pattern - * @param string $newKey New key name - * @return array + * @param array $array Array which keys should be replaced + * @param string $oldKeyPattern Regular expression of the old key + * @param string $newKey Name of the new key + * @return null|array */ - public static function replaceArrayKeys($dataArray, $oldKeyPattern, $newKey) + public static function replaceKeys(array $array, string $oldKeyPattern, string $newKey): ?array { + if (empty($array)) { + return null; + } + $effect = []; - if (is_array($dataArray) && !empty($dataArray)) { - foreach ($dataArray as $key => $value) { - if (preg_match($oldKeyPattern, $key)) { - $key = $newKey; - } - - if (is_array($value)) { - $value = self::replaceArrayKeys($value, $oldKeyPattern, $newKey); - } - - $effect[$key] = $value; + foreach ($array as $key => $value) { + if (preg_match($oldKeyPattern, $key)) { + $key = $newKey; } + + if (is_array($value)) { + $value = self::replaceKeys($value, $oldKeyPattern, $newKey); + } + + $effect[$key] = $value; } return $effect; @@ -376,17 +378,18 @@ class Arrays * Generates JavaScript code for given PHP array * * @param array $array The array that should be generated to JavaScript - * @param string $jsVariableName (optional) Name of the variable that will be in generated JavaScript code + * @param string $jsVariableName (optional) Name of the variable that will be in generated JavaScript code. + * Default: "autoGeneratedVariable". * @param bool $preserveIndexes (optional) If is set to true and $jsVariableName isn't empty, indexes also - * will be added to the JavaScript code. Otherwise not. + * will be added to the JavaScript code. Otherwise not (default behaviour). * @return null|string */ - public static function array2JavaScript(array $array, $jsVariableName = '', $preserveIndexes = false) - { - /* - * No elements? - * Nothing to do - */ + public static function array2JavaScript( + array $array, + string $jsVariableName = '', + bool $preserveIndexes = false + ): ?string { + // No elements? Nothing to do if (empty($array)) { return null; } @@ -396,7 +399,11 @@ class Arrays $arrayCount = count($array); $arrayPrepared = self::quoteStrings($array); - $isMultiDimensional = self::isMultiDimensional($arrayPrepared); + $isMultiDimensional = false; + + if (null !== $arrayPrepared) { + $isMultiDimensional = self::isMultiDimensional($arrayPrepared); + } /* * Name of the variable was not provided and it's a multi dimensional array? @@ -406,7 +413,7 @@ class Arrays $jsVariableName = 'autoGeneratedVariable'; } - if (!empty($jsVariableName) && is_string($jsVariableName)) { + if (!empty($jsVariableName)) { $result .= sprintf('var %s = ', $jsVariableName); } @@ -417,50 +424,52 @@ class Arrays $result .= ');'; } - foreach ($arrayPrepared as $index => $value) { - ++$counter; + if (null !== $arrayPrepared) { + foreach ($arrayPrepared as $index => $value) { + ++$counter; - if (is_array($value)) { - $variable = $index; + if (is_array($value)) { + $variable = $index; - if (is_int($index)) { - $variable = 'value_' . $variable; - } - - $value = self::array2JavaScript($value, $variable, $preserveIndexes); - - if (null !== $value && '' !== $value) { - /* - * Add an empty line for the 1st iteration only. Required to avoid missing empty line after - * declaration of variable: - * - * var autoGeneratedVariable = new Array(...);autoGeneratedVariable[0] = new Array(...); - * autoGeneratedVariable[1] = new Array(...); - */ - if (1 === $counter) { - $result .= "\n"; + if (is_int($index)) { + $variable = 'value_' . $variable; } - $result .= $value . "\n"; - $result .= sprintf('%s[%s] = %s;', $jsVariableName, Miscellaneous::quoteValue($index), $variable); + $value = self::array2JavaScript($value, $variable, $preserveIndexes); - if ($counter !== $arrayCount) { - $result .= "\n"; + if (null !== $value && '' !== $value) { + /* + * Add an empty line for the 1st iteration only. Required to avoid missing empty line after + * declaration of variable: + * + * var autoGeneratedVariable = new Array(...);autoGeneratedVariable[0] = new Array(...); + * autoGeneratedVariable[1] = new Array(...); + */ + if (1 === $counter) { + $result .= "\n"; + } + + $result .= $value . "\n"; + $result .= sprintf('%s[%s] = %s;', $jsVariableName, Miscellaneous::quoteValue($index), $variable); + + if ($counter !== $arrayCount) { + $result .= "\n"; + } } - } - } elseif ($preserveIndexes) { - if (!empty($jsVariableName)) { - $index = Miscellaneous::quoteValue($index); - $result .= sprintf("\n%s[%s] = %s;", $jsVariableName, $index, $value); - } - } else { - $format = '%s'; + } elseif ($preserveIndexes) { + if (!empty($jsVariableName)) { + $index = Miscellaneous::quoteValue($index); + $result .= sprintf("\n%s[%s] = %s;", $jsVariableName, $index, $value); + } + } else { + $format = '%s'; - if ($counter < $arrayCount) { - $format .= ', '; - } + if ($counter < $arrayCount) { + $format .= ', '; + } - $result .= sprintf($format, $value); + $result .= sprintf($format, $value); + } } } @@ -477,7 +486,7 @@ class Arrays * @param array $array The array to check for string values * @return null|array */ - public static function quoteStrings(array $array) + public static function quoteStrings(array $array): ?array { /* * No elements? @@ -492,10 +501,8 @@ class Arrays foreach ($array as $index => $value) { if (is_array($value)) { $value = self::quoteStrings($value); - } elseif (is_string($value)) { - if (!Regex::isQuoted($value)) { - $value = '\'' . $value . '\''; - } + } elseif (is_string($value) && !Regex::isQuoted($value)) { + $value = '\'' . $value . '\''; } $result[$index] = $value; @@ -505,31 +512,28 @@ class Arrays } /** - * Removes marginal element (first or last) + * Removes marginal element (first or last) from given array * - * @param array|string $item The item which should be shortened - * @param bool $last (optional) If is set to true, last element is removed. Otherwise - first. - * @return array|string + * @param array $array The array which should be shortened + * @param bool $last (optional) If is set to true, last element is removed (default behaviour). Otherwise - first. + * @return null|array */ - public static function removeMarginalElement($item, $last = true) + public static function removeMarginalElement(array $array, bool $last = true): ?array { - if (is_string($item)) { - if ($last) { - $item = substr($item, 0, -1); - } else { - $item = substr($item, 1); - } - } elseif (is_array($item)) { - $key = self::getFirstKey($item); - - if ($last) { - $key = self::getLastKey($item); - } - - unset($item[$key]); + // No elements? Nothing to do + if (empty($array)) { + return null; } - return $item; + $key = self::getFirstKey($array); + + if ($last) { + $key = self::getLastKey($array); + } + + unset($array[$key]); + + return $array; } /** @@ -590,7 +594,7 @@ class Arrays * @param bool $before (optional) If is set to true, all elements before given needle are removed. Otherwise - all * after needle. */ - public static function removeElements(array &$array, $needle, $before = true) + public static function removeElements(array &$array, $needle, $before = true): void { if (!empty($array)) { if (!$before) { @@ -604,7 +608,7 @@ class Arrays if ($isArray) { self::removeElements($value, $needle, $before); - if ($isArray && empty($value)) { + if (empty($value)) { $remove = true; } } elseif ($value === $needle) { @@ -730,7 +734,7 @@ class Arrays * @param array $array The array to count * @return null|int */ - public static function getNonArrayElementsCount(array $array) + public static function getNonArrayElementsCount(array $array): ?int { /* * No elements? @@ -742,9 +746,9 @@ class Arrays $count = 0; - foreach ($array as &$value) { + foreach ($array as $value) { if (is_array($value)) { - $count += self::getNonArrayElementsCount($value); + $count += (int)self::getNonArrayElementsCount($value); continue; } @@ -772,14 +776,14 @@ class Arrays * @param string $separator (optional) Separator used between name-value pairs in the string. * Default: "|". * @param string $valuesKeysSeparator (optional) Separator used between name and value in the string. Default: ":". - * @return array + * @return null|array */ - public static function string2array($string, $separator = '|', $valuesKeysSeparator = ':') - { - /* - * Empty string? - * Nothing to do - */ + public static function string2array( + string $string, + string $separator = '|', + string $valuesKeysSeparator = ':' + ): ?array { + // Empty string? Nothing to do if (empty($string)) { return null; } @@ -844,12 +848,12 @@ class Arrays /** * Returns paths of the last elements * - * @param array $array The array with elements - * @param string $separator (optional) Separator used between elements. Default: ".". - * @param string $parentPath (optional) Path of the parent element. Default: "". - * @param array|string $stopIfMatchedBy (optional) Patterns of keys or paths that matched will stop the process - * of path building and including children of those keys or paths (recursive - * will not be used for keys in lower level of given array). Default: "". + * @param array $array The array with elements + * @param string $separator (optional) Separator used between elements. Default: ".". + * @param string $parentPath (optional) Path of the parent element. Default: "". + * @param array $stopIfMatchedBy (optional) Patterns of keys or paths when matched will stop the process of path + * building and including children of those keys or paths (recursive will not be + * used for keys in lower level of given array). Default: []. * @return null|array * * Examples - $stopIfMatchedBy argument: @@ -859,21 +863,18 @@ class Arrays * "\d+", * ]; */ - public static function getLastElementsPaths(array $array, $separator = '.', $parentPath = '', $stopIfMatchedBy = '') - { - /* - * No elements? - * Nothing to do - */ + public static function getLastElementsPaths( + array $array, + string $separator = '.', + string $parentPath = '', + array $stopIfMatchedBy = [] + ): ?array { + // No elements? Nothing to do if (empty($array)) { return null; } - if (!empty($stopIfMatchedBy)) { - $stopIfMatchedBy = self::makeArray($stopIfMatchedBy); - } - - $paths = []; + $result = []; foreach ($array as $key => $value) { $path = $key; @@ -908,24 +909,27 @@ class Arrays /* * The value is passed to the returned array if: + * - the process is stopped, recursive is not used + * or * - it's not an array * or - * - the process is stopped, recursive is not used + * - it's an array, but empty */ - if (!$valueIsArray || ($valueIsArray && empty($value)) || $stopRecursion) { - $paths[$path] = $value; + if ($stopRecursion || !$valueIsArray || self::isEmptyArray($value)) { + $result[$path] = $value; continue; } // Let's iterate through the next level, using recursive - if ($valueIsArray) { - $recursivePaths = self::getLastElementsPaths($value, $separator, $path, $stopIfMatchedBy); - $paths += $recursivePaths; + $recursivePaths = self::getLastElementsPaths($value, $separator, $path, $stopIfMatchedBy); + + if (null !== $recursivePaths) { + $result += $recursivePaths; } } - return $paths; + return $result; } /** @@ -934,7 +938,7 @@ class Arrays * @param mixed $variable Variable that should be an array * @return array */ - public static function makeArray($variable) + public static function makeArray($variable): array { if (is_array($variable)) { return $variable; @@ -952,7 +956,7 @@ class Arrays * first level only. * @return bool */ - public static function areAllKeysMatchedByPattern(array $array, $pattern, $firstLevelOnly = false) + public static function areAllKeysMatchedByPattern(array $array, string $pattern, bool $firstLevelOnly = false): bool { /* * No elements? @@ -1413,9 +1417,9 @@ class Arrays * (default behaviour). * @return array */ - public static function arrayDiffRecursive(array $array1, array $array2, $valuesOnly = false) + public static function arrayDiffRecursive(array $array1, array $array2, bool $valuesOnly = false): array { - $effect = []; + $result = []; /* * Values should be compared only and both arrays are one-dimensional? @@ -1436,7 +1440,7 @@ class Arrays if ($array2HasKey && is_array($array2[$key])) { $difference = self::arrayDiffRecursive($value, $array2[$key], $valuesOnly); } - } elseif (!$array2HasKey || ($array2HasKey && $value !== $array2[$key])) { + } elseif (!$array2HasKey || $value !== $array2[$key]) { /* * We are here, because: * a) 2nd array hasn't key from 1st array @@ -1447,7 +1451,7 @@ class Arrays } if (null !== $difference) { - $effect[] = $difference; + $result[] = $difference; } // The key exists in 2nd array? @@ -1465,19 +1469,19 @@ class Arrays continue; } - $effect[$key] = $diff; + $result[$key] = $diff; } elseif ($value !== $array2[$key]) { // Value is different than in 2nd array? // OKay, I've got difference - $effect[$key] = $value; + $result[$key] = $value; } } else { // OKay, I've got difference - $effect[$key] = $value; + $result[$key] = $value; } } - return $effect; + return $result; } /** @@ -1513,7 +1517,7 @@ class Arrays * @param int $incrementStep (optional) Value used for incrementation. The step of incrementation. * @return null|array */ - public static function incrementIndexes(array $array, $startIndex = null, $incrementStep = 1) + public static function incrementIndexes(array $array, ?int $startIndex = null, int $incrementStep = 1): ?array { /* * No elements? @@ -1557,7 +1561,7 @@ class Arrays */ if (!empty($valuesToIncrement)) { foreach ($valuesToIncrement as $oldIndex => $value) { - $newIndex = $oldIndex + $incrementStep; + $newIndex = (int)$oldIndex + $incrementStep; $array[$newIndex] = $value; } } @@ -1596,7 +1600,7 @@ class Arrays * @param array $array The array to verify * @return null|bool */ - public static function isMultiDimensional(array $array) + public static function isMultiDimensional(array $array): ?bool { /* * No elements? @@ -1615,7 +1619,7 @@ class Arrays * @param array $array The array to verify * @return int */ - public static function getDimensionsCount(array $array) + public static function getDimensionsCount(array $array): int { /* * No elements? @@ -1650,7 +1654,7 @@ class Arrays * @param array $values The values to filter * @return null|array */ - public static function getNonEmptyValues(array $values) + public static function getNonEmptyValues(array $values): ?array { /* * No values? @@ -1660,9 +1664,9 @@ class Arrays return null; } - return array_filter($values, function ($value) { + return array_filter($values, static function ($value): bool { $nonEmptyScalar = is_scalar($value) && '' !== $value; - $nonEmptyArray = is_array($value) && !empty($value); + $nonEmptyArray = self::isNotEmptyArray($value); return $nonEmptyScalar || $nonEmptyArray || is_object($value); }); @@ -1675,7 +1679,7 @@ class Arrays * @param string $separator (optional) Separator used to implode the values. Default: ", ". * @return null|string */ - public static function getNonEmptyValuesAsString(array $values, $separator = ', ') + public static function getNonEmptyValuesAsString(array $values, string $separator = ', '): ?string { /* * No elements? @@ -1698,6 +1702,28 @@ class Arrays return implode($separator, $nonEmpty); } + /** + * Returns information if given value is an empty array + * + * @param mixed $value The value to verify + * @return bool + */ + public static function isEmptyArray($value): bool + { + return is_array($value) && empty($value); + } + + /** + * Returns information if given value is non-empty array + * + * @param mixed $value The value to verify + * @return bool + */ + public static function isNotEmptyArray($value): bool + { + return is_array($value) && !empty($value); + } + /** * Returns neighbour (next or previous element) for given element * @@ -1706,7 +1732,7 @@ class Arrays * @param bool $next (optional) If is set to true, returns next neighbour. Otherwise - previous. * @return null|mixed */ - private static function getNeighbour(array $array, $element, $next = true) + private static function getNeighbour(array $array, $element, bool $next = true) { /* * No elements? @@ -1730,7 +1756,7 @@ class Arrays * * Nothing to do */ - if ($noPrevious || $noNext || empty($array) || !in_array($element, $array, true)) { + if ($noPrevious || $noNext || !in_array($element, $array, true)) { return null; } diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index 7f45397..4ba0e37 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -1274,7 +1274,7 @@ class Miscellaneous * * @return string */ - public static function getProjectRootPath() + public static function getProjectRootPath(): string { $projectRootPath = ''; @@ -1298,4 +1298,25 @@ class Miscellaneous return $projectRootPath; } + + /** + * Removes marginal character (first or last) from given string + * + * @param string $string The string which should be shortened + * @param bool $last (optional) If is set to true, last element is removed (default behaviour). Otherwise - + * first. + * @return null|string + */ + public static function removeMarginalCharacter(string $string, bool $last = true): ?string + { + if (empty($string)) { + return null; + } + + if ($last) { + return substr($string, 0, -1); + } + + return substr($string, 1); + } } diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index d675b72..82c522a 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -15,6 +15,11 @@ use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException; use Meritoo\Common\Exception\Reflection\MissingChildClassesException; use Meritoo\Common\Exception\Reflection\NotExistingPropertyException; use Meritoo\Common\Exception\Reflection\TooManyChildClassesException; +use ReflectionClass; +use ReflectionException; +use ReflectionMethod; +use ReflectionObject; +use ReflectionProperty; /** * Useful reflection methods @@ -32,18 +37,18 @@ class Reflection * Otherwise - all methods, with inherited methods too. * @return array */ - public static function getMethods($class, $withoutInheritance = false) + public static function getMethods($class, bool $withoutInheritance = false): array { $effect = []; - $reflection = new \ReflectionClass($class); + $reflection = new ReflectionClass($class); $methods = $reflection->getMethods(); if (!empty($methods)) { $className = self::getClassName($class); foreach ($methods as $method) { - if ($method instanceof \ReflectionMethod) { + if ($method instanceof ReflectionMethod) { if ($withoutInheritance && $className !== $method->class) { continue; } @@ -62,9 +67,9 @@ class Reflection * @param object|string $class The object or name of object's class * @return array */ - public static function getConstants($class) + public static function getConstants($class): array { - $reflection = new \ReflectionClass($class); + $reflection = new ReflectionClass($class); return $reflection->getConstants(); } @@ -76,7 +81,7 @@ class Reflection * @param object|string $class The object or name of object's class * @return null|int */ - public static function getMaxNumberConstant($class) + public static function getMaxNumberConstant($class): ?int { $constants = self::getConstants($class); @@ -102,9 +107,9 @@ class Reflection * @param string $method Name of the method to find * @return bool */ - public static function hasMethod($class, $method) + public static function hasMethod($class, string $method): bool { - $reflection = new \ReflectionClass($class); + $reflection = new ReflectionClass($class); return $reflection->hasMethod($method); } @@ -116,9 +121,9 @@ class Reflection * @param string $property Name of the property to find * @return bool */ - public static function hasProperty($class, $property) + public static function hasProperty($class, string $property): bool { - $reflection = new \ReflectionClass($class); + $reflection = new ReflectionClass($class); return $reflection->hasProperty($property); } @@ -130,9 +135,9 @@ class Reflection * @param string $constant Name of the constant to find * @return bool */ - public static function hasConstant($class, $constant) + public static function hasConstant($class, string $constant): bool { - $reflection = new \ReflectionClass($class); + $reflection = new ReflectionClass($class); return $reflection->hasConstant($constant); } @@ -144,9 +149,9 @@ class Reflection * @param string $constant Name of the constant that contains a value * @return mixed */ - public static function getConstantValue($class, $constant) + public static function getConstantValue($class, string $constant) { - $reflection = new \ReflectionClass($class); + $reflection = new ReflectionClass($class); if (self::hasConstant($class, $constant)) { return $reflection->getConstant($constant); @@ -165,7 +170,7 @@ class Reflection * property. Otherwise - not. * @return mixed */ - public static function getPropertyValue($source, $property, $force = false) + public static function getPropertyValue($source, string $property, bool $force = false) { if (Regex::contains($property, '.')) { return self::getPropertyValueByPropertiesChain($source, $property, $force); @@ -209,7 +214,7 @@ class Reflection * object does not have property. Otherwise - not. * @return array */ - public static function getPropertyValues($objects, $property, $force = false) + public static function getPropertyValues($objects, string $property, bool $force = false): array { /* * No objects? @@ -245,7 +250,7 @@ class Reflection * not, full name of class is returned, with namespace. * @return null|string */ - public static function getClassName($source, $withoutNamespace = false) + public static function getClassName($source, bool $withoutNamespace = false): ?string { /* * First argument is not proper source of class? @@ -303,7 +308,7 @@ class Reflection * @param array|object|string $source An array of objects, namespaces, object or namespace * @return string */ - public static function getClassNamespace($source) + public static function getClassNamespace($source): string { $fullClassName = self::getClassName($source); @@ -327,7 +332,7 @@ class Reflection * @param string $interface The interface that should be implemented * @return bool */ - public static function isInterfaceImplemented($source, $interface) + public static function isInterfaceImplemented($source, string $interface): bool { $className = self::getClassName($source); $interfaces = class_implements($className); @@ -342,7 +347,7 @@ class Reflection * @param array|object|string $parentClass The parent class. An array of objects, namespaces, object or namespace. * @return bool */ - public static function isChildOfClass($childClass, $parentClass) + public static function isChildOfClass($childClass, $parentClass): bool { $childClassName = self::getClassName($childClass); $parentClassName = self::getClassName($parentClass); @@ -364,18 +369,18 @@ class Reflection * constants. By default all properties are returned. * @param bool $includeParents (optional) If is set to true, properties of parent classes are * included (recursively). Otherwise - not. - * @return \ReflectionProperty[] + * @return ReflectionProperty[] */ - public static function getProperties($source, $filter = null, $includeParents = false): array + public static function getProperties($source, int $filter = null, bool $includeParents = false): array { $className = self::getClassName($source); - $reflection = new \ReflectionClass($className); + $reflection = new ReflectionClass($className); if (null === $filter) { - $filter = \ReflectionProperty::IS_PRIVATE - + \ReflectionProperty::IS_PROTECTED - + \ReflectionProperty::IS_PUBLIC - + \ReflectionProperty::IS_STATIC; + $filter = ReflectionProperty::IS_PRIVATE + + ReflectionProperty::IS_PROTECTED + + ReflectionProperty::IS_PUBLIC + + ReflectionProperty::IS_STATIC; } $properties = $reflection->getProperties($filter); @@ -397,12 +402,12 @@ class Reflection * Returns a parent class or false if there is no parent class * * @param array|object|string $source An array of objects, namespaces, object or namespace - * @return bool|\ReflectionClass + * @return false|ReflectionClass */ public static function getParentClass($source) { $className = self::getClassName($source); - $reflection = new \ReflectionClass($className); + $reflection = new ReflectionClass($className); return $reflection->getParentClass(); } @@ -416,7 +421,7 @@ class Reflection * @throws CannotResolveClassNameException * @return null|array */ - public static function getChildClasses($class) + public static function getChildClasses($class): ?array { $allClasses = get_declared_classes(); @@ -500,15 +505,15 @@ class Reflection * @param string $property Name of the property * @param int $filter (optional) Filter of properties. Uses \ReflectionProperty class constants. * By default all properties are allowed / processed. - * @return null|\ReflectionProperty + * @return null|ReflectionProperty */ - public static function getProperty($class, $property, $filter = null) + public static function getProperty($class, string $property, int $filter = null): ?ReflectionProperty { $className = self::getClassName($class); $properties = self::getProperties($className, $filter); if (!empty($properties)) { - /** @var \ReflectionProperty $reflectionProperty */ + /** @var ReflectionProperty $reflectionProperty */ foreach ($properties as $reflectionProperty) { if ($reflectionProperty->getName() === $property) { return $reflectionProperty; @@ -529,7 +534,7 @@ class Reflection * @throws CannotResolveClassNameException * @return null|bool */ - public static function usesTrait($class, $trait, $verifyParents = false) + public static function usesTrait($class, $trait, bool $verifyParents = false): ?bool { $className = self::getClassName($class); $traitName = self::getClassName($trait); @@ -544,7 +549,7 @@ class Reflection throw new CannotResolveClassNameException($class, false); } - $reflection = new \ReflectionClass($className); + $reflection = new ReflectionClass($className); $traitsNames = $reflection->getTraitNames(); $uses = in_array($traitName, $traitsNames, true); @@ -567,10 +572,10 @@ class Reflection * @param array|object|string $class An array of objects, namespaces, object or namespace * @return null|string */ - public static function getParentClassName($class) + public static function getParentClassName($class): ?string { $className = self::getClassName($class); - $reflection = new \ReflectionClass($className); + $reflection = new ReflectionClass($className); $parentClass = $reflection->getParentClass(); if (null === $parentClass || false === $parentClass) { @@ -588,7 +593,7 @@ class Reflection * @param mixed $value Value of the property * @throws NotExistingPropertyException */ - public static function setPropertyValue($object, $property, $value) + public static function setPropertyValue($object, string $property, $value): void { $reflectionProperty = self::getProperty($object, $property); @@ -616,7 +621,7 @@ class Reflection * @param mixed $object Object that should contains given property * @param array $propertiesValues Key-value pairs, where key - name of the property, value - value of the property */ - public static function setPropertiesValues($object, array $propertiesValues) + public static function setPropertiesValues($object, array $propertiesValues): void { /* * No properties? @@ -637,7 +642,7 @@ class Reflection * @param string $class Class to verify * @return string */ - private static function getRealClass($class): string + private static function getRealClass(string $class): string { if (false === $pos = strrpos($class, '\\' . Proxy::MARKER . '\\')) { return $class; @@ -650,15 +655,15 @@ class Reflection * Returns value of given property using the property represented by reflection. * If value cannot be fetched, makes the property accessible temporarily. * - * @param mixed $object Object that should contains given property - * @param string $property Name of the property that contains a value - * @param null|\ReflectionProperty $reflectionProperty (optional) Property represented by reflection + * @param mixed $object Object that should contains given property + * @param string $property Name of the property that contains a value + * @param null|ReflectionProperty $reflectionProperty (optional) Property represented by reflection * @return mixed */ private static function getPropertyValueByReflectionProperty( $object, string $property, - ?\ReflectionProperty $reflectionProperty = null + ?ReflectionProperty $reflectionProperty = null ) { $value = null; $valueFound = false; @@ -666,12 +671,12 @@ class Reflection try { if (null === $reflectionProperty) { - $reflectionProperty = new \ReflectionProperty($className, $property); + $reflectionProperty = new ReflectionProperty($className, $property); } $value = $reflectionProperty->getValue($object); $valueFound = true; - } catch (\ReflectionException $exception) { + } catch (ReflectionException $exception) { } if (null !== $reflectionProperty) { @@ -705,7 +710,7 @@ class Reflection $value = null; $valueFound = false; - $reflectionObject = new \ReflectionObject($source); + $reflectionObject = new ReflectionObject($source); $property = Inflector::classify($property); $gettersPrefixes = [ @@ -718,7 +723,7 @@ class Reflection $getter = sprintf('%s%s', $prefix, $property); if ($reflectionObject->hasMethod($getter)) { - $method = new \ReflectionMethod($source, $getter); + $method = new ReflectionMethod($source, $getter); /* * Getter is not accessible publicly? @@ -791,7 +796,7 @@ class Reflection * property. Otherwise - not. * @return mixed */ - private static function getPropertyValueByPropertiesChain($source, $property, $force) + private static function getPropertyValueByPropertiesChain($source, string $property, bool $force) { $exploded = explode('.', $property); diff --git a/tests/Collection/CollectionTest.php b/tests/Collection/CollectionTest.php index b2d90b2..1b0bef1 100644 --- a/tests/Collection/CollectionTest.php +++ b/tests/Collection/CollectionTest.php @@ -13,6 +13,7 @@ use Generator; use Meritoo\Common\Collection\Collection; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; +use ReflectionClass; /** * Test case of the collection of elements @@ -21,7 +22,7 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Collection\Collection + * @covers \Meritoo\Common\Collection\Collection */ class CollectionTest extends BaseTestCase { @@ -327,7 +328,16 @@ class CollectionTest extends BaseTestCase public function testExistsVisibilityAndArguments() { - static::assertMethodVisibilityAndArguments(Collection::class, 'exists', OopVisibilityType::IS_PRIVATE, 1, 1); + $reflectionClass = new ReflectionClass(Collection::class); + $method = $reflectionClass->getMethod('exists'); + + static::assertMethodVisibilityAndArguments( + Collection::class, + $method, + OopVisibilityType::IS_PRIVATE, + 1, + 1 + ); } /** diff --git a/tests/Exception/Bundle/IncorrectBundleNameExceptionTest.php b/tests/Exception/Bundle/IncorrectBundleNameExceptionTest.php index 69c40ab..a48dac5 100644 --- a/tests/Exception/Bundle/IncorrectBundleNameExceptionTest.php +++ b/tests/Exception/Bundle/IncorrectBundleNameExceptionTest.php @@ -8,6 +8,7 @@ namespace Meritoo\Test\Common\Exception\Bundle; +use Generator; use Meritoo\Common\Exception\Bundle\IncorrectBundleNameException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; @@ -23,7 +24,7 @@ use Meritoo\Common\Type\OopVisibilityType; */ class IncorrectBundleNameExceptionTest extends BaseTestCase { - public function testConstructor() + public function testConstructor(): void { static::assertConstructorVisibilityAndArguments( IncorrectBundleNameException::class, @@ -39,13 +40,13 @@ class IncorrectBundleNameExceptionTest extends BaseTestCase * * @dataProvider provideBundleNameAndMessage */ - public function testCreate($description, $bundleName, $expectedMessage) + public function testCreate(string $description, string $bundleName, string $expectedMessage): void { $exception = IncorrectBundleNameException::create($bundleName); static::assertSame($expectedMessage, $exception->getMessage(), $description); } - public function provideBundleNameAndMessage() + public function provideBundleNameAndMessage(): Generator { $template = 'Name of bundle \'%s\' is incorrect. It should start with big letter and end with "Bundle". Is' . ' there everything ok?'; @@ -56,12 +57,6 @@ class IncorrectBundleNameExceptionTest extends BaseTestCase sprintf($template, ''), ]; - yield[ - 'Null as name of bundle', - null, - sprintf($template, ''), - ]; - yield[ 'String with spaces as name of bundle', 'This is test', diff --git a/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php b/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php index 5d4c8d6..8106936 100644 --- a/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php +++ b/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php @@ -12,6 +12,7 @@ use Generator; use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; +use stdClass; /** * Test case of an exception used while name of class or trait cannot be resolved @@ -20,13 +21,17 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\Reflection\CannotResolveClassNameException + * @covers \Meritoo\Common\Exception\Reflection\CannotResolveClassNameException */ class CannotResolveClassNameExceptionTest extends BaseTestCase { - public function testConstructorVisibilityAndArguments() + public function testConstructorVisibilityAndArguments(): void { - static::assertConstructorVisibilityAndArguments(CannotResolveClassNameException::class, OopVisibilityType::IS_PUBLIC, 3); + static::assertConstructorVisibilityAndArguments( + CannotResolveClassNameException::class, + OopVisibilityType::IS_PUBLIC, + 3 + ); } /** @@ -38,7 +43,7 @@ class CannotResolveClassNameExceptionTest extends BaseTestCase * * @dataProvider provideClassName */ - public function testConstructorMessage($source, $forClass, $expectedMessage) + public function testCreate($source, bool $forClass, string $expectedMessage): void { $exception = CannotResolveClassNameException::create($source, $forClass); static::assertSame($expectedMessage, $exception->getMessage()); @@ -50,7 +55,7 @@ class CannotResolveClassNameExceptionTest extends BaseTestCase * * @return Generator */ - public function provideClassName() + public function provideClassName(): Generator { yield[ 'Not\Existing\Class', @@ -66,8 +71,8 @@ class CannotResolveClassNameExceptionTest extends BaseTestCase yield[ [ - new \stdClass(), - new \stdClass(), + new stdClass(), + new stdClass(), ], true, 'Name of class from given \'array\' cannot be resolved. Is there everything ok?', diff --git a/tests/Exception/Reflection/ClassWithoutConstructorExceptionTest.php b/tests/Exception/Reflection/ClassWithoutConstructorExceptionTest.php new file mode 100644 index 0000000..85c6fec --- /dev/null +++ b/tests/Exception/Reflection/ClassWithoutConstructorExceptionTest.php @@ -0,0 +1,66 @@ + + * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Exception\Reflection\ClassWithoutConstructorException + */ +class ClassWithoutConstructorExceptionTest extends BaseTestCase +{ + public function testConstructor(): void + { + static::assertConstructorVisibilityAndArguments( + ClassWithoutConstructorException::class, + OopVisibilityType::IS_PUBLIC, + 3 + ); + } + + /** + * @param string $description Description of test case + * @param string $className Fully-qualified name of class that hasn't constructor + * @param string $expectedMessage Expected exception's message + * + * @dataProvider provideClassName + */ + public function testCreate(string $description, string $className, string $expectedMessage): void + { + $exception = ClassWithoutConstructorException::create($className); + static::assertSame($expectedMessage, $exception->getMessage(), $description); + } + + public function provideClassName(): Generator + { + $template = 'Oops, class \'%s\' hasn\'t constructor. Did you use proper class?'; + + yield[ + 'An empty name of class', + '', + sprintf($template, ''), + ]; + + yield[ + 'The Arrays class', + Arrays::class, + sprintf($template, Arrays::class), + ]; + } +} diff --git a/tests/Exception/Reflection/MissingChildClassesExceptionTest.php b/tests/Exception/Reflection/MissingChildClassesExceptionTest.php index 7da3484..d3aaf2e 100644 --- a/tests/Exception/Reflection/MissingChildClassesExceptionTest.php +++ b/tests/Exception/Reflection/MissingChildClassesExceptionTest.php @@ -20,13 +20,17 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\Reflection\MissingChildClassesException + * @covers \Meritoo\Common\Exception\Reflection\MissingChildClassesException */ class MissingChildClassesExceptionTest extends BaseTestCase { - public function testConstructorVisibilityAndArguments() + public function testConstructorVisibilityAndArguments(): void { - static::assertConstructorVisibilityAndArguments(MissingChildClassesException::class, OopVisibilityType::IS_PUBLIC, 3); + static::assertConstructorVisibilityAndArguments( + MissingChildClassesException::class, + OopVisibilityType::IS_PUBLIC, + 3 + ); } /** @@ -36,7 +40,7 @@ class MissingChildClassesExceptionTest extends BaseTestCase * * @dataProvider provideParentClass */ - public function testConstructorMessage($parentClass, $expectedMessage) + public function testCreate($parentClass, string $expectedMessage): void { $exception = MissingChildClassesException::create($parentClass); static::assertSame($expectedMessage, $exception->getMessage()); @@ -47,7 +51,7 @@ class MissingChildClassesExceptionTest extends BaseTestCase * * @return Generator */ - public function provideParentClass() + public function provideParentClass(): ?Generator { $template = 'The \'%s\' class requires one child class at least who will extend her (maybe is an abstract' . ' class), but the child classes are missing. Did you forget to extend this class?'; diff --git a/tests/Exception/Reflection/NotExistingPropertyExceptionTest.php b/tests/Exception/Reflection/NotExistingPropertyExceptionTest.php index aadd974..605aa36 100644 --- a/tests/Exception/Reflection/NotExistingPropertyExceptionTest.php +++ b/tests/Exception/Reflection/NotExistingPropertyExceptionTest.php @@ -19,11 +19,11 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\Reflection\NotExistingPropertyException + * @covers \Meritoo\Common\Exception\Reflection\NotExistingPropertyException */ class NotExistingPropertyExceptionTest extends BaseTestCase { - public function testConstructor() + public function testConstructor(): void { static::assertConstructorVisibilityAndArguments( NotExistingPropertyException::class, @@ -33,20 +33,20 @@ class NotExistingPropertyExceptionTest extends BaseTestCase } /** - * @param string $description Description of test - * @param mixed $object Object that should contains given property - * @param string $property Name of the property - * @param string $expectedMessage Expected exception's message + * @param string $description Description of test + * @param mixed $object Object that should contains given property + * @param null|string $property Name of the property + * @param string $expectedMessage Expected exception's message * * @dataProvider provideObjectPropertyAndMessage */ - public function testCreate($description, $object, $property, $expectedMessage) + public function testCreate(string $description, $object, ?string $property, string $expectedMessage): void { $exception = NotExistingPropertyException::create($object, $property); static::assertSame($expectedMessage, $exception->getMessage(), $description); } - public function provideObjectPropertyAndMessage() + public function provideObjectPropertyAndMessage(): ?\Generator { $template = 'Property \'%s\' does not exist in instance of class \'%s\'. Did you use proper name of property?'; diff --git a/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php b/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php index 9bb26b0..b0d8dc6 100644 --- a/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php +++ b/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php @@ -20,13 +20,17 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\Reflection\TooManyChildClassesException + * @covers \Meritoo\Common\Exception\Reflection\TooManyChildClassesException */ class TooManyChildClassesExceptionTest extends BaseTestCase { - public function testConstructorVisibilityAndArguments() + public function testConstructor(): void { - static::assertConstructorVisibilityAndArguments(TooManyChildClassesException::class, OopVisibilityType::IS_PUBLIC, 3); + static::assertConstructorVisibilityAndArguments( + TooManyChildClassesException::class, + OopVisibilityType::IS_PUBLIC, + 3 + ); } /** @@ -37,7 +41,7 @@ class TooManyChildClassesExceptionTest extends BaseTestCase * * @dataProvider provideParentAndChildClasses */ - public function testConstructorMessage($parentClass, array $childClasses, $expectedMessage) + public function testCreate($parentClass, array $childClasses, string $expectedMessage): void { $exception = TooManyChildClassesException::create($parentClass, $childClasses); static::assertSame($expectedMessage, $exception->getMessage()); @@ -49,7 +53,7 @@ class TooManyChildClassesExceptionTest extends BaseTestCase * * @return Generator */ - public function provideParentAndChildClasses() + public function provideParentAndChildClasses(): ?Generator { $template = "The '%s' class requires one child class at most who will extend her, but more than one child" . " class was found:\n- %s\n\nWhy did you create more than one classes that extend '%s' class?"; diff --git a/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php b/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php index f5440ad..a4f836d 100644 --- a/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php +++ b/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php @@ -21,13 +21,17 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\Type\UnknownOopVisibilityTypeException + * @covers \Meritoo\Common\Exception\Type\UnknownOopVisibilityTypeException */ class UnknownOopVisibilityTypeExceptionTest extends BaseTestCase { - public function testConstructorVisibilityAndArguments() + public function testConstructorVisibilityAndArguments(): void { - static::assertConstructorVisibilityAndArguments(UnknownOopVisibilityTypeException::class, OopVisibilityType::IS_PUBLIC, 3); + static::assertConstructorVisibilityAndArguments( + UnknownOopVisibilityTypeException::class, + OopVisibilityType::IS_PUBLIC, + 3 + ); } /** @@ -36,7 +40,7 @@ class UnknownOopVisibilityTypeExceptionTest extends BaseTestCase * * @dataProvider provideUnknownType */ - public function testConstructorMessage($unknownType, $expectedMessage) + public function testConstructorMessage($unknownType, $expectedMessage): void { $exception = UnknownOopVisibilityTypeException::createException($unknownType); static::assertSame($expectedMessage, $exception->getMessage()); @@ -47,7 +51,7 @@ class UnknownOopVisibilityTypeExceptionTest extends BaseTestCase * * @return Generator */ - public function provideUnknownType() + public function provideUnknownType(): Generator { $allTypes = (new OopVisibilityType())->getAll(); diff --git a/tests/Type/DatePartTypeTest.php b/tests/Type/DatePartTypeTest.php index 73e5d2f..4e9b312 100644 --- a/tests/Type/DatePartTypeTest.php +++ b/tests/Type/DatePartTypeTest.php @@ -8,7 +8,9 @@ namespace Meritoo\Test\Common\Type; +use Generator; use Meritoo\Common\Test\Base\BaseTypeTestCase; +use Meritoo\Common\Type\Base\BaseType; use Meritoo\Common\Type\DatePartType; /** @@ -25,7 +27,7 @@ class DatePartTypeTest extends BaseTypeTestCase /** * {@inheritdoc} */ - public function provideTypeToVerify() + public function provideTypeToVerify(): Generator { yield[ '', @@ -38,12 +40,12 @@ class DatePartTypeTest extends BaseTypeTestCase ]; yield[ - 0, + '0', false, ]; yield[ - 1, + '1', false, ]; @@ -81,22 +83,22 @@ class DatePartTypeTest extends BaseTypeTestCase /** * {@inheritdoc} */ - protected function getAllExpectedTypes() + protected function getAllExpectedTypes(): array { return [ - 'DAY' => DatePartType::DAY, - 'HOUR' => DatePartType::HOUR, - 'MINUTE' => DatePartType::MINUTE, - 'MONTH' => DatePartType::MONTH, - 'SECOND' => DatePartType::SECOND, - 'YEAR' => DatePartType::YEAR, + 'DAY' => 'day', + 'HOUR' => 'hour', + 'MINUTE' => 'minute', + 'MONTH' => 'month', + 'SECOND' => 'second', + 'YEAR' => 'year', ]; } /** * {@inheritdoc} */ - protected function getTestedTypeInstance() + protected function getTestedTypeInstance(): BaseType { return new DatePartType(); } diff --git a/tests/Type/DatePeriodTest.php b/tests/Type/DatePeriodTest.php index fdfed51..bb57851 100644 --- a/tests/Type/DatePeriodTest.php +++ b/tests/Type/DatePeriodTest.php @@ -11,6 +11,7 @@ namespace Meritoo\Test\Common\Type; use DateTime; use Generator; use Meritoo\Common\Test\Base\BaseTypeTestCase; +use Meritoo\Common\Type\Base\BaseType; use Meritoo\Common\Type\DatePeriod; use Meritoo\Common\Type\OopVisibilityType; @@ -21,13 +22,17 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Type\DatePeriod + * @covers \Meritoo\Common\Type\DatePeriod */ class DatePeriodTest extends BaseTypeTestCase { - public function testConstructorVisibilityAndArguments() + public function testConstructorVisibilityAndArguments(): void { - static::assertConstructorVisibilityAndArguments(DatePeriod::class, OopVisibilityType::IS_PUBLIC, 2, 0); + static::assertConstructorVisibilityAndArguments( + DatePeriod::class, + OopVisibilityType::IS_PUBLIC, + 2 + ); } /** @@ -36,7 +41,7 @@ class DatePeriodTest extends BaseTypeTestCase * * @dataProvider provideDatePeriod */ - public function testConstruct(DateTime $startDate = null, DateTime $endDate = null) + public function testConstruct(DateTime $startDate = null, DateTime $endDate = null): void { $period = new DatePeriod($startDate, $endDate); @@ -50,7 +55,7 @@ class DatePeriodTest extends BaseTypeTestCase * * @dataProvider provideDatePeriod */ - public function testGettersAndSetters(DateTime $startDate = null, DateTime $endDate = null) + public function testGettersAndSetters(DateTime $startDate = null, DateTime $endDate = null): void { $period = new DatePeriod(); @@ -67,7 +72,7 @@ class DatePeriodTest extends BaseTypeTestCase * * @dataProvider provideDatePeriodAndIncorrectDateFormat */ - public function testGetFormattedDateIncorrectDateFormat(DatePeriod $period, $format) + public function testGetFormattedDateIncorrectDateFormat(DatePeriod $period, $format): void { self::assertEquals('', $period->getFormattedDate($format)); } @@ -80,7 +85,7 @@ class DatePeriodTest extends BaseTypeTestCase * * @dataProvider provideDatePeriodAndDateFormat */ - public function testGetFormattedDate(DatePeriod $period, $format, $startDate, $expected) + public function testGetFormattedDate(DatePeriod $period, $format, $startDate, $expected): void { self::assertEquals($expected, $period->getFormattedDate($format, $startDate)); } @@ -90,7 +95,7 @@ class DatePeriodTest extends BaseTypeTestCase * * @return Generator */ - public function provideDatePeriod() + public function provideDatePeriod(): Generator { $startDate = new DateTime('2001-01-01'); $endDate = new DateTime('2002-02-02'); @@ -123,7 +128,7 @@ class DatePeriodTest extends BaseTypeTestCase * * @return Generator */ - public function provideDatePeriodAndIncorrectDateFormat() + public function provideDatePeriodAndIncorrectDateFormat(): Generator { $startDate = new DateTime('2001-01-01'); $endDate = new DateTime('2002-02-02'); @@ -133,11 +138,6 @@ class DatePeriodTest extends BaseTypeTestCase '', ]; - yield[ - new DatePeriod($startDate, $endDate), - null, - ]; - yield[ new DatePeriod($startDate, $endDate), false, @@ -149,7 +149,7 @@ class DatePeriodTest extends BaseTypeTestCase * * @return Generator */ - public function provideDatePeriodAndDateFormat() + public function provideDatePeriodAndDateFormat(): Generator { $startDate = new DateTime('2001-01-01'); $endDate = new DateTime('2002-02-02'); @@ -216,7 +216,7 @@ class DatePeriodTest extends BaseTypeTestCase /** * {@inheritdoc} */ - public function provideTypeToVerify() + public function provideTypeToVerify(): Generator { yield[ '', @@ -224,27 +224,22 @@ class DatePeriodTest extends BaseTypeTestCase ]; yield[ - -1, + '-1', false, ]; yield[ - true, - false, - ]; - - yield[ - DatePeriod::LAST_MONTH, + '4', true, ]; yield[ - DatePeriod::NEXT_WEEK, + '3', true, ]; yield[ - DatePeriod::THIS_YEAR, + '8', true, ]; } @@ -254,25 +249,25 @@ class DatePeriodTest extends BaseTypeTestCase * * @return array */ - protected function getAllExpectedTypes() + protected function getAllExpectedTypes(): array { return [ - 'LAST_MONTH' => DatePeriod::LAST_MONTH, - 'LAST_WEEK' => DatePeriod::LAST_WEEK, - 'LAST_YEAR' => DatePeriod::LAST_YEAR, - 'NEXT_MONTH' => DatePeriod::NEXT_MONTH, - 'NEXT_WEEK' => DatePeriod::NEXT_WEEK, - 'NEXT_YEAR' => DatePeriod::NEXT_YEAR, - 'THIS_MONTH' => DatePeriod::THIS_MONTH, - 'THIS_WEEK' => DatePeriod::THIS_WEEK, - 'THIS_YEAR' => DatePeriod::THIS_YEAR, + 'LAST_MONTH' => 4, + 'LAST_WEEK' => 1, + 'LAST_YEAR' => 7, + 'NEXT_MONTH' => 6, + 'NEXT_WEEK' => 3, + 'NEXT_YEAR' => 9, + 'THIS_MONTH' => 5, + 'THIS_WEEK' => 2, + 'THIS_YEAR' => 8, ]; } /** * {@inheritdoc} */ - protected function getTestedTypeInstance() + protected function getTestedTypeInstance(): BaseType { return new DatePeriod(); } diff --git a/tests/Type/OopVisibilityTypeTest.php b/tests/Type/OopVisibilityTypeTest.php index 9f5ee5f..34fabc1 100644 --- a/tests/Type/OopVisibilityTypeTest.php +++ b/tests/Type/OopVisibilityTypeTest.php @@ -8,6 +8,7 @@ namespace Meritoo\Test\Common\Type; +use Generator; use Meritoo\Common\Test\Base\BaseTypeTestCase; use Meritoo\Common\Type\Base\BaseType; use Meritoo\Common\Type\OopVisibilityType; @@ -26,7 +27,7 @@ class OopVisibilityTypeTest extends BaseTypeTestCase /** * {@inheritdoc} */ - public function provideTypeToVerify(): ?\Generator + public function provideTypeToVerify(): Generator { yield[ '', @@ -39,27 +40,22 @@ class OopVisibilityTypeTest extends BaseTypeTestCase ]; yield[ - -1, + '-1', false, ]; yield[ - true, - false, - ]; - - yield[ - 1, + '1', true, ]; yield[ - 2, + '2', true, ]; yield[ - 3, + '3', true, ]; } diff --git a/tests/Utilities/ArraysTest.php b/tests/Utilities/ArraysTest.php index c553f73..81a1dbe 100644 --- a/tests/Utilities/ArraysTest.php +++ b/tests/Utilities/ArraysTest.php @@ -8,6 +8,7 @@ namespace Meritoo\Test\Common\Utilities; +use Generator; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Utilities\Arrays; use Meritoo\Common\Utilities\Locale; @@ -20,7 +21,7 @@ use Meritoo\Test\Common\Utilities\Arrays\SimpleToString; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Utilities\Arrays + * @covers \Meritoo\Common\Utilities\Arrays */ class ArraysTest extends BaseTestCase { @@ -212,7 +213,7 @@ class ArraysTest extends BaseTestCase self::assertEquals('amet/1/primis', Arrays::getLastElementBreadCrumb($this->complexArray)); } - public function testGetLastRow() + public function testGetLastRow(): void { // Negative cases self::assertNull(Arrays::getLastRow([])); @@ -234,34 +235,32 @@ class ArraysTest extends BaseTestCase ], Arrays::getLastRow($this->complexArray)); } - public function testReplaceArrayKeys() - { - $effect = [ - 'nullam' => 'donec', - 'x' => [ - 'vitae' => [ - 'x' => 'quis', - ], - ], - 'elit', - ]; - - $dataArray = $this->complexArray['sit']; - self::assertEquals($effect, Arrays::replaceArrayKeys($dataArray, '|.*li.*|', 'x')); - - self::assertEquals([ - 'x' => 'sit', - 4 => 'amet', - ], Arrays::replaceArrayKeys($this->simpleArray, '|[0-3]+|', 'x')); + /** + * @param string $description Description of test case + * @param array $array Array which keys should be replaced + * @param string $oldKeyPattern Regular expression of the old key + * @param string $newKey Name of the new key + * @param array $expected Expected result + * + * @dataProvider provideArrayToReplaceKeys + */ + public function testReplaceKeys( + string $description, + array $array, + string $oldKeyPattern, + string $newKey, + ?array $expected + ): void { + self::assertSame($expected, Arrays::replaceKeys($array, $oldKeyPattern, $newKey), $description); } - public function testMakeArray() + public function testMakeArray(): void { self::assertSame($this->simpleArray, Arrays::makeArray($this->simpleArray)); self::assertSame(['test'], Arrays::makeArray('test')); } - public function testArray2JavaScript() + public function testArray2JavaScript(): void { // Negative cases self::assertNull(Arrays::array2JavaScript([])); @@ -339,36 +338,25 @@ letsTest[2] = value_2;'; * * @dataProvider provideArrayToQuoteStrings */ - public function testQuoteStrings($description, $expected, array $array) + public function testQuoteStrings(string $description, ?array $expected, array $array): void { self::assertSame($expected, Arrays::quoteStrings($array), $description); } - public function testRemoveMarginalElement() + /** + * @param string $description Description of test case + * @param array $array The array which should be shortened + * @param bool $last If is set to true, last element is removed (default behaviour). Otherwise - first. + * @param null|array $expected Expected result + * + * @dataProvider provideArrayToRemoveMarginalElement + */ + public function testRemoveMarginalElement(string $description, array $array, bool $last, ?array $expected): void { - $array = $this->simpleArray; - $string = 'Lorem ipsum'; - - // Removing first element - self::assertSame([ - 0 => 'Lorem', - 1 => 'ipsum', - 2 => 'dolor', - 3 => 'sit', - ], Arrays::removeMarginalElement($array)); - self::assertEquals('Lorem ipsu', Arrays::removeMarginalElement($string)); - - // Removing last element - self::assertSame([ - 1 => 'ipsum', - 2 => 'dolor', - 3 => 'sit', - 4 => 'amet', - ], Arrays::removeMarginalElement($array, false)); - self::assertEquals('orem ipsum', Arrays::removeMarginalElement($string, false)); + self::assertSame($expected, Arrays::removeMarginalElement($array, $last), $description); } - public function testRemoveElements() + public function testRemoveElements(): void { $array1 = $this->simpleArray; $array2 = $this->simpleArray; @@ -467,7 +455,7 @@ letsTest[2] = value_2;'; self::assertEquals($replaced, Arrays::setKeysAsValues($array, false)); } - public function testGetNonArrayElementsCount() + public function testGetNonArrayElementsCount(): void { // Negative cases self::assertNull(Arrays::getNonArrayElementsCount([])); @@ -478,11 +466,10 @@ letsTest[2] = value_2;'; self::assertEquals(12, Arrays::getNonArrayElementsCount($this->twoDimensionsArray)); } - public function testString2array() + public function testString2array(): void { // Negative cases self::assertNull(Arrays::string2array('')); - self::assertNull(Arrays::string2array(null)); // Positive cases $array = [ @@ -504,7 +491,7 @@ letsTest[2] = value_2;'; self::assertEquals($array, Arrays::string2array('red : #f00 | green : #0f0 | blue : #00f')); } - public function testAreKeysInArray() + public function testAreKeysInArray(): void { // Negative cases self::assertFalse(Arrays::areKeysInArray([], [])); @@ -568,12 +555,12 @@ letsTest[2] = value_2;'; self::assertTrue(Arrays::areKeysInArray($keys17, $this->complexArray, false)); } - public function testGetLastElementsPathsUsingEmptyArray() + public function testGetLastElementsPathsUsingEmptyArray(): void { self::assertNull(Arrays::getLastElementsPaths([])); } - public function testGetLastElementsPathsUsingDefaults() + public function testGetLastElementsPathsUsingDefaults(): void { // Using default separator and other default arguments $expected = [ @@ -592,7 +579,7 @@ letsTest[2] = value_2;'; self::assertEquals($expected, Arrays::getLastElementsPaths($this->complexArray)); } - public function testGetLastElementsPathsUsingCustomSeparator() + public function testGetLastElementsPathsUsingCustomSeparator(): void { // Using custom separator $separator = ' -> '; @@ -613,20 +600,24 @@ letsTest[2] = value_2;'; } /** - * @param array|string $stopIfMatchedBy Patterns of keys or paths that matched will stop the process of path - * building and including children of those keys or paths (recursive will - * not be used for keys in lower level of given array) - * @param string $separator Separator used in resultant strings. Default: ".". - * @param array $expected Expected array + * @param array $stopIfMatchedBy Patterns of keys or paths that matched will stop the process of path building and + * including children of those keys or paths (recursive will not be used for keys in + * lower level of given array) + * @param string $separator Separator used in resultant strings. Default: ".". + * @param array $expected Expected array * * @dataProvider provideStopIfMatchedByForGetLastElementsPaths */ - public function testGetLastElementsPathsUsingStopIfMatchedBy($stopIfMatchedBy, $separator, array $expected) - { - self::assertEquals($expected, Arrays::getLastElementsPaths($this->superComplexArray, $separator, '', $stopIfMatchedBy)); + public function testGetLastElementsPathsUsingStopIfMatchedBy( + array $stopIfMatchedBy, + string $separator, + array $expected + ): void { + $paths = Arrays::getLastElementsPaths($this->superComplexArray, $separator, '', $stopIfMatchedBy); + self::assertEquals($expected, $paths); } - public function testAreAllKeysMatchedByPattern() + public function testAreAllKeysMatchedByPattern(): void { $pattern = '\d+'; @@ -1471,6 +1462,30 @@ letsTest[2] = value_2;'; self::assertSame($expected, Arrays::getNonEmptyValuesAsString($values, $separator), $description); } + /** + * @param string $description Description of test case + * @param mixed $value The value to verify + * @param bool $expected Expected information + * + * @dataProvider provideValueToIsEmptyArray + */ + public function testIsEmptyArray(string $description, $value, bool $expected): void + { + self::assertSame($expected, Arrays::isEmptyArray($value), $description); + } + + /** + * @param string $description Description of test case + * @param mixed $value The value to verify + * @param bool $expected Expected information + * + * @dataProvider provideValueToIsNotEmptyArray + */ + public function testIsNotEmptyArray(string $description, $value, bool $expected): void + { + self::assertSame($expected, Arrays::isNotEmptyArray($value), $description); + } + /** * Provides simple array to set/replace values with keys * @@ -1573,13 +1588,13 @@ letsTest[2] = value_2;'; * Provides patterns of keys or paths that matched will stop the process and the expected array for the * getLastElementsPaths() method * - * @return \Generator + * @return Generator */ - public function provideStopIfMatchedByForGetLastElementsPaths() + public function provideStopIfMatchedByForGetLastElementsPaths(): ?Generator { // Special exception: do not use, stop recursive on the "diam" key yield[ - 'diam', + ['diam'], '.', [ 'ipsum.quis.vestibulum.porta-1.0' => 'turpis', @@ -1787,9 +1802,9 @@ letsTest[2] = value_2;'; /** * Provide values to filter and get non-empty values * - * @return \Generator + * @return Generator */ - public function provideValuesToFilterNonEmpty() + public function provideValuesToFilterNonEmpty(): ?Generator { $simpleObject = new SimpleToString('1234'); @@ -2554,6 +2569,307 @@ letsTest[2] = value_2;'; ]; } + public function provideValueToIsEmptyArray(): ?\Generator + { + yield[ + 'An empty string', + '', + false, + ]; + + yield[ + 'Non-empty string', + 'test', + false, + ]; + + yield[ + 'Null', + null, + false, + ]; + + yield[ + 'An integer equals 0', + 1234, + false, + ]; + + yield[ + 'An integer greater than 0', + 1234, + false, + ]; + + yield[ + 'An empty array', + [], + true, + ]; + + yield[ + 'Non-empty array', + [ + 'test', + ], + false, + ]; + } + + public function provideValueToIsNotEmptyArray(): ?\Generator + { + yield[ + 'An empty string', + '', + false, + ]; + + yield[ + 'Non-empty string', + 'test', + false, + ]; + + yield[ + 'Null', + null, + false, + ]; + + yield[ + 'An integer equals 0', + 1234, + false, + ]; + + yield[ + 'An integer greater than 0', + 1234, + false, + ]; + + yield[ + 'An empty array', + [], + false, + ]; + + yield[ + 'Non-empty array', + [ + 'test', + ], + true, + ]; + } + + public function provideArrayToRemoveMarginalElement(): Generator + { + yield[ + 'An empty array - remove last element', + [], + true, + null, + ]; + + yield[ + 'An empty array - remove first element', + [], + false, + null, + ]; + + yield[ + 'One-dimensional array - remove last element', + [ + 'Lorem', + 'ipsum', + 'dolor', + 'sit', + 'amet', + ], + true, + [ + 0 => 'Lorem', + 1 => 'ipsum', + 2 => 'dolor', + 3 => 'sit', + ], + ]; + + yield[ + 'One-dimensional array - remove first element', + [ + 'Lorem', + 'ipsum', + 'dolor', + 'sit', + 'amet', + ], + false, + [ + 1 => 'ipsum', + 2 => 'dolor', + 3 => 'sit', + 4 => 'amet', + ], + ]; + + yield[ + 'Multi-dimensional array - remove last element', + [ + 'lorem' => [ + 'ipsum' => [ + 'dolor' => 'sit', + 'diam' => [ + 'non' => 'egestas', + ], + ], + ], + 'consectetur' => 'adipiscing', + 'mollis' => 1234, + 2 => [], + 'sit' => [ + 'nullam' => 'donec', + 'aliquet' => [ + 'vitae' => [ + 'ligula' => 'quis', + ], + ], + 'elit', + ], + 'amet' => [ + 'iaculis', + 'primis', + ], + ], + true, + [ + 'lorem' => [ + 'ipsum' => [ + 'dolor' => 'sit', + 'diam' => [ + 'non' => 'egestas', + ], + ], + ], + 'consectetur' => 'adipiscing', + 'mollis' => 1234, + 2 => [], + 'sit' => [ + 'nullam' => 'donec', + 'aliquet' => [ + 'vitae' => [ + 'ligula' => 'quis', + ], + ], + 'elit', + ], + ], + ]; + + yield[ + 'Multi-dimensional array - remove first element', + [ + 'lorem' => [ + 'ipsum' => [ + 'dolor' => 'sit', + 'diam' => [ + 'non' => 'egestas', + ], + ], + ], + 'consectetur' => 'adipiscing', + 'mollis' => 1234, + 2 => [], + 'sit' => [ + 'nullam' => 'donec', + 'aliquet' => [ + 'vitae' => [ + 'ligula' => 'quis', + ], + ], + 'elit', + ], + 'amet' => [ + 'iaculis', + 'primis', + ], + ], + false, + [ + 'consectetur' => 'adipiscing', + 'mollis' => 1234, + 2 => [], + 'sit' => [ + 'nullam' => 'donec', + 'aliquet' => [ + 'vitae' => [ + 'ligula' => 'quis', + ], + ], + 'elit', + ], + 'amet' => [ + 'iaculis', + 'primis', + ], + ], + ]; + } + + public function provideArrayToReplaceKeys(): Generator + { + yield[ + 'An empty array', + [], + '', + '', + null, + ]; + + yield[ + '1st case', + [ + 'nullam' => 'donec', + 'aliquet' => [ + 'vitae' => [ + 'ligula' => 'quis', + ], + ], + 'elit', + ], + '|.*li.*|', + 'x', + [ + 'nullam' => 'donec', + 'x' => [ + 'vitae' => [ + 'x' => 'quis', + ], + ], + 'elit', + ], + ]; + + yield[ + '2nd case', + [ + 'Lorem', + 'ipsum', + 'dolor', + 'sit', + 'amet', + ], + '|[0-3]+|', + 'x', + [ + 'x' => 'sit', + 4 => 'amet', + ], + ]; + } + /** * {@inheritdoc} */ diff --git a/tests/Utilities/DateTest.php b/tests/Utilities/DateTest.php index 419b837..15ae92b 100644 --- a/tests/Utilities/DateTest.php +++ b/tests/Utilities/DateTest.php @@ -28,7 +28,7 @@ use Meritoo\Common\Utilities\Locale; */ class DateTest extends BaseTestCase { - public function testConstructor() + public function testConstructor(): void { static::assertHasNoConstructor(Date::class); } @@ -37,7 +37,7 @@ class DateTest extends BaseTestCase * @param mixed $value Empty value, e.g. "" * @dataProvider provideEmptyValue */ - public function testGetDateTimeEmptyValue($value) + public function testGetDateTimeEmptyValue($value): void { self::assertFalse(Date::getDateTime($value)); } @@ -46,7 +46,7 @@ class DateTest extends BaseTestCase * @param mixed $value Incorrect source of DateTime * @dataProvider provideIncorrectDateTimeValue */ - public function testGetDateTimeIncorrectValue($value) + public function testGetDateTimeIncorrectValue($value): void { self::assertFalse(Date::getDateTime($value)); } @@ -55,7 +55,7 @@ class DateTest extends BaseTestCase * @param bool $value The value which maybe is a date * @dataProvider provideBooleanValue */ - public function testGetDateTimeBoolean($value) + public function testGetDateTimeBoolean($value): void { self::assertFalse(Date::getDateTime($value)); } @@ -64,7 +64,7 @@ class DateTest extends BaseTestCase * @param string $relativeFormat Relative / compound format of DateTime * @dataProvider provideDateTimeRelativeFormat */ - public function testGetDateTimeRelativeFormats($relativeFormat) + public function testGetDateTimeRelativeFormats($relativeFormat): void { /* * Values based on relative / compound formats, but... without explicitly declaring them as compound @@ -85,12 +85,12 @@ class DateTest extends BaseTestCase * @param DateTime $dateTime Instance of DateTime class * @dataProvider provideDateTimeInstance */ - public function testGetDateTimeInstanceDateTime(DateTime $dateTime) + public function testGetDateTimeInstanceDateTime(DateTime $dateTime): void { self::assertInstanceOf(DateTime::class, Date::getDateTime($dateTime)); } - public function testGetDateTimeConcreteDates() + public function testGetDateTimeConcreteDates(): void { // Using the standard date format provided by the tested method self::assertInstanceOf(DateTime::class, Date::getDateTime('2015-03-20')); @@ -104,7 +104,7 @@ class DateTest extends BaseTestCase * @param mixed $value Empty value, e.g. "" * @dataProvider provideEmptyValue */ - public function testIsValidDateEmptyDates($value) + public function testIsValidDateEmptyDates($value): void { self::assertFalse(Date::isValidDate($value)); } @@ -113,12 +113,12 @@ class DateTest extends BaseTestCase * @param mixed $value Incorrect source of DateTime * @dataProvider provideIncorrectDateTimeValue */ - public function testIsValidDateIncorrectDates($value) + public function testIsValidDateIncorrectDates($value): void { self::assertFalse(Date::isValidDate($value)); } - public function testIsValidDateValidDates() + public function testIsValidDateValidDates(): void { self::assertTrue(Date::isValidDate('2017-01-01')); self::assertTrue(Date::isValidDate('2017-01-01 10:30', true)); @@ -134,7 +134,7 @@ class DateTest extends BaseTestCase * @param mixed $value Empty source of date format * @dataProvider provideEmptyValue */ - public function testIsValidDateFormatEmptyFormats($value) + public function testIsValidDateFormatEmptyFormats($value): void { self::assertFalse(Date::isValidDateFormat($value)); } @@ -143,12 +143,12 @@ class DateTest extends BaseTestCase * @param mixed $format Invalid format of date * @dataProvider provideInvalidDateFormats */ - public function testIsValidDateFormatInvalidFormats($format) + public function testIsValidDateFormatInvalidFormats($format): void { self::assertFalse(Date::isValidDateFormat($format)); } - public function testIsValidDateFormatValidFormats() + public function testIsValidDateFormatValidFormats(): void { self::assertTrue(Date::isValidDateFormat('Y')); self::assertTrue(Date::isValidDateFormat('yy')); @@ -165,12 +165,12 @@ class DateTest extends BaseTestCase * @param mixed $value Empty value, e.g. "" * @dataProvider provideEmptyValue */ - public function testGenerateRandomTimeEmptyFormat($value) + public function testGenerateRandomTimeEmptyFormat($value): void { self::assertNull(Date::generateRandomTime($value)); } - public function testGenerateRandomTimeIncorrectFormat() + public function testGenerateRandomTimeIncorrectFormat(): void { self::assertNull(Date::generateRandomTime(',')); self::assertNull(Date::generateRandomTime(';')); @@ -178,12 +178,12 @@ class DateTest extends BaseTestCase self::assertNull(Date::generateRandomTime('?')); } - public function testGenerateRandomTimeDefaultFormat() + public function testGenerateRandomTimeDefaultFormat(): void { self::assertRegExp('/\d{2}:\d{2}:\d{2}/', Date::generateRandomTime()); } - public function testGenerateRandomTimeCustomFormat() + public function testGenerateRandomTimeCustomFormat(): void { self::assertRegExp('/^0[1-9]{1}|1[0-2]{1}$/', Date::generateRandomTime('h')); // 01 through 12 self::assertRegExp('/^[0-5]?[0-9]$/', Date::generateRandomTime('i')); // 00 through 59 @@ -193,12 +193,12 @@ class DateTest extends BaseTestCase self::assertRegExp('/^[1-9]|1[0-2]:\d{2}$/', Date::generateRandomTime('g:i')); } - public function testGetCurrentDayOfWeek() + public function testGetCurrentDayOfWeek(): void { self::assertRegExp('/^[0-6]{1}$/', (string)Date::getCurrentDayOfWeek()); } - public function testGetCurrentDayOfWeekName() + public function testGetCurrentDayOfWeekName(): void { // Required to avoid failure: // @@ -228,7 +228,7 @@ class DateTest extends BaseTestCase * * @dataProvider provideIncorrectYearMonthDay */ - public function testGetDayOfWeekIncorrectValues($year, $month, $day) + public function testGetDayOfWeekIncorrectValues($year, $month, $day): void { $this->expectException(UnknownDatePartTypeException::class); self::assertEmpty(Date::getDayOfWeek($year, $month, $day)); @@ -241,7 +241,7 @@ class DateTest extends BaseTestCase * * @dataProvider provideYearMonthDay */ - public function testGetDayOfWeek($year, $month, $day) + public function testGetDayOfWeek($year, $month, $day): void { self::assertRegExp('/^[0-6]{1}$/', (string)Date::getDayOfWeek($year, $month, $day)); } @@ -252,18 +252,18 @@ class DateTest extends BaseTestCase * * @dataProvider provideEmptyDatesForDateDifference */ - public function testGetDateDifferenceEmptyDates($dateStart, $dateEnd) + public function testGetDateDifferenceEmptyDates($dateStart, $dateEnd): void { self::assertNull(Date::getDateDifference($dateStart, $dateEnd)); } - public function testGetDateDifferenceInvalidDates() + public function testGetDateDifferenceInvalidDates(): void { self::assertNull(Date::getDateDifference('2017-01-40', '2017-13-01')); self::assertNull(Date::getDateDifference('xyz', 'lorem')); } - public function testGetDateDifferenceOneDay() + public function testGetDateDifferenceOneDay(): void { // Difference of 1 day $dateStart = '2017-01-01'; @@ -311,7 +311,7 @@ class DateTest extends BaseTestCase self::assertEquals(0, Date::getDateDifference(new DateTime('yesterday'), new DateTime('midnight'), Date::DATE_DIFFERENCE_UNIT_MINUTES)); } - public function testGetDateDifferenceOneDayTwoHours() + public function testGetDateDifferenceOneDayTwoHours(): void { // Difference of 1 day, 2 hours and 15 minutes $dateStart = '2017-01-01 12:00'; @@ -344,7 +344,7 @@ class DateTest extends BaseTestCase self::assertEquals(15, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); } - public function testGetDateDifferenceOneMonthFortyOneDays() + public function testGetDateDifferenceOneMonthFortyOneDays(): void { // Difference of 1 month, 41 days, 4 hours and 30 minutes $dateStart = '2017-01-01 12:00'; @@ -377,7 +377,7 @@ class DateTest extends BaseTestCase self::assertEquals(30, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); } - public function testGetDateDifferenceNewYear() + public function testGetDateDifferenceNewYear(): void { $dateStart = '2017-12-31 23:59'; $dateEnd = '2018-01-01 00:00'; @@ -409,7 +409,7 @@ class DateTest extends BaseTestCase self::assertEquals(1, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); } - public function testGetDateDifferenceLessThan24Hours() + public function testGetDateDifferenceLessThan24Hours(): void { $dateStart = '2017-01-01 16:00'; $dateEnd = '2017-01-02 10:00'; @@ -441,7 +441,7 @@ class DateTest extends BaseTestCase self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); } - public function testGetDateDifferenceEqual24Hours() + public function testGetDateDifferenceEqual24Hours(): void { $dateStart = '2017-01-01 00:00'; $dateEnd = '2017-01-02 00:00'; @@ -473,7 +473,7 @@ class DateTest extends BaseTestCase self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); } - public function testGetDateDifferenceInvertedDates() + public function testGetDateDifferenceInvertedDates(): void { $dateStart = '2017-01-02 10:00'; $dateEnd = '2017-01-01 16:00'; @@ -505,7 +505,7 @@ class DateTest extends BaseTestCase self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); } - public function testGetDateDifferenceNoDifference() + public function testGetDateDifferenceNoDifference(): void { // No difference $dateStart = '2017-01-01 12:00'; @@ -542,7 +542,7 @@ class DateTest extends BaseTestCase * @param mixed $invalidCount Empty value, e.g. "" * @dataProvider provideEmptyValue */ - public function testGetDatesCollectionInvalidCount($invalidCount) + public function testGetDatesCollectionInvalidCount($invalidCount): void { self::assertEquals([], Date::getDatesCollection(new DateTime(), $invalidCount)); self::assertEquals([], Date::getDatesCollection(new DateTime(), -1)); @@ -552,14 +552,14 @@ class DateTest extends BaseTestCase * @param mixed $invalidInterval Empty value, e.g. "" * @dataProvider provideEmptyValue */ - public function testGetDatesCollectionInvalidInterval($invalidInterval) + public function testGetDatesCollectionInvalidInterval($invalidInterval): void { self::assertEquals([], Date::getDatesCollection(new DateTime(), 2, $invalidInterval)); self::assertEquals([], Date::getDatesCollection(new DateTime(), 2, 'lorem')); self::assertEquals([], Date::getDatesCollection(new DateTime(), 2, '%d')); } - public function testGetDatesCollection() + public function testGetDatesCollection(): void { // 1 date only $effect = [ @@ -596,7 +596,7 @@ class DateTest extends BaseTestCase self::assertEquals($effect, Date::getDatesCollection(new DateTime('2017-01-01'), 3, 'P%dM')); } - public function testGetRandomDateUsingDefaults() + public function testGetRandomDateUsingDefaults(): void { $startDate = new DateTime(); $start = 1; @@ -619,7 +619,7 @@ class DateTest extends BaseTestCase * * @dataProvider provideDataOfRandomDateIncorrectEnd */ - public function testGetRandomDateIncorrectEnd(DateTime $startDate, $start, $end) + public function testGetRandomDateIncorrectEnd(DateTime $startDate, $start, $end): void { $randomDate = Date::getRandomDate($startDate, $start, $end); @@ -636,7 +636,7 @@ class DateTest extends BaseTestCase * * @dataProvider provideDataOfRandomDate */ - public function testGetRandomDate(DateTime $startDate, $start, $end) + public function testGetRandomDate(DateTime $startDate, $start, $end): void { $randomDate = Date::getRandomDate($startDate, $start, $end); @@ -651,9 +651,9 @@ class DateTest extends BaseTestCase /** * @param mixed $period Empty value, e.g. "" - * @dataProvider provideEmptyValue + * @dataProvider provideEmptyScalarValue */ - public function testGetDatesForPeriodUsingEmptyPeriod($period) + public function testGetDatesForPeriodUsingEmptyPeriod($period): void { self::assertNull(Date::getDatesForPeriod($period)); } @@ -662,7 +662,7 @@ class DateTest extends BaseTestCase * @param int $period Incorrect period to verify * @dataProvider provideIncorrectPeriod */ - public function testGetDatesForPeriodUsingIncorrectPeriod($period) + public function testGetDatesForPeriodUsingIncorrectPeriod($period): void { self::assertNull(Date::getDatesForPeriod($period)); } @@ -674,7 +674,7 @@ class DateTest extends BaseTestCase * * @dataProvider provideCorrectPeriod */ - public function testGetDatesForPeriod($period, DatePeriod $expected) + public function testGetDatesForPeriod($period, DatePeriod $expected): void { self::assertEquals($expected, Date::getDatesForPeriod($period)); } diff --git a/tests/Utilities/MiscellaneousTest.php b/tests/Utilities/MiscellaneousTest.php index 7f48d98..93af639 100644 --- a/tests/Utilities/MiscellaneousTest.php +++ b/tests/Utilities/MiscellaneousTest.php @@ -23,7 +23,7 @@ use stdClass; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Utilities\Miscellaneous + * @covers \Meritoo\Common\Utilities\Miscellaneous */ class MiscellaneousTest extends BaseTestCase { @@ -707,22 +707,40 @@ class MiscellaneousTest extends BaseTestCase * * @dataProvider provideNumberToFillMissingZeros */ - public function testFillMissingZeros($number, $length, $before, $expected) + public function testFillMissingZeros($number, $length, $before, $expected): void { self::assertSame($expected, Miscellaneous::fillMissingZeros($number, $length, $before)); } - public function testGetProjectRootPath() + public function testGetProjectRootPath(): void { self::assertNotEmpty(Miscellaneous::getProjectRootPath()); } + /** + * @param string $description Description of test case + * @param string $string The string which should be shortened + * @param bool $last (optional) If is set to true, last element is removed (default behaviour). + * Otherwise - first. + * @param null|string $expected Expected result + * + * @dataProvider provideStringToRemoveMarginalCharacter + */ + public function testRemoveMarginalCharacter( + string $description, + string $string, + bool $last, + ?string $expected + ): void { + self::assertEquals($expected, Miscellaneous::removeMarginalCharacter($string, $last), $description); + } + /** * Provides string to convert characters to latin characters and not lower cased and not human-readable * * @return Generator */ - public function provideStringToLatinNotLowerCaseHuman() + public function provideStringToLatinNotLowerCaseHuman(): ?Generator { yield[ 'asuo', @@ -1443,6 +1461,51 @@ class MiscellaneousTest extends BaseTestCase ]; } + public function provideStringToRemoveMarginalCharacter(): ?Generator + { + yield[ + 'An empty string - remove last character', + '', + true, + null, + ]; + + yield[ + 'An empty string - remove first character', + '', + false, + null, + ]; + + yield[ + 'Simple, two words - remove last character', + 'Lorem ipsum', + true, + 'Lorem ipsu', + ]; + + yield[ + 'Simple, two words - remove first character', + 'Lorem ipsum', + false, + 'orem ipsum', + ]; + + yield[ + 'Two sentences - remove last character', + 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis.', + true, + 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis', + ]; + + yield[ + 'Two sentences - remove first character', + 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis.', + false, + 'tiam ullamcorper. Suspendisse a pellentesque dui, non felis.', + ]; + } + /** * {@inheritdoc} */ diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 1862ee3..7a0aaef 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -49,20 +49,20 @@ class ReflectionTest extends BaseTestCase * @param mixed $invalidClass Empty value, e.g. "" * @dataProvider provideEmptyValue */ - public function testGetClassNameInvalidClass($invalidClass) + public function testGetClassNameInvalidClass($invalidClass): void { self::assertNull(Reflection::getClassName($invalidClass)); self::assertNull(Reflection::getClassName(123)); } - public function testGetClassNameNotExistingClass() + public function testGetClassNameNotExistingClass(): void { // Not existing class self::assertEquals('', Reflection::getClassName('xyz')); self::assertEquals('', Reflection::getClassName('xyz', true)); } - public function testGetClassNameExistingClass() + public function testGetClassNameExistingClass(): void { // Existing class self::assertEquals(self::class, Reflection::getClassName(self::class)); @@ -77,9 +77,9 @@ class ReflectionTest extends BaseTestCase } /** - * A case when namespace of class contains name of class (name of class is duplicated, occurs twice) + * A case when namespace of class contains name of class (iow. name of class occurs twice) */ - public function testGetClassWhileNamespaceContainsClassName() + public function testGetClassWhileNamespaceContainsClassName(): void { self::assertEquals( 'Meritoo\Common\Collection\Collection', @@ -92,13 +92,13 @@ class ReflectionTest extends BaseTestCase ); } - public function testGetClassNamespaceNotExistingClass() + public function testGetClassNamespaceNotExistingClass(): void { // Not existing class self::assertEquals('', Reflection::getClassNamespace('xyz')); } - public function testGetClassNamespaceExistingClass() + public function testGetClassNamespaceExistingClass(): void { // Existing class self::assertEquals('Meritoo\Test\Common\Utilities', Reflection::getClassNamespace(self::class)); From a6b2704c665a728ac2f874ce7bc398c018cd6d24 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 5 May 2019 23:05:42 +0200 Subject: [PATCH 052/137] BaseType::isCorrectType() method > make static --- src/Traits/Test/Base/BaseTestCaseTrait.php | 2 +- .../Test/Base/BaseTypeTestCaseTrait.php | 8 +- src/Type/Base/BaseType.php | 22 +++--- src/Utilities/Date.php | 2 +- .../Base/UnknownTypeExceptionTest.php | 2 +- tests/Type/Base/BaseTypeTest.php | 79 +++++++++++-------- tests/Type/DatePartTypeTest.php | 20 ++--- tests/Type/DatePeriodTest.php | 10 +-- tests/Type/OopVisibilityTypeTest.php | 12 +-- tests/Utilities/DateTest.php | 8 +- 10 files changed, 86 insertions(+), 79 deletions(-) diff --git a/src/Traits/Test/Base/BaseTestCaseTrait.php b/src/Traits/Test/Base/BaseTestCaseTrait.php index dfb5452..504922d 100644 --- a/src/Traits/Test/Base/BaseTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTestCaseTrait.php @@ -187,7 +187,7 @@ trait BaseTestCaseTrait int $requiredArgumentsCount = 0 ): void { // Type of visibility is not correct? - if (!(new OopVisibilityType())->isCorrectType($visibilityType)) { + if (!OopVisibilityType::isCorrectType($visibilityType)) { throw UnknownOopVisibilityTypeException::createException($visibilityType); } diff --git a/src/Traits/Test/Base/BaseTypeTestCaseTrait.php b/src/Traits/Test/Base/BaseTypeTestCaseTrait.php index 4fc2f1a..e08c7b4 100644 --- a/src/Traits/Test/Base/BaseTypeTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTypeTestCaseTrait.php @@ -33,14 +33,14 @@ trait BaseTypeTestCaseTrait /** * Verifies whether given type is correct or not * - * @param null|string $type Type to verify - * @param bool $expected Information if given type is correct or not + * @param bool $isCorrect Information if processed type is correct + * @param bool $expected Expected information if processed type is correct * * @dataProvider provideTypeToVerify */ - public function testIfGivenTypeIsCorrect(?string $type, bool $expected): void + public function testIfGivenTypeIsCorrect(bool $isCorrect, bool $expected): void { - static::assertEquals($expected, $this->getTestedTypeInstance()->isCorrectType($type)); + static::assertEquals($expected, $isCorrect); } /** diff --git a/src/Type/Base/BaseType.php b/src/Type/Base/BaseType.php index fa3f6c7..a1465be 100644 --- a/src/Type/Base/BaseType.php +++ b/src/Type/Base/BaseType.php @@ -26,6 +26,17 @@ abstract class BaseType */ private $all; + /** + * Returns information if given type is correct + * + * @param null|string $type The type to check + * @return bool + */ + public static function isCorrectType(?string $type): bool + { + return in_array($type, (new static())->getAll(), true); + } + /** * Returns all types * @@ -39,15 +50,4 @@ abstract class BaseType return $this->all; } - - /** - * Returns information if given type is correct - * - * @param null|string $type The type to check - * @return bool - */ - public function isCorrectType(?string $type): bool - { - return in_array($type, $this->getAll(), true); - } } diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index ab60312..be378c8 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -76,7 +76,7 @@ class Date * Type of period is incorrect? * Nothing to do */ - if (!(new DatePeriod())->isCorrectType($period)) { + if (!DatePeriod::isCorrectType($period)) { return null; } diff --git a/tests/Exception/Base/UnknownTypeExceptionTest.php b/tests/Exception/Base/UnknownTypeExceptionTest.php index 6820c79..7e97f33 100644 --- a/tests/Exception/Base/UnknownTypeExceptionTest.php +++ b/tests/Exception/Base/UnknownTypeExceptionTest.php @@ -94,7 +94,7 @@ class TestService */ public function getTranslatedType($type) { - if ((new TestType())->isCorrectType($type)) { + if (TestType::isCorrectType($type)) { return ucfirst(str_replace('_', ' ', $type)); } diff --git a/tests/Type/Base/BaseTypeTest.php b/tests/Type/Base/BaseTypeTest.php index 99decad..e90cc9d 100644 --- a/tests/Type/Base/BaseTypeTest.php +++ b/tests/Type/Base/BaseTypeTest.php @@ -41,15 +41,25 @@ class BaseTypeTest extends BaseTestCase } /** - * @param BaseType $type Type of something - * @param string $toVerifyType Concrete type to verify (of given instance of type) - * @param bool $isCorrect Expected information if given type is correct + * @param string $toVerifyType Concrete type to verify + * @param bool $isCorrect Expected information if given type is correct * - * @dataProvider provideTypeWithConcreteType + * @dataProvider provideTypeToVerifyUsingTestEmptyType */ - public function testIsCorrectType(BaseType $type, $toVerifyType, $isCorrect) + public function testIsCorrectTypeUsingTestEmptyType(?string $toVerifyType, bool $isCorrect): void { - self::assertEquals($isCorrect, $type->isCorrectType($toVerifyType)); + self::assertEquals($isCorrect, TestEmptyType::isCorrectType($toVerifyType)); + } + + /** + * @param string $toVerifyType Concrete type to verify + * @param bool $isCorrect Expected information if given type is correct + * + * @dataProvider provideTypeToVerifyUsingTestType + */ + public function testIsCorrectTypeUsingTestType(?string $toVerifyType, bool $isCorrect): void + { + self::assertEquals($isCorrect, TestType::isCorrectType($toVerifyType)); } /** @@ -78,107 +88,108 @@ class BaseTypeTest extends BaseTestCase * * @return Generator */ - public function provideTypeWithConcreteType() + public function provideTypeToVerifyUsingTestEmptyType(): ?Generator { yield[ - new TestEmptyType(), null, false, ]; yield[ - new TestEmptyType(), - false, + 'null', false, ]; yield[ - new TestEmptyType(), - true, + 'false', + false, + ]; + + yield[ + 'true', false, ]; yield[ - new TestEmptyType(), '', false, ]; yield[ - new TestEmptyType(), - 0, + '0', false, ]; yield[ - new TestEmptyType(), - 1, + '1', false, ]; yield[ - new TestEmptyType(), 'lorem', false, ]; + } + /** + * Provides type of something for testing the isCorrectType() method + * + * @return Generator + */ + public function provideTypeToVerifyUsingTestType(): ?Generator + { yield[ - new TestType(), null, false, ]; yield[ - new TestType(), - false, + 'null', false, ]; yield[ - new TestType(), - true, + 'false', + false, + ]; + + yield[ + 'true', false, ]; yield[ - new TestType(), '', false, ]; yield[ - new TestType(), - 0, + '0', false, ]; yield[ - new TestType(), - 1, + '1', false, ]; yield[ - new TestType(), 'lorem', false, ]; yield[ - new TestType(), 'test', false, ]; yield[ - new TestType(), - TestType::TEST_1, + 'test_1', true, ]; yield[ - new TestType(), - TestType::TEST_2, + 'test_2', true, ]; } diff --git a/tests/Type/DatePartTypeTest.php b/tests/Type/DatePartTypeTest.php index 4e9b312..64d7c15 100644 --- a/tests/Type/DatePartTypeTest.php +++ b/tests/Type/DatePartTypeTest.php @@ -30,52 +30,52 @@ class DatePartTypeTest extends BaseTypeTestCase public function provideTypeToVerify(): Generator { yield[ - '', + DatePartType::isCorrectType(''), false, ]; yield[ - null, + DatePartType::isCorrectType(null), false, ]; yield[ - '0', + DatePartType::isCorrectType('0'), false, ]; yield[ - '1', + DatePartType::isCorrectType('1'), false, ]; yield[ - 'day', + DatePartType::isCorrectType('day'), true, ]; yield[ - 'hour', + DatePartType::isCorrectType('hour'), true, ]; yield[ - 'minute', + DatePartType::isCorrectType('minute'), true, ]; yield[ - 'month', + DatePartType::isCorrectType('month'), true, ]; yield[ - 'second', + DatePartType::isCorrectType('second'), true, ]; yield[ - 'year', + DatePartType::isCorrectType('year'), true, ]; } diff --git a/tests/Type/DatePeriodTest.php b/tests/Type/DatePeriodTest.php index bb57851..bcb9ca2 100644 --- a/tests/Type/DatePeriodTest.php +++ b/tests/Type/DatePeriodTest.php @@ -219,27 +219,27 @@ class DatePeriodTest extends BaseTypeTestCase public function provideTypeToVerify(): Generator { yield[ - '', + DatePeriod::isCorrectType(''), false, ]; yield[ - '-1', + DatePeriod::isCorrectType('-1'), false, ]; yield[ - '4', + DatePeriod::isCorrectType('4'), true, ]; yield[ - '3', + DatePeriod::isCorrectType('3'), true, ]; yield[ - '8', + DatePeriod::isCorrectType('8'), true, ]; } diff --git a/tests/Type/OopVisibilityTypeTest.php b/tests/Type/OopVisibilityTypeTest.php index 34fabc1..2f858cd 100644 --- a/tests/Type/OopVisibilityTypeTest.php +++ b/tests/Type/OopVisibilityTypeTest.php @@ -30,32 +30,32 @@ class OopVisibilityTypeTest extends BaseTypeTestCase public function provideTypeToVerify(): Generator { yield[ - '', + OopVisibilityType::isCorrectType(''), false, ]; yield[ - null, + OopVisibilityType::isCorrectType(null), false, ]; yield[ - '-1', + OopVisibilityType::isCorrectType('-1'), false, ]; yield[ - '1', + OopVisibilityType::isCorrectType('1'), true, ]; yield[ - '2', + OopVisibilityType::isCorrectType('2'), true, ]; yield[ - '3', + OopVisibilityType::isCorrectType('3'), true, ]; } diff --git a/tests/Utilities/DateTest.php b/tests/Utilities/DateTest.php index 15ae92b..a899f48 100644 --- a/tests/Utilities/DateTest.php +++ b/tests/Utilities/DateTest.php @@ -649,13 +649,9 @@ class DateTest extends BaseTestCase self::assertTrue($randomDate >= $intervalMinDate && $randomDate <= $intervalMaxDate); } - /** - * @param mixed $period Empty value, e.g. "" - * @dataProvider provideEmptyScalarValue - */ - public function testGetDatesForPeriodUsingEmptyPeriod($period): void + public function testGetDatesForPeriodUsingEmptyString(): void { - self::assertNull(Date::getDatesForPeriod($period)); + self::assertNull(Date::getDatesForPeriod('')); } /** From 98d0fed61d13a0d4b7ba5fc54da13c689e02dfea Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 5 May 2019 23:06:18 +0200 Subject: [PATCH 053/137] Refactoring --- src/Utilities/Arrays.php | 158 ++++-------------- src/Utilities/Date.php | 4 +- .../Base/UnknownTypeExceptionTest.php | 4 +- tests/Type/Base/BaseTypeTest.php | 4 +- 4 files changed, 38 insertions(+), 132 deletions(-) diff --git a/src/Utilities/Arrays.php b/src/Utilities/Arrays.php index 3652ebb..41386c2 100644 --- a/src/Utilities/Arrays.php +++ b/src/Utilities/Arrays.php @@ -34,10 +34,7 @@ class Arrays */ public static function values2string(array $array, $arrayColumnKey = '', $separator = ',') { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -66,10 +63,7 @@ class Arrays $values[] = $appendMe; } - /* - * No values found? - * Nothing to do - */ + // No values found? Nothing to do if (empty($values)) { return null; } @@ -93,10 +87,7 @@ class Arrays $valuesKeysSeparator = '=', $valuesWrapper = '' ) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -127,10 +118,7 @@ class Arrays */ public static function values2csv(array $array, $separator = ',') { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -189,10 +177,7 @@ class Arrays */ public static function getFirstElement(array $array, $firstLevelOnly = true) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -215,10 +200,7 @@ class Arrays */ public static function getFirstKey(array $array) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -257,10 +239,7 @@ class Arrays */ public static function getLastElement(array $array, $firstLevelOnly = true) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -283,10 +262,7 @@ class Arrays */ public static function getLastElementBreadCrumb(array $array, $separator = '/') { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -316,10 +292,7 @@ class Arrays */ public static function getLastRow(array $array) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -488,10 +461,7 @@ class Arrays */ public static function quoteStrings(array $array): ?array { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -544,10 +514,7 @@ class Arrays */ public static function getLastKey(array $array) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -566,10 +533,7 @@ class Arrays */ public static function removeElement(array $array, $item) { - /* - * No elements or the element does not exist? - * Nothing to do - */ + // No elements or the element does not exist? Nothing to do if (empty($array) || !in_array($item, $array, true)) { return false; } @@ -659,10 +623,7 @@ class Arrays */ public static function setKeysAsValues(array $array, $ignoreDuplicatedValues = true) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -708,10 +669,7 @@ class Arrays */ public static function ksortRecursive(array &$array, $sortFlags = SORT_REGULAR) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -736,10 +694,7 @@ class Arrays */ public static function getNonArrayElementsCount(array $array): ?int { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -958,10 +913,7 @@ class Arrays */ public static function areAllKeysMatchedByPattern(array $array, string $pattern, bool $firstLevelOnly = false): bool { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return false; } @@ -1046,10 +998,7 @@ class Arrays */ public static function getValueByKeysPath(array $array, array $keys) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -1100,10 +1049,7 @@ class Arrays */ public static function issetRecursive(array $array, array $keys) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return false; } @@ -1138,10 +1084,7 @@ class Arrays */ public static function getAllValuesOfKey(array $array, $key) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -1182,10 +1125,7 @@ class Arrays */ public static function setPositions(array $array, $keyName = self::POSITION_KEY_NAME, $startPosition = null) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -1214,10 +1154,7 @@ class Arrays */ public static function trimRecursive(array $array) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return []; } @@ -1286,10 +1223,7 @@ class Arrays */ public static function sortByCustomKeysOrder(array $array, array $keysOrder) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -1335,10 +1269,7 @@ class Arrays */ public static function implodeSmart(array $array, $separator) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -1370,10 +1301,7 @@ class Arrays */ public static function areAllValuesEmpty(array $array, $strictNull = false) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return false; } @@ -1493,8 +1421,7 @@ class Arrays */ public static function getIndexOf(array $array, $element) { - // No elements? - // Nothing to do + // No elements? Nothing to do if (empty($array)) { return false; } @@ -1519,10 +1446,7 @@ class Arrays */ public static function incrementIndexes(array $array, ?int $startIndex = null, int $incrementStep = 1): ?array { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -1602,10 +1526,7 @@ class Arrays */ public static function isMultiDimensional(array $array): ?bool { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } @@ -1621,10 +1542,7 @@ class Arrays */ public static function getDimensionsCount(array $array): int { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return 0; } @@ -1656,10 +1574,7 @@ class Arrays */ public static function getNonEmptyValues(array $values): ?array { - /* - * No values? - * Nothing to do - */ + // No values? Nothing to do if (empty($values)) { return null; } @@ -1681,20 +1596,14 @@ class Arrays */ public static function getNonEmptyValuesAsString(array $values, string $separator = ', '): ?string { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($values)) { return null; } $nonEmpty = self::getNonEmptyValues($values); - /* - * No values? - * Nothing to do - */ + // No values? Nothing to do if (empty($nonEmpty)) { return ''; } @@ -1734,10 +1643,7 @@ class Arrays */ private static function getNeighbour(array $array, $element, bool $next = true) { - /* - * No elements? - * Nothing to do - */ + // No elements? Nothing to do if (empty($array)) { return null; } diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index be378c8..6b614f6 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -66,11 +66,11 @@ class Date /** * Returns date's period (that contains start and end date) for given period * - * @param int $period The period, type of period. One of DatePeriod class constants, e.g. DatePeriod::LAST_WEEK. + * @param string $period The period, type of period. One of DatePeriod class constants, e.g. DatePeriod::LAST_WEEK. * @throws Exception * @return null|DatePeriod */ - public static function getDatesForPeriod($period) + public static function getDatesForPeriod(string $period): ?DatePeriod { /* * Type of period is incorrect? diff --git a/tests/Exception/Base/UnknownTypeExceptionTest.php b/tests/Exception/Base/UnknownTypeExceptionTest.php index 7e97f33..2c75b95 100644 --- a/tests/Exception/Base/UnknownTypeExceptionTest.php +++ b/tests/Exception/Base/UnknownTypeExceptionTest.php @@ -71,7 +71,7 @@ class UnknownTestTypeException extends UnknownTypeException * @param string $unknownType The unknown type of something (for testing purposes) * @return UnknownTestTypeException */ - public static function createException($unknownType) + public static function createException(string $unknownType): UnknownTestTypeException { return parent::create($unknownType, new TestType(), 'type of something used for testing'); } @@ -92,7 +92,7 @@ class TestService * @throws UnknownTestTypeException * @return string */ - public function getTranslatedType($type) + public function getTranslatedType(string $type): string { if (TestType::isCorrectType($type)) { return ucfirst(str_replace('_', ' ', $type)); diff --git a/tests/Type/Base/BaseTypeTest.php b/tests/Type/Base/BaseTypeTest.php index e90cc9d..94af1bd 100644 --- a/tests/Type/Base/BaseTypeTest.php +++ b/tests/Type/Base/BaseTypeTest.php @@ -19,7 +19,7 @@ use Meritoo\Common\Type\Base\BaseType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Type\Base\BaseType + * @covers \Meritoo\Common\Type\Base\BaseType */ class BaseTypeTest extends BaseTestCase { @@ -67,7 +67,7 @@ class BaseTypeTest extends BaseTestCase * * @return Generator */ - public function provideType() + public function provideType(): ?Generator { yield[ new TestEmptyType(), From 9a1f49d3736375193f70dc060014eb4df5aa23ed Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 10 May 2019 22:17:40 +0200 Subject: [PATCH 054/137] Trait for the Collection > type hinting --- src/Traits/Collection/ArrayAccessTrait.php | 8 ++++---- src/Traits/Collection/CountableTrait.php | 2 +- .../Collection/IteratorAggregateTrait.php | 2 +- src/Traits/Collection/MainTrait.php | 18 +++++++++--------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Traits/Collection/ArrayAccessTrait.php b/src/Traits/Collection/ArrayAccessTrait.php index 5db8567..faa6076 100644 --- a/src/Traits/Collection/ArrayAccessTrait.php +++ b/src/Traits/Collection/ArrayAccessTrait.php @@ -19,7 +19,7 @@ trait ArrayAccessTrait /** * {@inheritdoc} */ - public function offsetExists($offset) + public function offsetExists($offset): bool { return $this->exists($offset); } @@ -39,7 +39,7 @@ trait ArrayAccessTrait /** * {@inheritdoc} */ - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { $this->elements[$offset] = $value; } @@ -47,7 +47,7 @@ trait ArrayAccessTrait /** * {@inheritdoc} */ - public function offsetUnset($offset) + public function offsetUnset($offset): void { if ($this->exists($offset)) { unset($this->elements[$offset]); @@ -60,7 +60,7 @@ trait ArrayAccessTrait * @param int|string $index The index/key of element * @return bool */ - private function exists($index) + private function exists($index): bool { return isset($this->elements[$index]) || array_key_exists($index, $this->elements); } diff --git a/src/Traits/Collection/CountableTrait.php b/src/Traits/Collection/CountableTrait.php index 4579d40..761581f 100644 --- a/src/Traits/Collection/CountableTrait.php +++ b/src/Traits/Collection/CountableTrait.php @@ -19,7 +19,7 @@ trait CountableTrait /** * {@inheritdoc} */ - public function count() + public function count(): int { return count($this->elements); } diff --git a/src/Traits/Collection/IteratorAggregateTrait.php b/src/Traits/Collection/IteratorAggregateTrait.php index 9c814b1..7430212 100644 --- a/src/Traits/Collection/IteratorAggregateTrait.php +++ b/src/Traits/Collection/IteratorAggregateTrait.php @@ -21,7 +21,7 @@ trait IteratorAggregateTrait /** * {@inheritdoc} */ - public function getIterator() + public function getIterator(): ArrayIterator { return new ArrayIterator($this->elements); } diff --git a/src/Traits/Collection/MainTrait.php b/src/Traits/Collection/MainTrait.php index 9188179..fae3153 100644 --- a/src/Traits/Collection/MainTrait.php +++ b/src/Traits/Collection/MainTrait.php @@ -33,7 +33,7 @@ trait MainTrait * @param mixed $index (optional) Index / key of the element * @return $this */ - public function add($element, $index = null) + public function add($element, $index = null): self { if (null === $index || '' === $index) { $this->elements[] = $element; @@ -52,7 +52,7 @@ trait MainTrait * this collection. Otherwise - not. * @return $this */ - public function addMultiple($elements, $useIndexes = false) + public function addMultiple($elements, bool $useIndexes = false): self { if (!empty($elements)) { foreach ($elements as $index => $element) { @@ -75,7 +75,7 @@ trait MainTrait * @param mixed $element The element to prepend * @return $this */ - public function prepend($element) + public function prepend($element): self { array_unshift($this->elements, $element); @@ -88,7 +88,7 @@ trait MainTrait * @param mixed $element The element to remove * @return $this */ - public function remove($element) + public function remove($element): self { if ($this->count() > 0) { foreach ($this->elements as $index => $existing) { @@ -108,7 +108,7 @@ trait MainTrait * * @return bool */ - public function isEmpty() + public function isEmpty(): bool { return empty($this->elements); } @@ -119,7 +119,7 @@ trait MainTrait * @param mixed $element The element to verify * @return bool */ - public function isFirst($element) + public function isFirst($element): bool { return reset($this->elements) === $element; } @@ -130,7 +130,7 @@ trait MainTrait * @param mixed $element The element to verify * @return bool */ - public function isLast($element) + public function isLast($element): bool { return end($this->elements) === $element; } @@ -141,7 +141,7 @@ trait MainTrait * @param mixed $element The element to verify * @return bool */ - public function has($element) + public function has($element): bool { $index = Arrays::getIndexOf($this->elements, $element); @@ -210,7 +210,7 @@ trait MainTrait * * @return array */ - public function toArray() + public function toArray(): array { return $this->elements; } From e75854feee46685ff7918df75b7edadbbd63e306 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 10 May 2019 23:47:48 +0200 Subject: [PATCH 055/137] Collection > trait > split into smaller traits (to make it more flexible) --- CHANGELOG.md | 1 + src/Traits/Collection/AddTrait.php | 63 +++++++++ src/Traits/Collection/GetTrait.php | 73 +++++++++++ src/Traits/Collection/MainTrait.php | 182 -------------------------- src/Traits/Collection/ModifyTrait.php | 52 ++++++++ src/Traits/Collection/VerifyTrait.php | 65 +++++++++ src/Traits/CollectionTrait.php | 8 ++ 7 files changed, 262 insertions(+), 182 deletions(-) create mode 100644 src/Traits/Collection/AddTrait.php create mode 100644 src/Traits/Collection/GetTrait.php create mode 100644 src/Traits/Collection/ModifyTrait.php create mode 100644 src/Traits/Collection/VerifyTrait.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 2987754..69edba8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Common and useful classes, methods, exceptions etc. 1. PHP Coding Standards Fixer > update configuration 2. Phing > tests > add task for Psalm (https://psalm.dev) +3. Collection > trait > split into smaller traits (to make it more flexible) # 1.0.3 diff --git a/src/Traits/Collection/AddTrait.php b/src/Traits/Collection/AddTrait.php new file mode 100644 index 0000000..b51a921 --- /dev/null +++ b/src/Traits/Collection/AddTrait.php @@ -0,0 +1,63 @@ + + * @copyright Meritoo + */ +trait AddTrait +{ + /** + * Adds given element (at the end of collection) + * + * @param mixed $element The element to add + * @param mixed $index (optional) Index / key of the element + * @return $this + */ + public function add($element, $index = null): self + { + if (null === $index || '' === $index) { + $this->elements[] = $element; + } else { + $this->elements[$index] = $element; + } + + return $this; + } + + /** + * Adds given elements (at the end of collection) + * + * @param array|Collection $elements The elements to add + * @param bool|false $useIndexes (optional) If is set to true, indexes of given elements will be used in + * this collection. Otherwise - not. + * @return $this + */ + public function addMultiple($elements, bool $useIndexes = false): self + { + if (!empty($elements)) { + foreach ($elements as $index => $element) { + if ($useIndexes) { + $this->add($element, $index); + + continue; + } + + $this->add($element); + } + } + + return $this; + } +} diff --git a/src/Traits/Collection/GetTrait.php b/src/Traits/Collection/GetTrait.php new file mode 100644 index 0000000..4cba31b --- /dev/null +++ b/src/Traits/Collection/GetTrait.php @@ -0,0 +1,73 @@ + + * @copyright Meritoo + */ +trait GetTrait +{ + /** + * Returns previous element for given element + * + * @param mixed $element The element to verify + * @return null|mixed + */ + public function getPrevious($element) + { + return Arrays::getPreviousElement($this->elements, $element); + } + + /** + * Returns next element for given element + * + * @param mixed $element The element to verify + * @return null|mixed + */ + public function getNext($element) + { + return Arrays::getNextElement($this->elements, $element); + } + + /** + * Returns the first element in the collection + * + * @return mixed + */ + public function getFirst() + { + return Arrays::getFirstElement($this->elements); + } + + /** + * Returns the last element in the collection + * + * @return mixed + */ + public function getLast() + { + return Arrays::getLastElement($this->elements); + } + + /** + * Returns element with given index + * + * @param mixed $index Index / key of the element + * @return null|mixed + */ + public function getByIndex($index) + { + return $this->elements[$index] ?? null; + } +} diff --git a/src/Traits/Collection/MainTrait.php b/src/Traits/Collection/MainTrait.php index fae3153..8b08e6c 100644 --- a/src/Traits/Collection/MainTrait.php +++ b/src/Traits/Collection/MainTrait.php @@ -8,9 +8,6 @@ namespace Meritoo\Common\Traits\Collection; -use Meritoo\Common\Collection\Collection; -use Meritoo\Common\Utilities\Arrays; - /** * Main trait for the Collection * @@ -26,185 +23,6 @@ trait MainTrait */ private $elements; - /** - * Adds given element (at the end of collection) - * - * @param mixed $element The element to add - * @param mixed $index (optional) Index / key of the element - * @return $this - */ - public function add($element, $index = null): self - { - if (null === $index || '' === $index) { - $this->elements[] = $element; - } else { - $this->elements[$index] = $element; - } - - return $this; - } - - /** - * Adds given elements (at the end of collection) - * - * @param array|Collection $elements The elements to add - * @param bool|false $useIndexes (optional) If is set to true, indexes of given elements will be used in - * this collection. Otherwise - not. - * @return $this - */ - public function addMultiple($elements, bool $useIndexes = false): self - { - if (!empty($elements)) { - foreach ($elements as $index => $element) { - if ($useIndexes) { - $this->add($element, $index); - - continue; - } - - $this->add($element); - } - } - - return $this; - } - - /** - * Prepends given element (adds given element at the beginning of collection) - * - * @param mixed $element The element to prepend - * @return $this - */ - public function prepend($element): self - { - array_unshift($this->elements, $element); - - return $this; - } - - /** - * Removes given element - * - * @param mixed $element The element to remove - * @return $this - */ - public function remove($element): self - { - if ($this->count() > 0) { - foreach ($this->elements as $index => $existing) { - if ($element === $existing) { - unset($this->elements[$index]); - - break; - } - } - } - - return $this; - } - - /** - * Returns information if collection is empty - * - * @return bool - */ - public function isEmpty(): bool - { - return empty($this->elements); - } - - /** - * Returns information if given element is first in the collection - * - * @param mixed $element The element to verify - * @return bool - */ - public function isFirst($element): bool - { - return reset($this->elements) === $element; - } - - /** - * Returns information if given element is last in the collection - * - * @param mixed $element The element to verify - * @return bool - */ - public function isLast($element): bool - { - return end($this->elements) === $element; - } - - /** - * Returns information if the collection has given element, iow. if given element exists in the collection - * - * @param mixed $element The element to verify - * @return bool - */ - public function has($element): bool - { - $index = Arrays::getIndexOf($this->elements, $element); - - return null !== $index && false !== $index; - } - - /** - * Returns previous element for given element - * - * @param mixed $element The element to verify - * @return null|mixed - */ - public function getPrevious($element) - { - return Arrays::getPreviousElement($this->elements, $element); - } - - /** - * Returns next element for given element - * - * @param mixed $element The element to verify - * @return null|mixed - */ - public function getNext($element) - { - return Arrays::getNextElement($this->elements, $element); - } - - /** - * Returns the first element in the collection - * - * @return mixed - */ - public function getFirst() - { - return Arrays::getFirstElement($this->elements); - } - - /** - * Returns the last element in the collection - * - * @return mixed - */ - public function getLast() - { - return Arrays::getLastElement($this->elements); - } - - /** - * Returns element with given index - * - * @param mixed $index Index / key of the element - * @return null|mixed - */ - public function getByIndex($index) - { - if (isset($this->elements[$index])) { - return $this->elements[$index]; - } - - return null; - } - /** * Returns representation of object as array * diff --git a/src/Traits/Collection/ModifyTrait.php b/src/Traits/Collection/ModifyTrait.php new file mode 100644 index 0000000..958e4de --- /dev/null +++ b/src/Traits/Collection/ModifyTrait.php @@ -0,0 +1,52 @@ + + * @copyright Meritoo + */ +trait ModifyTrait +{ + /** + * Prepends given element (adds given element at the beginning of collection) + * + * @param mixed $element The element to prepend + * @return $this + */ + public function prepend($element): self + { + array_unshift($this->elements, $element); + + return $this; + } + + /** + * Removes given element + * + * @param mixed $element The element to remove + * @return $this + */ + public function remove($element): self + { + if ($this->count() > 0) { + foreach ($this->elements as $index => $existing) { + if ($element === $existing) { + unset($this->elements[$index]); + + break; + } + } + } + + return $this; + } +} diff --git a/src/Traits/Collection/VerifyTrait.php b/src/Traits/Collection/VerifyTrait.php new file mode 100644 index 0000000..b88d821 --- /dev/null +++ b/src/Traits/Collection/VerifyTrait.php @@ -0,0 +1,65 @@ + + * @copyright Meritoo + */ +trait VerifyTrait +{ + /** + * Returns information if collection is empty + * + * @return bool + */ + public function isEmpty(): bool + { + return empty($this->elements); + } + + /** + * Returns information if given element is first in the collection + * + * @param mixed $element The element to verify + * @return bool + */ + public function isFirst($element): bool + { + return reset($this->elements) === $element; + } + + /** + * Returns information if given element is last in the collection + * + * @param mixed $element The element to verify + * @return bool + */ + public function isLast($element): bool + { + return end($this->elements) === $element; + } + + /** + * Returns information if the collection has given element, iow. if given element exists in the collection + * + * @param mixed $element The element to verify + * @return bool + */ + public function has($element): bool + { + $index = Arrays::getIndexOf($this->elements, $element); + + return null !== $index && false !== $index; + } +} diff --git a/src/Traits/CollectionTrait.php b/src/Traits/CollectionTrait.php index 8cb0cad..d7ac305 100644 --- a/src/Traits/CollectionTrait.php +++ b/src/Traits/CollectionTrait.php @@ -8,10 +8,14 @@ namespace Meritoo\Common\Traits; +use Meritoo\Common\Traits\Collection\AddTrait; use Meritoo\Common\Traits\Collection\ArrayAccessTrait; use Meritoo\Common\Traits\Collection\CountableTrait; +use Meritoo\Common\Traits\Collection\GetTrait; use Meritoo\Common\Traits\Collection\IteratorAggregateTrait; use Meritoo\Common\Traits\Collection\MainTrait; +use Meritoo\Common\Traits\Collection\ModifyTrait; +use Meritoo\Common\Traits\Collection\VerifyTrait; /** * Trait for the Collection @@ -22,6 +26,10 @@ use Meritoo\Common\Traits\Collection\MainTrait; trait CollectionTrait { use MainTrait; + use AddTrait; + use ModifyTrait; + use GetTrait; + use VerifyTrait; use CountableTrait; use ArrayAccessTrait; use IteratorAggregateTrait; From 2091adc8d063efff26c5e55969e36f5ab84371b4 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 11 May 2019 00:19:38 +0200 Subject: [PATCH 056/137] Collection > trait > return "void" where "self" causes type hinting problem and is not required --- CHANGELOG.md | 4 ++++ VERSION | 2 +- src/Traits/Collection/AddTrait.php | 34 +++++++++++++-------------- src/Traits/Collection/ModifyTrait.php | 26 +++++++++----------- 4 files changed, 32 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69edba8..dd96b21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Common and useful classes, methods, exceptions etc. +# 1.0.5 + +1. Collection > trait > return "void" where "self" causes type hinting problem and is not required + # 1.0.4 1. PHP Coding Standards Fixer > update configuration diff --git a/VERSION b/VERSION index ee90284..90a27f9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.4 +1.0.5 diff --git a/src/Traits/Collection/AddTrait.php b/src/Traits/Collection/AddTrait.php index b51a921..0714ec9 100644 --- a/src/Traits/Collection/AddTrait.php +++ b/src/Traits/Collection/AddTrait.php @@ -23,17 +23,16 @@ trait AddTrait * * @param mixed $element The element to add * @param mixed $index (optional) Index / key of the element - * @return $this */ - public function add($element, $index = null): self + public function add($element, $index = null): void { if (null === $index || '' === $index) { $this->elements[] = $element; - } else { - $this->elements[$index] = $element; + + return; } - return $this; + $this->elements[$index] = $element; } /** @@ -42,22 +41,21 @@ trait AddTrait * @param array|Collection $elements The elements to add * @param bool|false $useIndexes (optional) If is set to true, indexes of given elements will be used in * this collection. Otherwise - not. - * @return $this */ - public function addMultiple($elements, bool $useIndexes = false): self + public function addMultiple($elements, bool $useIndexes = false): void { - if (!empty($elements)) { - foreach ($elements as $index => $element) { - if ($useIndexes) { - $this->add($element, $index); - - continue; - } - - $this->add($element); - } + if (empty($elements)) { + return; } - return $this; + foreach ($elements as $index => $element) { + if ($useIndexes) { + $this->add($element, $index); + + continue; + } + + $this->add($element); + } } } diff --git a/src/Traits/Collection/ModifyTrait.php b/src/Traits/Collection/ModifyTrait.php index 958e4de..c08e677 100644 --- a/src/Traits/Collection/ModifyTrait.php +++ b/src/Traits/Collection/ModifyTrait.php @@ -20,33 +20,29 @@ trait ModifyTrait * Prepends given element (adds given element at the beginning of collection) * * @param mixed $element The element to prepend - * @return $this */ - public function prepend($element): self + public function prepend($element): void { array_unshift($this->elements, $element); - - return $this; } /** * Removes given element * * @param mixed $element The element to remove - * @return $this */ - public function remove($element): self + public function remove($element): void { - if ($this->count() > 0) { - foreach ($this->elements as $index => $existing) { - if ($element === $existing) { - unset($this->elements[$index]); - - break; - } - } + if (0 === $this->count()) { + return; } - return $this; + foreach ($this->elements as $index => $existing) { + if ($element === $existing) { + unset($this->elements[$index]); + + break; + } + } } } From b482d814e431456bf3f6aa6378c0dfb4b2933367 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 30 May 2019 21:32:00 +0200 Subject: [PATCH 057/137] Use .env instead of .env.dist --- .env.dist | 15 --------------- CHANGELOG.md | 4 ++++ VERSION | 2 +- 3 files changed, 5 insertions(+), 16 deletions(-) delete mode 100644 .env.dist diff --git a/.env.dist b/.env.dist deleted file mode 100644 index 4c093b4..0000000 --- a/.env.dist +++ /dev/null @@ -1,15 +0,0 @@ -# ----------------------------------------------------------------------------- -### Docker -# ----------------------------------------------------------------------------- - -# -# All containers -# -DOCKER_CONTAINER_OWNER=meritoo -DOCKER_CONTAINER_PROJECT=common-library - -# -# PHP configuration: -# - timezone -# -TIMEZONE=Europe/Warsaw diff --git a/CHANGELOG.md b/CHANGELOG.md index dd96b21..1c8eebf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Common and useful classes, methods, exceptions etc. +# 1.0.6 + +1. Use `.env` instead of `.env.dist` + # 1.0.5 1. Collection > trait > return "void" where "self" causes type hinting problem and is not required diff --git a/VERSION b/VERSION index 90a27f9..af0b7dd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.5 +1.0.6 From 538aa1fa799964dc71eaf101c93106645da68325 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 30 May 2019 21:43:06 +0200 Subject: [PATCH 058/137] Docker > use images (instead of Dockerfiles) --- docker-compose.yml | 18 +++--- docker/config/Dockerfile | 131 --------------------------------------- docker/config/php.ini | 3 - docker/config/xdebug.ini | 6 -- phing/filesets.xml | 4 +- phing/properties.dist | 6 -- 6 files changed, 9 insertions(+), 159 deletions(-) delete mode 100644 docker/config/Dockerfile delete mode 100644 docker/config/php.ini delete mode 100644 docker/config/xdebug.ini diff --git a/docker-compose.yml b/docker-compose.yml index 6224f02..8c2c204 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,29 +5,27 @@ services: # Required to run project # php: - image: ${DOCKER_CONTAINER_OWNER}/${DOCKER_CONTAINER_PROJECT}-php + image: meritoo/php7 container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-php entrypoint: php command: -S 0.0.0.0:9999 - build: - context: ./docker/config - args: - - TIMEZONE=${TIMEZONE} + environment: + TIMEZONE: ${TIMEZONE} volumes: - - .:/project:cached + - .:/var/www/application:cached composer: - image: ${DOCKER_CONTAINER_OWNER}/${DOCKER_CONTAINER_PROJECT}-php + image: meritoo/php7 container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-composer entrypoint: php -d memory_limit=-1 /usr/local/bin/composer volumes: - - .:/project:cached + - .:/var/www/application:cached # # Required to run PHPUnit's tests # phpunit: - image: ${DOCKER_CONTAINER_OWNER}/${DOCKER_CONTAINER_PROJECT}-php + image: meritoo/php7 container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-phpunit entrypoint: ./vendor/bin/phpunit command: --version volumes: - - .:/project:cached + - .:/var/www/application:cached diff --git a/docker/config/Dockerfile b/docker/config/Dockerfile deleted file mode 100644 index 5a7861b..0000000 --- a/docker/config/Dockerfile +++ /dev/null @@ -1,131 +0,0 @@ -FROM php:7.2-cli -MAINTAINER Meritoo - -# -# Tools & libraries -# -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - vim \ - git \ - unzip \ - libicu-dev \ - locales \ - && apt-get clean \ - && rm -rf \ - /var/lib/apt/lists/* \ - /tmp/* \ - /var/tmp/* - -# -# Generating locales: -# - de_DE -# - es_ES -# - en_GB -# - en_US -# - fr_FR -# - it_IT -# - pl_PL -# - ru_RU -# -RUN sed -i 's/^# de_DE/de_DE/g; \ - s/^# es_ES/es_ES/g; \ - s/^# en_GB/en_GB/g; \ - s/^# en_US/en_US/g; \ - s/^# fr_FR/fr_FR/g; \ - s/^# it_IT/it_IT/g; \ - s/^# pl_PL/pl_PL/g; \ - s/^# ru_RU/ru_RU/g;' /etc/locale.gen \ - && locale-gen - -# -# Set default language -# -# Required to avoid problem with using strange language by error messages. -# Example: "chmod(): Aucun fichier ou dossier de ce type" -# -ENV LANGUAGE=en_US.UTF-8 - -# -# PHP extensions -# -RUN docker-php-ext-install \ - intl \ - mbstring - -# -# PHP extensions (PECL): -# - Xdebug -# -RUN pecl install \ - xdebug \ - && docker-php-ext-enable \ - xdebug - -COPY xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini - -# -# PHP configuration: -# - default configuration -# - timezone -# -COPY php.ini /usr/local/etc/php/php.ini -ARG TIMEZONE -RUN ln -snf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \ - && echo ${TIMEZONE} > /etc/timezone \ - && printf '[PHP]\ndate.timezone = "%s"\n' ${TIMEZONE} > /usr/local/etc/php/conf.d/tzone.ini \ - && "date" -#RUN echo "\n""date.timezone = $TIMEZONE""\n" >> /usr/local/etc/php/php.ini - -# -# Phing -# -RUN pear channel-discover pear.phing.info \ - && pear install [--alldeps] phing/phing - -# -# Composer - environment variables: -# - disable warning about running commands as root/super user -# - disable automatic clearing of sudo sessions -# -# More: -# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser -# -ENV COMPOSER_ALLOW_SUPERUSER 1 - -# -# Composer + https://packagist.org/packages/hirak/prestissimo package -# -RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ - && php -r "if (hash_file('SHA384', 'composer-setup.php') === \ - '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo \ - 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \ - && php composer-setup.php --install-dir=/usr/local/bin --filename=composer \ - && php -r "unlink('composer-setup.php');" \ - && composer global require \ - --no-plugins \ - --no-scripts \ - --no-progress \ - --no-suggest \ - --no-interaction \ - --prefer-dist \ - --optimize-autoloader \ - --classmap-authoritative \ - hirak/prestissimo \ - && rm -rf ~/.composer/cache/* \ - && composer clear-cache \ - && composer --version - -# -# Bash -# -RUN sed -i 's/^# export/export/g; \ - s/^# alias/alias/g;' ~/.bashrc \ - && echo 'COLUMNS=200'"\n" >> ~/.bashrc - -# -# Use project-related binaries globally -# -ENV PATH="/project/vendor/bin:${PATH}" - -WORKDIR /project diff --git a/docker/config/php.ini b/docker/config/php.ini deleted file mode 100644 index b984c5d..0000000 --- a/docker/config/php.ini +++ /dev/null @@ -1,3 +0,0 @@ -display_errors = On -display_startup_errors = On -error_reporting = E_ALL diff --git a/docker/config/xdebug.ini b/docker/config/xdebug.ini deleted file mode 100644 index 22b2547..0000000 --- a/docker/config/xdebug.ini +++ /dev/null @@ -1,6 +0,0 @@ -[xdebug] -zend_extension=xdebug.so - -xdebug.remote_enable=1 -xdebug.remote_port=9001 -xdebug.remote_host=10.254.254.254 diff --git a/phing/filesets.xml b/phing/filesets.xml index fa969ea..59355ff 100644 --- a/phing/filesets.xml +++ b/phing/filesets.xml @@ -4,9 +4,7 @@ diff --git a/phing/properties.dist b/phing/properties.dist index 74bdba4..941410c 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -53,12 +53,6 @@ dir.reports.coverage = ${dir.reports}/phpunit-coverage dir.data.tests = ${dir.data}/tests dir.data.temporary = ${dir.data}/tmp -# Docker directories -# -dir.docker = ${project.basedir}/docker -dir.docker.data = ${dir.docker}/data/db -dir.docker.logs = ${dir.docker}/logs/nginx - # -------------------------------------------------------------------------------- # Static Analysis # -------------------------------------------------------------------------------- From e002adc162c022585198ab140034ddf5917ccd20 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 30 May 2019 21:55:09 +0200 Subject: [PATCH 059/137] PHP Coding Standards Fixer > fix coding standard --- tests/Utilities/ArraysTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Utilities/ArraysTest.php b/tests/Utilities/ArraysTest.php index 81a1dbe..e68b25a 100644 --- a/tests/Utilities/ArraysTest.php +++ b/tests/Utilities/ArraysTest.php @@ -2569,7 +2569,7 @@ letsTest[2] = value_2;'; ]; } - public function provideValueToIsEmptyArray(): ?\Generator + public function provideValueToIsEmptyArray(): ?Generator { yield[ 'An empty string', @@ -2616,7 +2616,7 @@ letsTest[2] = value_2;'; ]; } - public function provideValueToIsNotEmptyArray(): ?\Generator + public function provideValueToIsNotEmptyArray(): ?Generator { yield[ 'An empty string', From 15824d3f777ba821422a0ca22008e32423a521f6 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 2 Jun 2019 18:23:12 +0200 Subject: [PATCH 060/137] composer > squizlabs/php_codesniffer package > use ^3.4 (instead of ^2.9) --- .gitignore | 8 ++++++++ composer.json | 2 +- docs/Development.md | 7 ------- phing/properties.dist | 5 +++++ phing/tests.xml | 10 +++------- phpcs.xml.dist | 16 ++++++++++++++++ 6 files changed, 33 insertions(+), 15 deletions(-) create mode 100644 phpcs.xml.dist diff --git a/.gitignore b/.gitignore index a45c104..a2050f5 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,13 @@ /.php_cs.cache +# ------------------------------------------------------------------------------ +### PHP_CodeSniffer +# ------------------------------------------------------------------------------ +/.phpcs-cache +/phpcs.xml + + # ----------------------------------------------------------------------------- ### Build files # ----------------------------------------------------------------------------- @@ -117,6 +124,7 @@ Temporary Items # ------------------------------------------------------------------------------ # Windows thumbnail cache files Thumbs.db +Thumbs.db:encryptable ehthumbs.db ehthumbs_vista.db diff --git a/composer.json b/composer.json index 776b25d..90a54b8 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "phpstan/phpstan": "^0.11.1", "phpunit/phpunit": "^8.0", "sebastian/phpcpd": "^4.1", - "squizlabs/php_codesniffer": " ^2.9", + "squizlabs/php_codesniffer": "^3.4", "vimeo/psalm": "^3.0" }, "autoload": { diff --git a/docs/Development.md b/docs/Development.md index 211e9f4..19c6632 100644 --- a/docs/Development.md +++ b/docs/Development.md @@ -105,13 +105,6 @@ docker-compose exec php phing -f phing/tests.xml test:phpunit docker-compose run --rm phpunit --verbose --no-coverage ``` -# Versions of packages - -### squizlabs/php_codesniffer - -I have to use [squizlabs/php_codesniffer](https://packagist.org/packages/squizlabs/php_codesniffer) `^2.9` instead of -`^3.3`, because [Phing doesn't support 3.x PHP_CodeSniffer](https://github.com/phingofficial/phing/issues/716). - # Mutation Tests Served by [Infection — Mutation Testing Framework](https://infection.github.io). diff --git a/phing/properties.dist b/phing/properties.dist index 941410c..c287955 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -47,6 +47,7 @@ dir.tests = ${project.basedir}/tests dir.build = ${project.basedir}/build dir.reports = ${dir.build}/reports dir.reports.coverage = ${dir.reports}/phpunit-coverage +dir.reports.code_sniffer = ${dir.reports}/code_sniffer # Data directories # @@ -72,6 +73,10 @@ check.php_coveralls.command = ./vendor/bin/php-coveralls --ansi -v # tests.cs_fixer.command = ./vendor/bin/php-cs-fixer fix --verbose +# Path of the PHP_CodeSniffer (https://github.com/squizlabs/PHP_CodeSniffer) +# +tests.code_sniffer.command = ./vendor/bin/phpcs --report-full=${dir.reports.code_sniffer}/full.txt --report-summary=${dir.reports.code_sniffer}/summary.txt --report-checkstyle=${dir.reports.code_sniffer}/checkstyle.xml + # Test database path # tests.database = ${dir.data.temporary}/database.sqlite diff --git a/phing/tests.xml b/phing/tests.xml index 1edeb2c..631b3e1 100644 --- a/phing/tests.xml +++ b/phing/tests.xml @@ -55,14 +55,9 @@ test:infection" /> - + - - - - - - + @@ -112,6 +107,7 @@ + diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..2930822 --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,16 @@ + + + + + + + + + + + + src/ + tests/ + + From a9b985385ebcb291f0d9a32ae1c0480cc0ce9e11 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 2 Jun 2019 19:03:55 +0200 Subject: [PATCH 061/137] Add project configuration (project files related to IDE) --- .gitignore | 68 ++++++- .idea/.name | 1 + .idea/Meritoo Common Library.iml | 112 +++++++++++ .idea/composerJson.xml | 10 + .idea/inspectionProfiles/Project_Default.xml | 125 ++++++++++++ .idea/misc.xml | 6 + .idea/modules.xml | 8 + .idea/php-test-framework.xml | 14 ++ .idea/php.xml | 198 +++++++++++++++++++ .idea/symfony2.xml | 6 + .idea/vcs.xml | 6 + 11 files changed, 553 insertions(+), 1 deletion(-) create mode 100644 .idea/.name create mode 100644 .idea/Meritoo Common Library.iml create mode 100644 .idea/composerJson.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/php-test-framework.xml create mode 100644 .idea/php.xml create mode 100644 .idea/symfony2.xml create mode 100644 .idea/vcs.xml diff --git a/.gitignore b/.gitignore index a2050f5..e87265b 100644 --- a/.gitignore +++ b/.gitignore @@ -67,8 +67,74 @@ # ------------------------------------------------------------------------------ ### JetBrains template # ------------------------------------------------------------------------------ -/.idea +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser # ------------------------------------------------------------------------------ ### macOS template diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..af2d727 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Meritoo Common Library \ No newline at end of file diff --git a/.idea/Meritoo Common Library.iml b/.idea/Meritoo Common Library.iml new file mode 100644 index 0000000..b0760a9 --- /dev/null +++ b/.idea/Meritoo Common Library.iml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/composerJson.xml b/.idea/composerJson.xml new file mode 100644 index 0000000..1b07430 --- /dev/null +++ b/.idea/composerJson.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..68acef7 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,125 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..28a804d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..2ae0b8c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/php-test-framework.xml b/.idea/php-test-framework.xml new file mode 100644 index 0000000..fd66dd0 --- /dev/null +++ b/.idea/php-test-framework.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/php.xml b/.idea/php.xml new file mode 100644 index 0000000..0b27612 --- /dev/null +++ b/.idea/php.xml @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /usr/local/etc/php/conf.d/docker-php-ext-imagick.ini, /usr/local/etc/php/conf.d/docker-php-ext-intl.ini, /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini, /usr/local/etc/php/conf.d/docker-php-ext-pdo_mysql.ini, /usr/local/etc/php/conf.d/docker-php-ext-sodium.ini, /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini, /usr/local/etc/php/conf.d/docker-php-ext-zip.ini, /usr/local/etc/php/conf.d/tzone.ini + /usr/local/etc/php/php.ini + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/symfony2.xml b/.idea/symfony2.xml new file mode 100644 index 0000000..632dba4 --- /dev/null +++ b/.idea/symfony2.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 11e5ce3d56214ce342ef10104f63e7cb453c1af3 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 2 Jun 2019 19:04:23 +0200 Subject: [PATCH 062/137] Store .env in repository (do not ignore) --- .env | 15 +++++++++++++++ .gitignore | 6 ------ 2 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 0000000..4c093b4 --- /dev/null +++ b/.env @@ -0,0 +1,15 @@ +# ----------------------------------------------------------------------------- +### Docker +# ----------------------------------------------------------------------------- + +# +# All containers +# +DOCKER_CONTAINER_OWNER=meritoo +DOCKER_CONTAINER_PROJECT=common-library + +# +# PHP configuration: +# - timezone +# +TIMEZONE=Europe/Warsaw diff --git a/.gitignore b/.gitignore index e87265b..1717b0b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,3 @@ -# ------------------------------------------------------------------------------ -### Environment-related parameters -# ------------------------------------------------------------------------------ -.env - - # ------------------------------------------------------------------------------ ### Vendors # ------------------------------------------------------------------------------ From c4e09f77a3c243590688f978ef6a9854ebf2aa55 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 2 Jun 2019 19:17:39 +0200 Subject: [PATCH 063/137] Update Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c8eebf..09f9de7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ Common and useful classes, methods, exceptions etc. # 1.0.6 1. Use `.env` instead of `.env.dist` +2. Docker > use images (instead of Dockerfiles) +3. composer > squizlabs/php_codesniffer package > use ^3.4 (instead of ^2.9) # 1.0.5 From 3b81d0d9321984efd2e69d5bdb20c998b2e663b1 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 17 Jun 2019 08:43:40 +0200 Subject: [PATCH 064/137] Do not require name of class by BaseTestCaseTrait::assertMethodVisibilityAndArguments() method --- CHANGELOG.md | 1 + src/Traits/Test/Base/BaseTestCaseTrait.php | 11 ----------- tests/Collection/CollectionTest.php | 1 - 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09f9de7..c694dcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Common and useful classes, methods, exceptions etc. 1. Use `.env` instead of `.env.dist` 2. Docker > use images (instead of Dockerfiles) 3. composer > squizlabs/php_codesniffer package > use ^3.4 (instead of ^2.9) +4. Do not require name of class by BaseTestCaseTrait::assertMethodVisibilityAndArguments() method # 1.0.5 diff --git a/src/Traits/Test/Base/BaseTestCaseTrait.php b/src/Traits/Test/Base/BaseTestCaseTrait.php index 504922d..554291f 100644 --- a/src/Traits/Test/Base/BaseTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTestCaseTrait.php @@ -164,7 +164,6 @@ trait BaseTestCaseTrait /** * Verifies visibility and arguments of method * - * @param string $className Fully-qualified name of class that contains method to verify * @param ReflectionMethod $method Name of method or just the method to verify * @param string $visibilityType Expected visibility of verified method. One of OopVisibilityType * class constants. @@ -180,7 +179,6 @@ trait BaseTestCaseTrait * - instance of ReflectionMethod - just the method (provided by ReflectionClass::getMethod() method) */ protected static function assertMethodVisibilityAndArguments( - string $className, ReflectionMethod $method, string $visibilityType, int $argumentsCount = 0, @@ -191,14 +189,6 @@ trait BaseTestCaseTrait throw UnknownOopVisibilityTypeException::createException($visibilityType); } - $reflection = new ReflectionClass($className); - - // Name of method provided only? - // Let's find instance of the method (based on reflection) - if (!$method instanceof ReflectionMethod) { - $method = $reflection->getMethod($method); - } - switch ($visibilityType) { case OopVisibilityType::IS_PUBLIC: static::assertTrue($method->isPublic()); @@ -243,7 +233,6 @@ trait BaseTestCaseTrait } static::assertMethodVisibilityAndArguments( - $className, $method, $visibilityType, $argumentsCount, diff --git a/tests/Collection/CollectionTest.php b/tests/Collection/CollectionTest.php index 1b0bef1..96e61ab 100644 --- a/tests/Collection/CollectionTest.php +++ b/tests/Collection/CollectionTest.php @@ -332,7 +332,6 @@ class CollectionTest extends BaseTestCase $method = $reflectionClass->getMethod('exists'); static::assertMethodVisibilityAndArguments( - Collection::class, $method, OopVisibilityType::IS_PRIVATE, 1, From 5678b5b22a983d0e307fafb5872acb8093959688 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 20 Jun 2019 18:58:20 +0200 Subject: [PATCH 065/137] Fix "Found a contradiction when evaluating $fullBundleName and trying to reconcile type 'string' to !string" bug pointed by Psalm --- src/Utilities/Bundle.php | 6 +----- tests/Utilities/BundleTest.php | 10 ++-------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/Utilities/Bundle.php b/src/Utilities/Bundle.php index dfbde0e..83eade3 100644 --- a/src/Utilities/Bundle.php +++ b/src/Utilities/Bundle.php @@ -61,14 +61,10 @@ class Bundle * @throws IncorrectBundleNameException * @return null|string */ - public static function getShortBundleName($fullBundleName) + public static function getShortBundleName(string $fullBundleName): ?string { // Oops, given name of bundle is invalid if (!Regex::isValidBundleName($fullBundleName)) { - if (!is_string($fullBundleName)) { - $fullBundleName = gettype($fullBundleName); - } - throw new IncorrectBundleNameException($fullBundleName); } diff --git a/tests/Utilities/BundleTest.php b/tests/Utilities/BundleTest.php index 12507ee..9e665dc 100644 --- a/tests/Utilities/BundleTest.php +++ b/tests/Utilities/BundleTest.php @@ -85,16 +85,10 @@ class BundleTest extends BaseTestCase self::assertEquals($expected, Bundle::getBundleViewPath($viewPath, $bundleName, $extension)); } - /** - * @param mixed $emptyValue Empty value, e.g. "" - * - * @throws IncorrectBundleNameException - * @dataProvider provideEmptyValue - */ - public function testGetShortBundleNameUsingEmptyValue($emptyValue) + public function testGetShortBundleNameUsingEmptyValue(): void { $this->expectException(IncorrectBundleNameException::class); - Bundle::getShortBundleName($emptyValue); + Bundle::getShortBundleName(''); } /** From 1ac1a221ec63134e4ecc818f7d1eac0a4060e1fe Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 20 Jun 2019 19:25:34 +0200 Subject: [PATCH 066/137] Minor refactoring --- src/Utilities/Bundle.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Utilities/Bundle.php b/src/Utilities/Bundle.php index 83eade3..b1ecb32 100644 --- a/src/Utilities/Bundle.php +++ b/src/Utilities/Bundle.php @@ -21,18 +21,18 @@ class Bundle /** * Returns path of given bundle to view / template with given extension * - * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" + * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template". Extension is not required. * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" * @param string $extension (optional) Extension of the view / template (default: "html.twig") * @throws IncorrectBundleNameException * @return null|string */ - public static function getBundleViewPath($viewPath, $bundleName, $extension = 'html.twig') - { - /* - * Unknown path, extension of the view / template or name of the bundle? - * Nothing to do - */ + public static function getBundleViewPath( + string $viewPath, + string $bundleName, + string $extension = 'html.twig' + ): ?string { + // Nothing to do, because at least one unknown argument provided if (empty($viewPath) || empty($bundleName) || empty($extension)) { return null; } @@ -48,10 +48,10 @@ class Bundle } // Prepare short name of bundle and path of view / template with "/" (instead of ":") - $shortBundleName = static::getShortBundleName($bundleName); - $viewPath = str_replace(':', '/', $viewPath); + $shortName = static::getShortBundleName($bundleName); + $path = str_replace(':', '/', $viewPath); - return sprintf('@%s/%s', $shortBundleName, $viewPath); + return sprintf('@%s/%s', $shortName, $path); } /** From 6efbf940a3d222db353fa711022bfb1d32bdefa6 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 20 Jun 2019 20:05:56 +0200 Subject: [PATCH 067/137] Fix "Found a redundant condition when evaluating docblock-defined type $composerJsonPath and trying to reconcile type 'string' to string" bug pointed by Psalm --- src/Utilities/Composer.php | 13 ++++--------- tests/Utilities/ComposerTest.php | 20 ++++++-------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/Utilities/Composer.php b/src/Utilities/Composer.php index 1e423e8..24ee2ce 100644 --- a/src/Utilities/Composer.php +++ b/src/Utilities/Composer.php @@ -30,14 +30,9 @@ class Composer * @param string $nodeName Name of node who value should be returned * @return null|string */ - public static function getValue($composerJsonPath, $nodeName) + public static function getValue(string $composerJsonPath, string $nodeName): ?string { - $composerJsonString = is_string($composerJsonPath); - $composerJsonReadable = false; - - if ($composerJsonString) { - $composerJsonReadable = is_readable($composerJsonPath); - } + $composerJsonReadable = is_readable($composerJsonPath); /* * Provided path or name of node are invalid? @@ -46,12 +41,12 @@ class Composer * * Nothing to do */ - if (!$composerJsonString || !is_string($nodeName) || !$composerJsonReadable || empty($nodeName)) { + if (!$composerJsonReadable || empty($nodeName)) { return null; } $content = file_get_contents($composerJsonPath); - $data = json_decode($content); + $data = json_decode($content, false); /* * Unknown data from the composer.json file or there is no node with given name? diff --git a/tests/Utilities/ComposerTest.php b/tests/Utilities/ComposerTest.php index 7bf6602..c4a9252 100644 --- a/tests/Utilities/ComposerTest.php +++ b/tests/Utilities/ComposerTest.php @@ -35,23 +35,15 @@ class ComposerTest extends BaseTestCase static::assertHasNoConstructor(Composer::class); } - /** - * @param string $composerJsonPath Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testGetValueNotExistingComposerJson($composerJsonPath) + public function testGetValueNotExistingComposerJson(): void { - self::assertNull(Composer::getValue($composerJsonPath, '')); + self::assertNull(Composer::getValue('', '')); self::assertNull(Composer::getValue('not/existing/composer.json', '')); } - /** - * @param string $nodeName Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testGetValueNotExistingNode($nodeName) + public function testGetValueNotExistingNode(): void { - self::assertNull(Composer::getValue($this->composerJsonPath, $nodeName)); + self::assertNull(Composer::getValue($this->composerJsonPath, '')); self::assertNull(Composer::getValue($this->composerJsonPath, 'not_existing_node')); } @@ -61,7 +53,7 @@ class ComposerTest extends BaseTestCase * * @dataProvider getExistingNode */ - public function testGetValueExistingNode($nodeName, $nodeValue) + public function testGetValueExistingNode(string $nodeName, string $nodeValue): void { self::assertEquals($nodeValue, Composer::getValue($this->composerJsonPath, $nodeName)); } @@ -71,7 +63,7 @@ class ComposerTest extends BaseTestCase * * @return Generator */ - public function getExistingNode() + public function getExistingNode(): Generator { yield[ 'name', From a1c3ba8543e2351f0781614de402f5a0f868c38c Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 20 Jun 2019 20:21:14 +0200 Subject: [PATCH 068/137] Fix "Cannot call method sub on possibly null value" bug pointed by Psalm --- src/Utilities/Date.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index 6b614f6..4d950fa 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -125,7 +125,10 @@ class Date if (null !== $nextMonth) { $dateEnd = $nextMonth->getStartDate(); - $dateEnd->sub(new DateInterval('P1D')); + + if (null !== $dateEnd) { + $dateEnd->sub(new DateInterval('P1D')); + } } break; From c0998ac5b98f358dedcb84213dfb51ca93c2c940 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 20 Jun 2019 20:29:17 +0200 Subject: [PATCH 069/137] Fix "Argument 1 of DateTime::setdate expects int, string|false provided" bug pointed by Psalm --- src/Utilities/Date.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index 4d950fa..30ff7d1 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -160,7 +160,7 @@ class Date $dateEnd->modify($modifyString); } - $year = $dateStart->format('Y'); + $year = (int)$dateStart->format('Y'); $dateStart->setDate($year, 1, 1); $dateEnd->setDate($year, 12, 31); From 4ddc299e5bd5383da8a0dd653a38ccad832a150b Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 20 Jun 2019 21:04:44 +0200 Subject: [PATCH 070/137] Fix "Cannot call method add on possibly null value" bug pointed by Psalm --- src/Utilities/Date.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index 30ff7d1..421b411 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -120,7 +120,10 @@ class Date if (null !== $lastMonth) { $dateStart = $lastMonth->getEndDate(); - $dateStart->add(new DateInterval('P1D')); + + if (null !== $dateStart) { + $dateStart->add(new DateInterval('P1D')); + } } if (null !== $nextMonth) { From c5a68b54af1e8214f4b35e09ad33ca07cc033bac Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 20 Jun 2019 21:11:00 +0200 Subject: [PATCH 071/137] Fix "Argument 1 of Meritoo\\Common\\Utilities\\Date::getdayofweek expects int, string|false provided" bug pointed by Psalm --- src/Utilities/Date.php | 24 ++++++++++-------------- tests/Utilities/DateTest.php | 18 +++--------------- 2 files changed, 13 insertions(+), 29 deletions(-) diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index 421b411..e8d870d 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -235,20 +235,20 @@ class Date * * @return int */ - public static function getCurrentDayOfWeek() + public static function getCurrentDayOfWeek(): int { $now = new DateTime(); - $year = $now->format('Y'); - $month = $now->format('m'); - $day = $now->format('d'); + $year = (int)$now->format('Y'); + $month = (int)$now->format('m'); + $day = (int)$now->format('d'); return self::getDayOfWeek($year, $month, $day); } /** * Returns day of week (number 0 to 6, 0 - sunday, 6 - saturday). - * Based on the Zeller's algorithm (http://pl.wikipedia.org/wiki/Kalendarz_wieczny). + * Based on the Zeller's algorithm (https://en.wikipedia.org/wiki/Perpetual_calendar). * * @param int $year The year value * @param int $month The month value @@ -257,12 +257,8 @@ class Date * @throws UnknownDatePartTypeException * @return int */ - public static function getDayOfWeek($year, $month, $day) + public static function getDayOfWeek(int $year, int $month, int $day): int { - $year = (int)$year; - $month = (int)$month; - $day = (int)$day; - // Oops, given year is incorrect if ($year <= 0) { throw UnknownDatePartTypeException::createException(DatePartType::YEAR, $year); @@ -299,13 +295,13 @@ class Date * * @return string */ - public static function getCurrentDayOfWeekName() + public static function getCurrentDayOfWeekName(): string { $now = new DateTime(); - $year = $now->format('Y'); - $month = $now->format('m'); - $day = $now->format('d'); + $year = (int)$now->format('Y'); + $month = (int)$now->format('m'); + $day = (int)$now->format('d'); return self::getDayOfWeekName($year, $month, $day); } diff --git a/tests/Utilities/DateTest.php b/tests/Utilities/DateTest.php index a899f48..a827eb0 100644 --- a/tests/Utilities/DateTest.php +++ b/tests/Utilities/DateTest.php @@ -228,7 +228,7 @@ class DateTest extends BaseTestCase * * @dataProvider provideIncorrectYearMonthDay */ - public function testGetDayOfWeekIncorrectValues($year, $month, $day): void + public function testGetDayOfWeekIncorrectValues(int $year, int $month, int $day): void { $this->expectException(UnknownDatePartTypeException::class); self::assertEmpty(Date::getDayOfWeek($year, $month, $day)); @@ -241,7 +241,7 @@ class DateTest extends BaseTestCase * * @dataProvider provideYearMonthDay */ - public function testGetDayOfWeek($year, $month, $day): void + public function testGetDayOfWeek(int $year, int $month, int $day): void { self::assertRegExp('/^[0-6]{1}$/', (string)Date::getDayOfWeek($year, $month, $day)); } @@ -766,20 +766,8 @@ class DateTest extends BaseTestCase * * @return Generator */ - public function provideIncorrectYearMonthDay() + public function provideIncorrectYearMonthDay(): Generator { - yield[ - null, - null, - null, - ]; - - yield[ - '', - '', - '', - ]; - yield[ 0, 0, From a2c875556e18b16892077a47839926934e92bda8 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 20 Jun 2019 21:32:03 +0200 Subject: [PATCH 072/137] Move validation of year, month and day to separate methods --- src/Utilities/Date.php | 65 +++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index e8d870d..27037f0 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -259,20 +259,9 @@ class Date */ public static function getDayOfWeek(int $year, int $month, int $day): int { - // Oops, given year is incorrect - if ($year <= 0) { - throw UnknownDatePartTypeException::createException(DatePartType::YEAR, $year); - } - - // Oops, given month is incorrect - if ($month < 1 || $month > 12) { - throw UnknownDatePartTypeException::createException(DatePartType::MONTH, $month); - } - - // Oops, given day is incorrect - if ($day < 1 || $day > 31) { - throw UnknownDatePartTypeException::createException(DatePartType::DAY, $day); - } + static::validateYear($year); + static::validateMonth($month); + static::validateDay($day); if ($month < 3) { $count = 0; @@ -705,4 +694,52 @@ class Date return $fromFormat instanceof DateTime; } + + /** + * Verifies/validates given year + * + * @param int $year Year to verify/validate + * @throws UnknownDatePartTypeException + */ + private static function validateYear(int $year): void + { + // Oops, given year is incorrect + if ($year >= 0) { + return; + } + + throw UnknownDatePartTypeException::createException(DatePartType::YEAR, $year); + } + + /** + * Verifies/validates given month + * + * @param int $month Month to verify/validate + * @throws UnknownDatePartTypeException + */ + private static function validateMonth(int $month): void + { + // Oops, given month is incorrect + if ($month >= 1 && $month <= 12) { + return; + } + + throw UnknownDatePartTypeException::createException(DatePartType::MONTH, $month); + } + + /** + * Verifies/validates given day + * + * @param int $day Day to verify/validate + * @throws UnknownDatePartTypeException + */ + private static function validateDay(int $day): void + { + // Oops, given day is incorrect + if ($day >= 1 && $day <= 31) { + return; + } + + throw UnknownDatePartTypeException::createException(DatePartType::DAY, $day); + } } From b251bcec0e12d52d8724d0192bae2076f25a17c0 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 20 Jun 2019 21:36:31 +0200 Subject: [PATCH 073/137] Update project configuration (project files related to IDE) --- .idea/inspectionProfiles/Project_Default.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 68acef7..82b4c38 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -70,6 +70,8 @@ - + From a86a10c51e98b0d9d237a4cdcd8067484c9af0eb Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 10 Aug 2019 21:32:40 +0200 Subject: [PATCH 077/137] Increase Mutation Score Indicator (MSI) by removing "src/Exception/Reflection/CannotResolveClassNameException.php:29 [M] TrueValue" mutant --- .../CannotResolveClassNameException.php | 11 ++++---- src/Utilities/Reflection.php | 6 ++--- .../CannotResolveClassNameExceptionTest.php | 26 +++++++++++-------- tests/Utilities/ReflectionTest.php | 11 +++----- 4 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/Exception/Reflection/CannotResolveClassNameException.php b/src/Exception/Reflection/CannotResolveClassNameException.php index ff5191f..faaf4d0 100644 --- a/src/Exception/Reflection/CannotResolveClassNameException.php +++ b/src/Exception/Reflection/CannotResolveClassNameException.php @@ -21,13 +21,12 @@ class CannotResolveClassNameException extends Exception /** * Creates exception * - * @param array|object|string $source Source of the class's / trait's name. It can be an array of objects, - * namespaces, object or namespace. - * @param bool $forClass (optional) If is set to true, message of this exception for class is - * prepared. Otherwise - for trait. + * @param string $source Source of name of the class or trait + * @param bool $forClass (optional) If is set to true, message of this exception for class is prepared. Otherwise + * - for trait. * @return CannotResolveClassNameException */ - public static function create($source, bool $forClass = true): CannotResolveClassNameException + public static function create(string $source, bool $forClass = true): CannotResolveClassNameException { $forWho = 'trait'; $value = ''; @@ -37,7 +36,7 @@ class CannotResolveClassNameException extends Exception } if (is_scalar($source)) { - $value = sprintf(' %s', (string)$source); + $value = sprintf(' %s', $source); } $template = 'Name of %s from given \'%s\'%s cannot be resolved. Is there everything ok?'; diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index 82c522a..96ccce7 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -437,7 +437,7 @@ class Reflection // Oops, cannot resolve class if (null === $className) { - throw CannotResolveClassNameException::create($class); + throw CannotResolveClassNameException::create(''); } $childClasses = []; @@ -541,12 +541,12 @@ class Reflection // Oops, cannot resolve class if (null === $className || '' === $className) { - throw CannotResolveClassNameException::create($class); + throw CannotResolveClassNameException::create(''); } // Oops, cannot resolve trait if (null === $traitName || '' === $traitName) { - throw new CannotResolveClassNameException($class, false); + throw CannotResolveClassNameException::create('', false); } $reflection = new ReflectionClass($className); diff --git a/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php b/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php index 8106936..afce710 100644 --- a/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php +++ b/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php @@ -34,16 +34,23 @@ class CannotResolveClassNameExceptionTest extends BaseTestCase ); } + public function testCreateUsingDefaults(): void + { + $exception = CannotResolveClassNameException::create(stdClass::class); + $expectedMessage = 'Name of class from given \'string\' stdClass cannot be resolved. Is there everything ok?'; + + static::assertSame($expectedMessage, $exception->getMessage()); + } + /** - * @param array|object|string $source Source of the class's / trait's name. It can be an array of objects, - * namespaces, object or namespace. - * @param bool $forClass If is set to true, message of this exception for class is prepared. - * Otherwise - for trait. - * @param string $expectedMessage Expected exception's message + * @param string $source Source of name of the class or trait + * @param bool $forClass (optional) If is set to true, message of this exception for class is prepared. + * Otherwise - for trait. + * @param string $expectedMessage Expected exception's message * * @dataProvider provideClassName */ - public function testCreate($source, bool $forClass, string $expectedMessage): void + public function testCreate(string $source, bool $forClass, string $expectedMessage): void { $exception = CannotResolveClassNameException::create($source, $forClass); static::assertSame($expectedMessage, $exception->getMessage()); @@ -70,12 +77,9 @@ class CannotResolveClassNameExceptionTest extends BaseTestCase ]; yield[ - [ - new stdClass(), - new stdClass(), - ], + stdClass::class, true, - 'Name of class from given \'array\' cannot be resolved. Is there everything ok?', + 'Name of class from given \'string\' stdClass cannot be resolved. Is there everything ok?', ]; } } diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 7a0aaef..edf5344 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -125,7 +125,7 @@ class ReflectionTest extends BaseTestCase * @param mixed $invalidClass Empty value, e.g. "" * @dataProvider provideEmptyValue */ - public function testGetChildClassesInvalidClass($invalidClass) + public function testGetChildClassesInvalidClass($invalidClass): void { $this->expectException(CannotResolveClassNameException::class); @@ -206,7 +206,7 @@ class ReflectionTest extends BaseTestCase * * @dataProvider provideInvalidClassAndTrait */ - public function testUsesTraitInvalidClass($class, $trait) + public function testUsesTraitInvalidClass($class, $trait): void { $this->expectException(CannotResolveClassNameException::class); self::assertNull(Reflection::usesTrait($class, $trait)); @@ -577,7 +577,7 @@ class ReflectionTest extends BaseTestCase * * @return Generator */ - public function provideInvalidClassAndTrait() + public function provideInvalidClassAndTrait(): ?Generator { yield[ '', @@ -593,11 +593,6 @@ class ReflectionTest extends BaseTestCase 0, 0, ]; - - yield[ - [], - [], - ]; } /** From 462625caff7978477176ed9354b001503c82b5aa Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 11 Aug 2019 12:24:55 +0200 Subject: [PATCH 078/137] Missing test of Reflection::getConstants() method --- tests/Utilities/ReflectionTest.php | 34 ++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index edf5344..44186d5 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -458,6 +458,17 @@ class ReflectionTest extends BaseTestCase static::assertNull(Reflection::getConstantValue(H::class, 'users')); } + /** + * @param object|string $class The object or name of object's class + * @param array $expected Expected constants + * + * @dataProvider provideClassToGetConstants + */ + public function testGetConstants($class, array $expected): void + { + static::assertSame($expected, Reflection::getConstants($class)); + } + public function testGetConstantValue() { static::assertSame(H::LOREM, Reflection::getConstantValue(H::class, 'LOREM')); @@ -749,4 +760,27 @@ class ReflectionTest extends BaseTestCase ], ]; } + + public function provideClassToGetConstants(): ?Generator + { + yield[ + new \stdClass(), + [], + ]; + + yield[ + \stdClass::class, + [], + ]; + + yield[ + H::class, + [ + 'DOLOR' => 'sit', + 'LOREM' => 'ipsum', + 'MAX_USERS' => 5, + 'MIN_USERS' => 2, + ], + ]; + } } From fe6ec278e3270319c79943518990ebedcd69ab3e Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 11 Aug 2019 12:30:16 +0200 Subject: [PATCH 079/137] Minor refactoring --- tests/Type/Base/BaseTypeTest.php | 4 +- tests/Type/DatePeriodTest.php | 2 +- tests/Utilities/ReflectionTest.php | 142 ++++++++++++----------------- 3 files changed, 62 insertions(+), 86 deletions(-) diff --git a/tests/Type/Base/BaseTypeTest.php b/tests/Type/Base/BaseTypeTest.php index 94af1bd..282c59f 100644 --- a/tests/Type/Base/BaseTypeTest.php +++ b/tests/Type/Base/BaseTypeTest.php @@ -23,7 +23,7 @@ use Meritoo\Common\Type\Base\BaseType; */ class BaseTypeTest extends BaseTestCase { - public function testConstructor() + public function testConstructor(): void { static::assertHasNoConstructor(BaseType::class); } @@ -34,7 +34,7 @@ class BaseTypeTest extends BaseTestCase * * @dataProvider provideType */ - public function testGetAll(BaseType $type, array $expectedTypes) + public function testGetAll(BaseType $type, array $expectedTypes): void { $all = $type->getAll(); self::assertEquals($expectedTypes, $all); diff --git a/tests/Type/DatePeriodTest.php b/tests/Type/DatePeriodTest.php index bcb9ca2..5f6f0c0 100644 --- a/tests/Type/DatePeriodTest.php +++ b/tests/Type/DatePeriodTest.php @@ -72,7 +72,7 @@ class DatePeriodTest extends BaseTypeTestCase * * @dataProvider provideDatePeriodAndIncorrectDateFormat */ - public function testGetFormattedDateIncorrectDateFormat(DatePeriod $period, $format): void + public function testGetFormattedDateUsingIncorrectDateFormat(DatePeriod $period, $format): void { self::assertEquals('', $period->getFormattedDate($format)); } diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 44186d5..5c5b6b1 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -28,6 +28,7 @@ use Meritoo\Test\Common\Utilities\Reflection\H; use Meritoo\Test\Common\Utilities\Reflection\I; use Meritoo\Test\Common\Utilities\Reflection\J; use ReflectionProperty; +use stdClass; /** * Test case of the useful reflection methods @@ -40,7 +41,7 @@ use ReflectionProperty; */ class ReflectionTest extends BaseTestCase { - public function testConstructor() + public function testConstructor(): void { static::assertHasNoConstructor(Reflection::class); } @@ -82,7 +83,7 @@ class ReflectionTest extends BaseTestCase public function testGetClassWhileNamespaceContainsClassName(): void { self::assertEquals( - 'Meritoo\Common\Collection\Collection', + Collection::class, Reflection::getClassName(Collection::class) ); @@ -113,7 +114,7 @@ class ReflectionTest extends BaseTestCase /** * A case when namespace of class contains name of class (name of class is duplicated, occurs twice) */ - public function testGetClassNamespaceWhileNamespaceContainsClassName() + public function testGetClassNamespaceWhileNamespaceContainsClassName(): void { self::assertEquals( 'Meritoo\Common\Collection', @@ -133,13 +134,13 @@ class ReflectionTest extends BaseTestCase self::assertNull(Reflection::getChildClasses(123)); } - public function testGetChildClassesNotExistingClass() + public function testGetChildClassesNotExistingClass(): void { $this->expectException(CannotResolveClassNameException::class); self::assertEquals('', Reflection::getChildClasses('xyz')); } - public function testGetChildClassesExistingClass() + public function testGetChildClassesExistingClass(): void { /* * Attention. I have to create instances of these classes to load them and be available while using @@ -164,13 +165,13 @@ class ReflectionTest extends BaseTestCase self::assertEquals($effect, Reflection::getChildClasses(A::class)); } - public function testGetOneChildClassWithMissingChildClasses() + public function testGetOneChildClassWithMissingChildClasses(): void { $this->expectException(MissingChildClassesException::class); self::assertEquals('LoremIpsum', Reflection::getOneChildClass(C::class)); } - public function testGetOneChildClassWithTooManyChildClasses() + public function testGetOneChildClassWithTooManyChildClasses(): void { // Required to get all classes by get_declared_classes() function and avoid failure: // @@ -182,7 +183,7 @@ class ReflectionTest extends BaseTestCase Reflection::getOneChildClass(A::class); } - public function testGetOneChildClass() + public function testGetOneChildClass(): void { // Required to get all classes by get_declared_classes() function and avoid throw of // Meritoo\Common\Exception\Reflection\MissingChildClassesException exception @@ -191,7 +192,7 @@ class ReflectionTest extends BaseTestCase self::assertEquals(C::class, Reflection::getOneChildClass(B::class)); } - public function testGetMethods() + public function testGetMethods(): void { self::assertCount(1, Reflection::getMethods(B::class, true)); self::assertCount(3, Reflection::getMethods(B::class)); @@ -216,13 +217,13 @@ class ReflectionTest extends BaseTestCase * @param mixed $trait Empty value, e.g. "" * @dataProvider provideEmptyValue */ - public function testUsesTraitInvalidTrait($trait) + public function testUsesTraitInvalidTrait($trait): void { $this->expectException(CannotResolveClassNameException::class); self::assertNull(Reflection::usesTrait(DateTime::class, $trait)); } - public function testUsesTraitExistingClass() + public function testUsesTraitExistingClass(): void { self::assertTrue(Reflection::usesTrait(A::class, E::class)); self::assertFalse(Reflection::usesTrait(B::class, E::class)); @@ -230,7 +231,7 @@ class ReflectionTest extends BaseTestCase self::assertFalse(Reflection::usesTrait(D::class, E::class)); } - public function testUsesTraitExistingClassAndVerifyParents() + public function testUsesTraitExistingClassAndVerifyParents(): void { self::assertTrue(Reflection::usesTrait(A::class, E::class, true)); self::assertTrue(Reflection::usesTrait(B::class, E::class, true)); @@ -238,12 +239,12 @@ class ReflectionTest extends BaseTestCase self::assertFalse(Reflection::usesTrait(D::class, E::class, true)); } - public function testGetProperties() + public function testGetProperties(): void { self::assertCount(1, Reflection::getProperties(B::class)); } - public function testGetPropertiesUsingFilter() + public function testGetPropertiesUsingFilter(): void { self::assertCount( 1, @@ -261,24 +262,24 @@ class ReflectionTest extends BaseTestCase ); } - public function testGetPropertiesWithParents() + public function testGetPropertiesWithParents(): void { self::assertCount(2, Reflection::getProperties(B::class, null, true)); } - public function testGetPropertyValueOfNotExistingProperty() + public function testGetPropertyValueOfNotExistingProperty(): void { self::assertNull(Reflection::getPropertyValue(new D(), 'something')); self::assertNull(Reflection::getPropertyValue(new D(), 'something', true)); } - public function testGetPropertyValueFromChain() + public function testGetPropertyValueFromChain(): void { $f = new F(1000, 'New York', 'USA', 'john.scott'); self::assertEquals('John', Reflection::getPropertyValue($f, 'g.firstName')); } - public function testGetPropertyValueWithPublicGetter() + public function testGetPropertyValueWithPublicGetter(): void { $country = 'USA'; $f = new F(1000, 'New York', $country, 'john.scott'); @@ -286,7 +287,7 @@ class ReflectionTest extends BaseTestCase self::assertEquals($country, Reflection::getPropertyValue($f, 'country')); } - public function testGetPropertyValueWithProtectedGetter() + public function testGetPropertyValueWithProtectedGetter(): void { $city = 'New York'; $f = new F(1000, $city, 'USA', 'john.scott'); @@ -294,7 +295,7 @@ class ReflectionTest extends BaseTestCase self::assertEquals($city, Reflection::getPropertyValue($f, 'city')); } - public function testGetPropertyValueWithPrivateGetter() + public function testGetPropertyValueWithPrivateGetter(): void { $accountBalance = 1000; $f = new F($accountBalance, 'New York', 'USA', 'john.scott'); @@ -302,7 +303,7 @@ class ReflectionTest extends BaseTestCase self::assertEquals($accountBalance, Reflection::getPropertyValue($f, 'accountBalance')); } - public function testGetPropertyValueWithoutGetter() + public function testGetPropertyValueWithoutGetter(): void { $username = 'john.scott'; $f = new F(1000, 'New York', 'USA', $username); @@ -316,19 +317,19 @@ class ReflectionTest extends BaseTestCase self::assertEquals(1, Reflection::getPropertyValue($c, 'count', true)); } - public function testGetPropertyValuesFromEmptySource() + public function testGetPropertyValuesFromEmptySource(): void { self::assertEquals([], Reflection::getPropertyValues([], 'something')); self::assertEquals([], Reflection::getPropertyValues(new Collection(), 'something')); } - public function testGetPropertyValuesOfNotExistingPropertyFromSingleObject() + public function testGetPropertyValuesOfNotExistingPropertyFromSingleObject(): void { self::assertEquals([], Reflection::getPropertyValues(new D(), 'something')); self::assertEquals([], Reflection::getPropertyValues(new D(), 'something', true)); } - public function testGetPropertyValuesOfNotExistingPropertyFromMultipleObjects() + public function testGetPropertyValuesOfNotExistingPropertyFromMultipleObjects(): void { $objects = [ new A(), @@ -349,13 +350,13 @@ class ReflectionTest extends BaseTestCase self::assertEquals([], Reflection::getPropertyValues($collection, 'something', true)); } - public function testGetPropertyValuesOfExistingPropertyFromSingleObject() + public function testGetPropertyValuesOfExistingPropertyFromSingleObject(): void { self::assertEquals(['John'], Reflection::getPropertyValues(new G(), 'firstName')); self::assertEquals(['John'], Reflection::getPropertyValues(new G(), 'firstName', true)); } - public function testGetPropertyValuesOfExistingPropertyFromMultipleObjects() + public function testGetPropertyValuesOfExistingPropertyFromMultipleObjects(): void { $expected = [ 'New York', @@ -378,7 +379,7 @@ class ReflectionTest extends BaseTestCase self::assertEquals($expected, Reflection::getPropertyValues($collection, 'city', true)); } - public function testGetPropertyValuesFromChainAndSingleObject() + public function testGetPropertyValuesFromChainAndSingleObject(): void { $f = new F(1000, 'New York', 'USA', 'john.scott'); $j = new J(); @@ -390,7 +391,7 @@ class ReflectionTest extends BaseTestCase self::assertEquals(['John'], Reflection::getPropertyValues($j, 'f.g.firstName', true)); } - public function testGetPropertyValuesFromChainAndMultipleObjects() + public function testGetPropertyValuesFromChainAndMultipleObjects(): void { $expected = [ 'John', @@ -413,47 +414,47 @@ class ReflectionTest extends BaseTestCase self::assertEquals($expected, Reflection::getPropertyValues($collection, 'g.firstName', true)); } - public function testGetMaxNumberConstantUsingClassWithoutConstants() + public function testGetMaxNumberConstantUsingClassWithoutConstants(): void { static::assertNull(Reflection::getMaxNumberConstant(A::class)); } - public function testGetMaxNumberConstant() + public function testGetMaxNumberConstant(): void { static::assertSame(5, Reflection::getMaxNumberConstant(H::class)); } - public function testHasMethodUsingClassWithoutMethod() + public function testHasMethodUsingClassWithoutMethod(): void { static::assertFalse(Reflection::hasMethod(A::class, 'getUser')); } - public function testHasMethod() + public function testHasMethod(): void { static::assertTrue(Reflection::hasMethod(A::class, 'getCount')); } - public function testHasPropertyUsingClassWithoutProperty() + public function testHasPropertyUsingClassWithoutProperty(): void { static::assertFalse(Reflection::hasProperty(A::class, 'users')); } - public function testHasProperty() + public function testHasProperty(): void { static::assertTrue(Reflection::hasProperty(A::class, 'count')); } - public function testHasConstantUsingClassWithoutConstant() + public function testHasConstantUsingClassWithoutConstant(): void { static::assertFalse(Reflection::hasConstant(H::class, 'users')); } - public function testHasConstant() + public function testHasConstant(): void { static::assertTrue(Reflection::hasConstant(H::class, 'LOREM')); } - public function testGetConstantValueUsingClassWithoutConstant() + public function testGetConstantValueUsingClassWithoutConstant(): void { static::assertNull(Reflection::getConstantValue(H::class, 'users')); } @@ -469,37 +470,37 @@ class ReflectionTest extends BaseTestCase static::assertSame($expected, Reflection::getConstants($class)); } - public function testGetConstantValue() + public function testGetConstantValue(): void { static::assertSame(H::LOREM, Reflection::getConstantValue(H::class, 'LOREM')); } - public function testIsInterfaceImplementedUsingClassWithoutInterface() + public function testIsInterfaceImplementedUsingClassWithoutInterface(): void { static::assertFalse(Reflection::isInterfaceImplemented(A::class, I::class)); } - public function testIsInterfaceImplemented() + public function testIsInterfaceImplemented(): void { static::assertTrue(Reflection::isInterfaceImplemented(B::class, I::class)); } - public function testIsChildOfClassUsingClassWithoutChildClass() + public function testIsChildOfClassUsingClassWithoutChildClass(): void { static::assertFalse(Reflection::isChildOfClass(A::class, B::class)); } - public function testIsChildOfClass() + public function testIsChildOfClass(): void { static::assertTrue(Reflection::isChildOfClass(B::class, A::class)); } - public function testGetPropertyUsingClassWithoutProperty() + public function testGetPropertyUsingClassWithoutProperty(): void { static::assertNull(Reflection::getProperty(A::class, 'lorem')); } - public function testGetPropertyUsingClassWithPrivateProperty() + public function testGetPropertyUsingClassWithPrivateProperty(): void { $property = Reflection::getProperty(A::class, 'count', ReflectionProperty::IS_PRIVATE); @@ -508,7 +509,7 @@ class ReflectionTest extends BaseTestCase static::assertSame('count', $property->getName()); } - public function testGetPropertyUsingClassWithProtectedProperty() + public function testGetPropertyUsingClassWithProtectedProperty(): void { $property = Reflection::getProperty(B::class, 'name', ReflectionProperty::IS_PROTECTED); @@ -523,7 +524,7 @@ class ReflectionTest extends BaseTestCase * * @dataProvider provideObjectAndNotExistingProperty */ - public function testSetPropertyValueUsingNotExistingProperty($object, $property) + public function testSetPropertyValueUsingNotExistingProperty($object, $property): void { $this->expectException(NotExistingPropertyException::class); Reflection::setPropertyValue($object, $property, 'test test test'); @@ -536,7 +537,7 @@ class ReflectionTest extends BaseTestCase * * @dataProvider provideObjectPropertyAndValue */ - public function testSetPropertyValue($object, $property, $value) + public function testSetPropertyValue($object, $property, $value): void { $oldValue = Reflection::getPropertyValue($object, $property); Reflection::setPropertyValue($object, $property, $value); @@ -546,7 +547,7 @@ class ReflectionTest extends BaseTestCase static::assertSame($newValue, $value); } - public function testSetPropertiesValuesWithoutProperties() + public function testSetPropertiesValuesWithoutProperties(): void { $object = new G(); Reflection::setPropertiesValues($object, []); @@ -561,7 +562,7 @@ class ReflectionTest extends BaseTestCase * * @dataProvider provideObjectAndNotExistingProperties */ - public function testSetPropertiesValuesUsingNotExistingProperties($object, array $propertiesValues) + public function testSetPropertiesValuesUsingNotExistingProperties($object, array $propertiesValues): void { $this->expectException(NotExistingPropertyException::class); Reflection::setPropertiesValues($object, $propertiesValues); @@ -573,7 +574,7 @@ class ReflectionTest extends BaseTestCase * * @dataProvider provideObjectAndPropertiesValues */ - public function testSetPropertiesValues($object, array $propertiesValues) + public function testSetPropertiesValues($object, array $propertiesValues): void { Reflection::setPropertiesValues($object, $propertiesValues); @@ -583,11 +584,6 @@ class ReflectionTest extends BaseTestCase } } - /** - * Provides invalid class and trait - * - * @return Generator - */ public function provideInvalidClassAndTrait(): ?Generator { yield[ @@ -606,15 +602,10 @@ class ReflectionTest extends BaseTestCase ]; } - /** - * Provides object and name of not existing property - * - * @return Generator - */ - public function provideObjectAndNotExistingProperty() + public function provideObjectAndNotExistingProperty(): ?Generator { yield[ - new \stdClass(), + new stdClass(), 'test', ]; @@ -629,12 +620,7 @@ class ReflectionTest extends BaseTestCase ]; } - /** - * Provides object, name of property and value of the property - * - * @return Generator - */ - public function provideObjectPropertyAndValue() + public function provideObjectPropertyAndValue(): ?Generator { yield[ new A(), @@ -661,15 +647,10 @@ class ReflectionTest extends BaseTestCase ]; } - /** - * Provides object and not existing properties - * - * @return Generator - */ - public function provideObjectAndNotExistingProperties() + public function provideObjectAndNotExistingProperties(): ?Generator { yield[ - new \stdClass(), + new stdClass(), [ 'test' => 1, ], @@ -690,12 +671,7 @@ class ReflectionTest extends BaseTestCase ]; } - /** - * Provides object and its new values of properties - * - * @return Generator - */ - public function provideObjectAndPropertiesValues() + public function provideObjectAndPropertiesValues(): ?Generator { yield[ new A(), @@ -764,12 +740,12 @@ class ReflectionTest extends BaseTestCase public function provideClassToGetConstants(): ?Generator { yield[ - new \stdClass(), + new stdClass(), [], ]; yield[ - \stdClass::class, + stdClass::class, [], ]; From ce7ec254b1c4aff8bb82fe1ab4e6c5ade5bd5c9a Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 11 Aug 2019 12:55:12 +0200 Subject: [PATCH 080/137] Increase Mutation Score Indicator (MSI) by removing "src/Type/Base/BaseType.php:37 [M] TrueValue" mutant --- src/Type/Base/BaseType.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Type/Base/BaseType.php b/src/Type/Base/BaseType.php index a1465be..d3e49cc 100644 --- a/src/Type/Base/BaseType.php +++ b/src/Type/Base/BaseType.php @@ -34,7 +34,7 @@ abstract class BaseType */ public static function isCorrectType(?string $type): bool { - return in_array($type, (new static())->getAll(), true); + return in_array($type, (new static())->getAll()); } /** From 21bfadf5d67333d48ccde7a373438c545ec5536a Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 11 Aug 2019 12:56:08 +0200 Subject: [PATCH 081/137] Increase Mutation Score Indicator (MSI) by removing "src/Type/DatePeriod.php:120 [M] TrueValue" mutant --- tests/Type/DatePeriodTest.php | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/Type/DatePeriodTest.php b/tests/Type/DatePeriodTest.php index 5f6f0c0..0069a3c 100644 --- a/tests/Type/DatePeriodTest.php +++ b/tests/Type/DatePeriodTest.php @@ -77,6 +77,18 @@ class DatePeriodTest extends BaseTypeTestCase self::assertEquals('', $period->getFormattedDate($format)); } + /** + * @param DatePeriod $period The date period to verify + * @param string $format Format used to format the date + * @param string $expected Expected, formatted date + * + * @dataProvider provideDatePeriodAndDateFormatUsingStartDateOnly + */ + public function testGetFormattedDateUsingStartDateOnly(DatePeriod $period, $format, $expected): void + { + self::assertEquals($expected, $period->getFormattedDate($format)); + } + /** * @param DatePeriod $period The date period to verify * @param string $format Format used to format the date @@ -144,6 +156,41 @@ class DatePeriodTest extends BaseTypeTestCase ]; } + /** + * Provides period and format of date to verify using the start date + * + * @return Generator + */ + public function provideDatePeriodAndDateFormatUsingStartDateOnly(): Generator + { + $startDate = new DateTime('2001-01-01'); + $endDate = new DateTime('2002-02-02'); + + yield[ + new DatePeriod($startDate, $endDate), + 'Y', + '2001', + ]; + + yield[ + new DatePeriod($startDate, $endDate), + 'D', + 'Mon', + ]; + + yield[ + new DatePeriod($startDate, $endDate), + 'Y-m-d', + '2001-01-01', + ]; + + yield[ + new DatePeriod($startDate, $endDate), + 'Y-m-d H:i', + '2001-01-01 00:00', + ]; + } + /** * Provides period and format of date to verify * From ec1e95a086d25d5a6088fbc08e04563e68ca73e3 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 11 Aug 2019 13:06:19 +0200 Subject: [PATCH 082/137] Minor refactoring --- src/Utilities/Date.php | 46 ++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index 27037f0..8ab59fb 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -191,7 +191,7 @@ class Date * method. * @return null|string */ - public static function generateRandomTime($format = 'H:i:s') + public static function generateRandomTime($format = 'H:i:s'): ?string { $dateTime = new DateTime(); @@ -303,7 +303,7 @@ class Date * @param int $day The day value * @return string */ - public static function getDayOfWeekName($year, $month, $day) + public static function getDayOfWeekName($year, $month, $day): string { $hour = 0; $minute = 0; @@ -381,22 +381,26 @@ class Date self::DATE_DIFFERENCE_UNIT_MINUTES, ]; - if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_YEARS === $differenceUnit) { + $differenceYear = self::DATE_DIFFERENCE_UNIT_YEARS === $differenceUnit; + $differenceMonth = self::DATE_DIFFERENCE_UNIT_MONTHS === $differenceUnit; + $differenceMinutes = self::DATE_DIFFERENCE_UNIT_MINUTES === $differenceUnit; + + if (null === $differenceUnit || $differenceYear) { $diff = $end->diff($start); // Difference between dates in years should be returned only? - if (self::DATE_DIFFERENCE_UNIT_YEARS === $differenceUnit) { + if ($differenceYear) { return $diff->y; } $difference[self::DATE_DIFFERENCE_UNIT_YEARS] = $diff->y; } - if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_MONTHS === $differenceUnit) { + if (null === $differenceUnit || $differenceMonth) { $diff = $end->diff($start); // Difference between dates in months should be returned only? - if (self::DATE_DIFFERENCE_UNIT_MONTHS === $differenceUnit) { + if ($differenceMonth) { return $diff->m; } @@ -437,11 +441,11 @@ class Date $hoursInSeconds = $hours * $hourSeconds; } - if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_MINUTES === $differenceUnit) { + if (null === $differenceUnit || $differenceMinutes) { $minutes = (int)floor(($dateDiff - $daysInSeconds - $hoursInSeconds) / 60); // Difference between dates in minutes should be returned only? - if (self::DATE_DIFFERENCE_UNIT_MINUTES === $differenceUnit) { + if ($differenceMinutes) { return $minutes; } @@ -463,7 +467,7 @@ class Date * @throws Exception * @return array */ - public static function getDatesCollection(DateTime $startDate, $datesCount, $intervalTemplate = 'P%dD') + public static function getDatesCollection(DateTime $startDate, $datesCount, $intervalTemplate = 'P%dD'): array { $dates = []; @@ -513,8 +517,12 @@ class Date * @throws Exception * @return DateTime */ - public static function getRandomDate(DateTime $startDate = null, $start = 1, $end = 100, $intervalTemplate = 'P%sD') - { + public static function getRandomDate( + DateTime $startDate = null, + $start = 1, + $end = 100, + $intervalTemplate = 'P%sD' + ): DateTime { if (null === $startDate) { $startDate = new DateTime(); } @@ -531,7 +539,7 @@ class Date } $randomDate = clone $startDate; - $randomInterval = new DateInterval(sprintf($intervalTemplate, mt_rand($start, $end))); + $randomInterval = new DateInterval(sprintf($intervalTemplate, random_int($start, $end))); return $randomDate->add($randomInterval); } @@ -623,12 +631,10 @@ class Date * Verify instance of the DateTime created by constructor and by createFromFormat() method. * After formatting, these dates should be the same. */ - else { - if ($dateFromFormat->format($dateFormat) === $value) { - return $date; - } + elseif ($dateFromFormat->format($dateFormat) === $value) { + return $date; } - } catch (\Exception $exception) { + } catch (Exception $exception) { if (!$allowCompoundFormats) { return false; } @@ -643,7 +649,7 @@ class Date if ($dateString !== (string)$value) { return new DateTime($dateString); } - } catch (\Exception $exception) { + } catch (Exception $exception) { } return false; @@ -658,7 +664,7 @@ class Date * month", "yyyy"). Otherwise - not and every incorrect value is refused. * @return bool */ - public static function isValidDate($value, $allowCompoundFormats = false) + public static function isValidDate($value, $allowCompoundFormats = false): bool { return self::getDateTime($value, $allowCompoundFormats) instanceof DateTime; } @@ -669,7 +675,7 @@ class Date * @param string $format The validated format of date * @return bool */ - public static function isValidDateFormat($format) + public static function isValidDateFormat($format): bool { if (empty($format) || !is_string($format)) { return false; From bc20645cba4c27fbf379001fa01a646190bd97ff Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 11 Aug 2019 13:25:28 +0200 Subject: [PATCH 083/137] Increase Mutation Score Indicator (MSI) by removing "src/Type/DatePeriod.php:131 [M] LogicalOr" mutant --- src/Type/DatePeriod.php | 3 ++- tests/Type/DatePeriodTest.php | 41 +++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/Type/DatePeriod.php b/src/Type/DatePeriod.php index d25985c..8556031 100644 --- a/src/Type/DatePeriod.php +++ b/src/Type/DatePeriod.php @@ -114,7 +114,8 @@ class DatePeriod extends BaseType * Returns formatted one of the period's date: start date or end date * * @param string $format Format used to format the date - * @param bool $startDate (optional) If is set to true, start date will be formatted. Otherwise - end date. + * @param bool $startDate (optional) If is set to true, start date will be formatted (default behaviour). + * Otherwise - end date. * @return string */ public function getFormattedDate(string $format, bool $startDate = true): string diff --git a/tests/Type/DatePeriodTest.php b/tests/Type/DatePeriodTest.php index 0069a3c..c6ae1f8 100644 --- a/tests/Type/DatePeriodTest.php +++ b/tests/Type/DatePeriodTest.php @@ -77,6 +77,18 @@ class DatePeriodTest extends BaseTypeTestCase self::assertEquals('', $period->getFormattedDate($format)); } + /** + * @param DatePeriod $period The date period to verify + * @param string $format Format used to format the date + * @param bool $startDate If is set to true, start date is formatted. Otherwise - end date. + * + * @dataProvider provideDatePeriodAndUnknownDate + */ + public function testGetFormattedDateUsingUnknownDate(DatePeriod $period, $format, $startDate): void + { + self::assertEquals('', $period->getFormattedDate($format, $startDate)); + } + /** * @param DatePeriod $period The date period to verify * @param string $format Format used to format the date @@ -156,6 +168,35 @@ class DatePeriodTest extends BaseTypeTestCase ]; } + public function provideDatePeriodAndUnknownDate(): ?Generator + { + $date = new DateTime('2001-01-01'); + + yield[ + new DatePeriod(), + 'Y-m-d', + false, + ]; + + yield[ + new DatePeriod(), + 'Y-m-d', + true, + ]; + + yield[ + new DatePeriod($date), + 'Y-m-d', + false, + ]; + + yield[ + new DatePeriod(null, $date), + 'Y-m-d', + true, + ]; + } + /** * Provides period and format of date to verify using the start date * From 030e33064d0204e7a20eee35a13915ebc5992811 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 24 Aug 2019 17:22:07 +0200 Subject: [PATCH 084/137] Increase Mutation Score Indicator (MSI) by making Meritoo\Common\Traits\Test\Base\BaseTestCaseTrait::getFilePathForTesting() method protected (instead of public) --- src/Traits/Test/Base/BaseTestCaseTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Traits/Test/Base/BaseTestCaseTrait.php b/src/Traits/Test/Base/BaseTestCaseTrait.php index 554291f..23fe294 100644 --- a/src/Traits/Test/Base/BaseTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTestCaseTrait.php @@ -147,7 +147,7 @@ trait BaseTestCaseTrait * @param string $directoryPath (optional) Path of directory containing the file * @return string */ - public function getFilePathForTesting(string $fileName, string $directoryPath = ''): string + protected function getFilePathForTesting(string $fileName, string $directoryPath = ''): string { $rootPath = Miscellaneous::getProjectRootPath(); From cc06cdde6f3318aeebb19478cb3a841e46e9f0c4 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 25 Aug 2019 20:22:42 +0200 Subject: [PATCH 085/137] Minor refactoring --- src/Utilities/Regex.php | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index 148f3b2..78705da 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -776,10 +776,7 @@ class Regex */ public static function getValidColorHexValue($color, $throwException = true) { - /* - * Not a scalar value? - * Nothing to do - */ + // Not a scalar value? if (!is_scalar($color)) { return false; } @@ -787,10 +784,7 @@ class Regex $color = Miscellaneous::replace($color, '/#/', ''); $length = strlen($color); - /* - * Color is not 3 or 6 characters long? - * Nothing to do - */ + // Color hasn't 3 or 6 characters length? if (3 !== $length && 6 !== $length) { if ($throwException) { throw new IncorrectColorHexLengthException($color); @@ -799,10 +793,7 @@ class Regex return false; } - /* - * Color is 3 characters long? - * Let's make it 6 characters long - */ + // Make the color 6 characters length, if has 3 if (3 === $length) { $color = Miscellaneous::replace($color, '/(.)(.)(.)/', '$1$1$2$2$3$3'); } @@ -810,19 +801,16 @@ class Regex $pattern = self::$patterns['color']; $match = (bool)preg_match($pattern, $color); - /* - * It's valid color - * Nothing to do more - */ - if ($match) { - return strtolower($color); + // It's not a valid color + if (!$match) { + if ($throwException) { + throw new InvalidColorHexValueException($color); + } + + return false; } - if ($throwException) { - throw new InvalidColorHexValueException($color); - } - - return false; + return strtolower($color); } /** From 0afcf9843e1a058f225bcb3f4b5376ef6ff4fc1e Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 27 Aug 2019 20:23:28 +0200 Subject: [PATCH 086/137] Make more readable documentation of Regex class --- docs/Static-methods/Regex.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/Static-methods/Regex.md b/docs/Static-methods/Regex.md index 14998a2..f45a707 100644 --- a/docs/Static-methods/Regex.md +++ b/docs/Static-methods/Regex.md @@ -17,20 +17,22 @@ File: `src/Utilities/Regex.php` - `string $value` - Value that should be transformed to slug -##### Example 1 +##### Examples -- value: non-scalar or `null` -- result: `false` +1) -##### Example 2 + - value: non-scalar or `null` + - result: `false` -- value: `""` (an empty string) -- result: `""` (an empty string) +2) -##### Example 3 + - value: `""` (an empty string) + - result: `""` (an empty string) -- value: `"Lorem ipsum. Dolor sit 12.34 amet."` -- result: `"lorem-ipsum-dolor-sit-1234-amet"` +3) + + - value: `"Lorem ipsum. Dolor sit 12.34 amet."` + - result: `"lorem-ipsum-dolor-sit-1234-amet"` # More From e704dacabde2888ab4c02a9be8d5cd7352b696dc Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 27 Aug 2019 20:26:31 +0200 Subject: [PATCH 087/137] Add Regex::clearBeginningSlash() and Regex::clearEndingSlash() methods (that remove slash from the beginning and the end of given string) --- docs/Static-methods/Regex.md | 50 ++++++++ src/Utilities/Regex.php | 16 +++ tests/Utilities/RegexTest.php | 228 ++++++++++++++++++++++++++++++++++ 3 files changed, 294 insertions(+) diff --git a/docs/Static-methods/Regex.md b/docs/Static-methods/Regex.md index f45a707..f86e3fb 100644 --- a/docs/Static-methods/Regex.md +++ b/docs/Static-methods/Regex.md @@ -34,6 +34,56 @@ File: `src/Utilities/Regex.php` - value: `"Lorem ipsum. Dolor sit 12.34 amet."` - result: `"lorem-ipsum-dolor-sit-1234-amet"` +### clearBeginningSlash(string): string + +> Clears, removes slash from the beginning of given string + +##### Arguments + +- `string $string` - String that may contains slash as the 1st character + +##### Examples + +1) + + - string: `"lorem ipsum"` + - result: `"lorem ipsum"` + +2) + + - string: `"/lorem ipsum"` + - result: `"lorem ipsum"` + +3) + + - string: `"/ lorem 123 ipsum"` + - result: `" lorem 123 ipsum"` + +### clearEndingSlash(string): string + +> Clears, removes slash from the end of given string + +##### Arguments + +- `string $string` - String that may contains slash as the last character + +##### Examples + +1) + + - string: `"lorem ipsum"` + - result: `"lorem ipsum"` + +2) + + - string: `"lorem ipsum/"` + - result: `"lorem ipsum"` + +3) + + - string: `"lorem 123 ipsum /"` + - result: `"lorem 123 ipsum "` + # More 1. [Base test case (with common methods and data providers)](../Base-test-case.md) diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index 78705da..1077bda 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -40,6 +40,8 @@ class Regex 'color' => '/^[a-f0-9]{6}$/i', 'bundleName' => '/^(([A-Z]{1}[a-z0-9]+)((?2))*)(Bundle)$/', 'binaryValue' => '/[^\x20-\x7E\t\r\n]/', + 'beginningSlash' => '|^\/|', + 'endingSlash' => '|\/$|', /* * Matches: @@ -999,4 +1001,18 @@ class Regex return preg_replace('/[-\s]+/', '-', $result); } + + public static function clearBeginningSlash(string $string): string + { + $pattern = static::$patterns['beginningSlash']; + + return preg_replace($pattern, '', $string); + } + + public static function clearEndingSlash(string $string): string + { + $pattern = static::$patterns['endingSlash']; + + return preg_replace($pattern, '', $string); + } } diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index df9b925..3c404ea 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -649,6 +649,28 @@ class RegexTest extends BaseTestCase self::assertSame($expected, Regex::createSlug($value)); } + /** + * @param string $string + * @param string $expected + * + * @dataProvider provideStringToClearBeginningSlash + */ + public function testClearBeginningSlash(string $string, string $expected): void + { + static::assertSame($expected, Regex::clearBeginningSlash($string)); + } + + /** + * @param string $string + * @param string $expected + * + * @dataProvider provideStringToClearEndingSlash + */ + public function testClearEndingSlash(string $string, string $expected): void + { + static::assertSame($expected, Regex::clearEndingSlash($string)); + } + /** * Provides name of bundle and information if it's valid name * @@ -1983,6 +2005,212 @@ class RegexTest extends BaseTestCase ]; } + public function provideStringToClearBeginningSlash(): ?Generator + { + yield[ + '', + '', + ]; + + yield[ + '/', + '', + ]; + + yield[ + '\\', + '\\', + ]; + + yield[ + '//', + '/', + ]; + + yield[ + 'lorem ipsum', + 'lorem ipsum', + ]; + + yield[ + '1234', + '1234', + ]; + + yield[ + 'lorem/ipsum', + 'lorem/ipsum', + ]; + + yield[ + 'lorem / ipsum', + 'lorem / ipsum', + ]; + + yield[ + 'lorem\ipsum', + 'lorem\ipsum', + ]; + + yield[ + 'lorem \ ipsum', + 'lorem \ ipsum', + ]; + + yield[ + '\lorem ipsum', + '\lorem ipsum', + ]; + + yield[ + '\ lorem ipsum', + '\ lorem ipsum', + ]; + + yield[ + 'lorem ipsum/', + 'lorem ipsum/', + ]; + + yield[ + 'lorem ipsum /', + 'lorem ipsum /', + ]; + + yield[ + '/lorem ipsum', + 'lorem ipsum', + ]; + + yield[ + '/ lorem ipsum', + ' lorem ipsum', + ]; + + yield[ + '/123 456', + '123 456', + ]; + + yield[ + '/ 123 456', + ' 123 456', + ]; + + yield[ + '/lorem 123 ipsum 456', + 'lorem 123 ipsum 456', + ]; + + yield[ + '/ lorem 123 ipsum 456', + ' lorem 123 ipsum 456', + ]; + } + + public function provideStringToClearEndingSlash(): ?Generator + { + yield[ + '', + '', + ]; + + yield[ + '/', + '', + ]; + + yield[ + '\\', + '\\', + ]; + + yield[ + '//', + '/', + ]; + + yield[ + 'lorem ipsum', + 'lorem ipsum', + ]; + + yield[ + '1234', + '1234', + ]; + + yield[ + 'lorem/ipsum', + 'lorem/ipsum', + ]; + + yield[ + 'lorem / ipsum', + 'lorem / ipsum', + ]; + + yield[ + 'lorem\ipsum', + 'lorem\ipsum', + ]; + + yield[ + 'lorem \ ipsum', + 'lorem \ ipsum', + ]; + + yield[ + '\lorem ipsum', + '\lorem ipsum', + ]; + + yield[ + '\ lorem ipsum', + '\ lorem ipsum', + ]; + + yield[ + '/lorem ipsum', + '/lorem ipsum', + ]; + + yield[ + '/ lorem ipsum', + '/ lorem ipsum', + ]; + + yield[ + 'lorem ipsum/', + 'lorem ipsum', + ]; + + yield[ + 'lorem ipsum /', + 'lorem ipsum ', + ]; + + yield[ + '123 456/', + '123 456', + ]; + + yield[ + '123 456 /', + '123 456 ', + ]; + + yield[ + 'lorem 123 ipsum 456/', + 'lorem 123 ipsum 456', + ]; + + yield[ + 'lorem 123 ipsum 456 /', + 'lorem 123 ipsum 456 ', + ]; + } + /** * {@inheritdoc} */ From 10992570adabefeea2b728408c3fe84686656a70 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 28 Aug 2019 15:44:37 +0200 Subject: [PATCH 088/137] Make more readable documentation of Arrays class --- docs/Static-methods/Arrays.md | 54 +++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/docs/Static-methods/Arrays.md b/docs/Static-methods/Arrays.md index dda85ec..a8c3f14 100644 --- a/docs/Static-methods/Arrays.md +++ b/docs/Static-methods/Arrays.md @@ -17,20 +17,22 @@ File: `src/Utilities/Arrays.php` - `array $values` - The values to filter -##### Example 1 +##### Examples -- values: `[]` (no values) -- result: `[]` (an empty array) +1) -##### Example 2 + - values: `[]` (no values) + - result: `[]` (an empty array) -- values: `[null, ""]` (all empty values) -- result: `[]` (an empty array) +2) -##### Example 3 + - values: `[null, ""]` (all empty values) + - result: `[]` (an empty array) -- values: `["test 1", "", 123, null, 0]` -- result: `["test 1", 123, 0]` +3) + + - values: `["test 1", "", 123, null, 0]` + - result: `["test 1", 123, 0]` ### getNonEmptyValuesAsString(array $values, $separator = ', ') @@ -41,29 +43,31 @@ File: `src/Utilities/Arrays.php` - `array $values` - The values to filter - `[string $separator]` - (optional) Separator used to implode the values. Default: ", ". -##### Example 1 +##### Examples -- values: `[]` (no values) -- separator: default or any other string -- result: `""` (an empty string) +1) -##### Example 2 + - values: `[]` (no values) + - separator: default or any other string + - result: `""` (an empty string) -- values: `[null, ""]` (all empty values) -- separator: default or any other string -- result: `""` (an empty string) +2) -##### Example 3 + - values: `[null, ""]` (all empty values) + - separator: default or any other string + - result: `""` (an empty string) -- values: `["test 1", "", 123, null, 0]` -- separator: `", "` (default) -- result: `"test 1, 123, 0"` +3) -##### Example 4 + - values: `["test 1", "", 123, null, 0]` + - separator: `", "` (default) + - result: `"test 1, 123, 0"` -- values: `["test 1", "", 123, null, 0]` -- separator: `" | "` -- result: `"test 1 | 123 | 0"` +4) + + - values: `["test 1", "", 123, null, 0]` + - separator: `" | "` + - result: `"test 1 | 123 | 0"` # More From 891411e2315ef3132f3076443cdb3ef0fcec4d9f Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 28 Aug 2019 15:51:03 +0200 Subject: [PATCH 089/137] Add Arrays::containsEmptyStringsOnly() method Returns information if given array contains an empty strings only --- docs/Static-methods/Arrays.md | 23 +++++++++++++++ src/Utilities/Arrays.php | 9 ++++++ tests/Utilities/ArraysTest.php | 53 ++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/docs/Static-methods/Arrays.md b/docs/Static-methods/Arrays.md index a8c3f14..35547c2 100644 --- a/docs/Static-methods/Arrays.md +++ b/docs/Static-methods/Arrays.md @@ -9,6 +9,29 @@ Common and useful classes, methods, exceptions etc. Class: `Meritoo\Common\Utilities\Arrays` File: `src/Utilities/Arrays.php` +### containsEmptyStringsOnly(array): bool + +> Returns information if given array contains an empty strings only + +##### Arguments + +- `array $array` - The array to verify + +##### Examples + +1) + + - array: `[]` (an empty array) + - result: `false` + +2) + - array: `["", -1]` + - result: `false` + +3) + - array: `["", null, ""]` + - result: `true` + ### getNonEmptyValues(array $values) > Returns non-empty values, e.g. without "" (empty string), null or [] diff --git a/src/Utilities/Arrays.php b/src/Utilities/Arrays.php index 41386c2..b9a9d8e 100644 --- a/src/Utilities/Arrays.php +++ b/src/Utilities/Arrays.php @@ -1633,6 +1633,15 @@ class Arrays return is_array($value) && !empty($value); } + public static function containsEmptyStringsOnly(array $array): bool + { + if (empty($array)) { + return false; + } + + return '' === trim(implode('', $array)); + } + /** * Returns neighbour (next or previous element) for given element * diff --git a/tests/Utilities/ArraysTest.php b/tests/Utilities/ArraysTest.php index e68b25a..82e0c3e 100644 --- a/tests/Utilities/ArraysTest.php +++ b/tests/Utilities/ArraysTest.php @@ -1486,6 +1486,17 @@ letsTest[2] = value_2;'; self::assertSame($expected, Arrays::isNotEmptyArray($value), $description); } + /** + * @param array $array + * @param bool $expected + * + * @dataProvider provideArrayToVerifyIfContainsEmptyStringsOnly + */ + public function testContainsEmptyStringsOnly(array $array, bool $expected): void + { + static::assertSame($expected, Arrays::containsEmptyStringsOnly($array)); + } + /** * Provides simple array to set/replace values with keys * @@ -2870,6 +2881,48 @@ letsTest[2] = value_2;'; ]; } + public function provideArrayToVerifyIfContainsEmptyStringsOnly(): ?Generator + { + yield[ + [], + false, + ]; + + yield[ + [ + '', + 1, + ], + false, + ]; + + yield[ + [ + '', + null, + 1, + ], + false, + ]; + + yield[ + [ + '', + null, + ], + true, + ]; + + yield[ + [ + '', + null, + '', + ], + true, + ]; + } + /** * {@inheritdoc} */ From f7a8da055062c990c15d398987854a434a341227 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 28 Aug 2019 16:01:27 +0200 Subject: [PATCH 090/137] Add Uri::buildUrl() method Builds url with given root url and parts of url --- README.md | 1 + docs/Base-test-case.md | 1 + docs/Exceptions.md | 1 + docs/Static-methods.md | 1 + docs/Static-methods/Arrays.md | 1 + docs/Static-methods/Regex.md | 1 + docs/Static-methods/Uri.md | 47 +++++++++++++++++++++++++ docs/Value-Objects.md | 1 + src/Utilities/Uri.php | 22 +++++++++++- tests/Utilities/UriTest.php | 66 ++++++++++++++++++++++++++++++++++- 10 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 docs/Static-methods/Uri.md diff --git a/README.md b/README.md index 6eddebb..b8fe66f 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ composer require meritoo/common-library 4. [Static methods](docs/Static-methods.md) 1. [Arrays](docs/Static-methods/Arrays.md) 2. [Regex](docs/Static-methods/Regex.md) + 3. [Uri](docs/Static-methods/Uri.md) 5. [Value Objects](docs/Value-Objects.md) # Development diff --git a/docs/Base-test-case.md b/docs/Base-test-case.md index bb8ac79..3452796 100644 --- a/docs/Base-test-case.md +++ b/docs/Base-test-case.md @@ -51,6 +51,7 @@ class MimeTypesTest extends BaseTestCase 5. [Static methods](Static-methods.md) 1. [Arrays](Static-methods/Arrays.md) 2. [Regex](Static-methods/Regex.md) + 3. [Uri](Static-methods/Uri.md) 6. [Value Objects](Value-Objects.md) [‹ Back to `Readme`](../README.md) diff --git a/docs/Exceptions.md b/docs/Exceptions.md index de4a570..49c38f2 100644 --- a/docs/Exceptions.md +++ b/docs/Exceptions.md @@ -60,6 +60,7 @@ class UnknownSimpleTypeException extends UnknownTypeException 5. [Static methods](Static-methods.md) 1. [Arrays](Static-methods/Arrays.md) 2. [Regex](Static-methods/Regex.md) + 3. [Uri](Static-methods/Uri.md) 6. [Value Objects](Value-Objects.md) [‹ Back to `Readme`](../README.md) diff --git a/docs/Static-methods.md b/docs/Static-methods.md index f1f0f7a..0b225e0 100644 --- a/docs/Static-methods.md +++ b/docs/Static-methods.md @@ -22,6 +22,7 @@ var_dump($firstElement); // string(5) "lorem" 5. [**Static methods**](Static-methods.md) 1. [Arrays](Static-methods/Arrays.md) 2. [Regex](Static-methods/Regex.md) + 3. [Uri](Static-methods/Uri.md) 6. [Value Objects](Value-Objects.md) [‹ Back to `Readme`](../README.md) diff --git a/docs/Static-methods/Arrays.md b/docs/Static-methods/Arrays.md index 35547c2..7169a55 100644 --- a/docs/Static-methods/Arrays.md +++ b/docs/Static-methods/Arrays.md @@ -101,6 +101,7 @@ File: `src/Utilities/Arrays.php` 5. [Static methods](../Static-methods.md) 1. [**Arrays**](Arrays.md) 2. [Regex](Regex.md) + 3. [Uri](Uri.md) 6. [Value Objects](../Value-Objects.md) [‹ Back to `Readme`](../../README.md) diff --git a/docs/Static-methods/Regex.md b/docs/Static-methods/Regex.md index f86e3fb..1a4a48b 100644 --- a/docs/Static-methods/Regex.md +++ b/docs/Static-methods/Regex.md @@ -93,6 +93,7 @@ File: `src/Utilities/Regex.php` 5. [Static methods](../Static-methods.md) 1. [Arrays](../Static-methods/Arrays.md) 2. [**Regex**](Regex.md) + 3. [Uri](Uri.md) 6. [Value Objects](../Value-Objects.md) [‹ Back to `Readme`](../../README.md) diff --git a/docs/Static-methods/Uri.md b/docs/Static-methods/Uri.md new file mode 100644 index 0000000..5808d31 --- /dev/null +++ b/docs/Static-methods/Uri.md @@ -0,0 +1,47 @@ +# Meritoo Common Library + +Common and useful classes, methods, exceptions etc. + +# Uri + +> Useful methods related to uri + +Class: `Meritoo\Common\Utilities\Uri` +File: `src/Utilities/Uri.php` + +### buildUrl(string, string ...): string + +> Builds url with given root url and parts of url (concatenates them using "/") + +##### Arguments + +- `string $rootUrl` - Protocol and domain (or domain only) +- `string ...$urlParts` - Parts of url that will be concatenated with the rool url by "/" + +##### Examples + +1) + + - rootUrl: `"http://my.example"` + - urlParts: `""` (an empty string) + - result: `"http://my.example"` + +2) + + - rootUrl: `"http://my.example"` + - urlParts: `"/test", "/123"` + - result: `"http://my.example/test/123"` + +# More + +1. [Base test case (with common methods and data providers)](../Base-test-case.md) +2. [Collection of elements](../Collection/Collection.md) +3. [Templates](../Collection/Templates.md) +4. [Exceptions](../Exceptions.md) +5. [Static methods](../Static-methods.md) + 1. [Arrays](Arrays.md) + 2. [Regex](Regex.md) + 3. [**Uri**](Uri.md) +6. [Value Objects](../Value-Objects.md) + +[‹ Back to `Readme`](../../README.md) diff --git a/docs/Value-Objects.md b/docs/Value-Objects.md index fa8d6ec..83184de 100644 --- a/docs/Value-Objects.md +++ b/docs/Value-Objects.md @@ -344,6 +344,7 @@ $asString = (string)$version; // "1.0.2" 5. [Static methods](Static-methods.md) 1. [Arrays](Static-methods/Arrays.md) 2. [Regex](Static-methods/Regex.md) + 3. [Uri](Static-methods/Uri.md) 6. [**Value Objects**](Value-Objects.md) [‹ Back to `Readme`](../README.md) diff --git a/src/Utilities/Uri.php b/src/Utilities/Uri.php index f1a47b8..602262a 100644 --- a/src/Utilities/Uri.php +++ b/src/Utilities/Uri.php @@ -9,7 +9,7 @@ namespace Meritoo\Common\Utilities; /** - * Useful uri methods (only static functions) + * Useful methods related to uri * * @author Meritoo * @copyright Meritoo @@ -351,4 +351,24 @@ class Uri return sprintf('%s://%s', $protocol, $url); } + + public static function buildUrl(string $rootUrl, string ...$urlParts): string + { + $rootUrl = Regex::clearEndingSlash($rootUrl); + + if (empty($urlParts) || Arrays::containsEmptyStringsOnly($urlParts)) { + return $rootUrl; + } + + array_walk($urlParts, static function (&$part) { + $part = Regex::clearBeginningSlash($part); + $part = Regex::clearEndingSlash($part); + }); + + return sprintf( + '%s/%s', + $rootUrl, + implode('/', $urlParts) + ); + } } diff --git a/tests/Utilities/UriTest.php b/tests/Utilities/UriTest.php index 6b3bf18..3739abb 100644 --- a/tests/Utilities/UriTest.php +++ b/tests/Utilities/UriTest.php @@ -19,7 +19,7 @@ use Meritoo\Common\Utilities\Uri; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Utilities\Uri + * @covers \Meritoo\Common\Utilities\Uri */ class UriTest extends BaseTestCase { @@ -255,6 +255,18 @@ class UriTest extends BaseTestCase self::assertEquals($expectedUrl, Uri::getSecuredUrl($url, $user, $password)); } + /** + * @param string $expected + * @param string $rootUrl + * @param string ...$urlParts + * + * @dataProvider provideRootUrlAndUrlParts + */ + public function testBuildUrl(string $expected, string $rootUrl, string ...$urlParts): void + { + static::assertSame($expected, Uri::buildUrl($rootUrl, ...$urlParts)); + } + /** * Provides url to replenish protocol * @@ -372,4 +384,56 @@ class UriTest extends BaseTestCase 'http://john:pass123@lorem.com/contact', ]; } + + public function provideRootUrlAndUrlParts(): ?Generator + { + yield[ + '', + '', + ]; + + yield[ + '', + '', + '', + ]; + + yield[ + 'http://my.example', + 'http://my.example', + '', + ]; + + yield[ + 'http://my.example', + 'http://my.example', + '', + '', + ]; + + yield[ + 'http://my.example//test/12/test/', + 'http://my.example', + '', + 'test', + '12/test', + '', + ]; + + yield[ + 'http://my.example//test/12/test', + 'http://my.example', + '', + 'test/', + '12/test/', + ]; + + yield[ + 'http://my.example/test/12/test/', + 'http://my.example', + '/test/', + '/12/test', + '', + ]; + } } From 16cdd1cd606651557d06e98f8bf0fc70b155960c Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 5 Sep 2019 21:49:32 +0200 Subject: [PATCH 091/137] Extract BaseTestCaseTrait::assertMethodVisibility() & BaseTestCaseTrait::assertMethodArgumentsCount() methods (from BaseTestCaseTrait::assertMethodVisibilityAndArguments() method) --- docs/Base-test-case.md | 12 ++++-- src/Traits/Test/Base/BaseTestCaseTrait.php | 45 +++++++++++----------- tests/Collection/CollectionTest.php | 8 +--- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/docs/Base-test-case.md b/docs/Base-test-case.md index 3452796..3f7ef40 100644 --- a/docs/Base-test-case.md +++ b/docs/Base-test-case.md @@ -4,7 +4,15 @@ Common and useful classes, methods, exceptions etc. # Base test case (with common methods and data providers) -Located here: `Meritoo\Common\Test\Base\BaseTestCase`. Just extend the `BaseTestCase` class and use it like in `Meritoo\Common\Test\Utilities\DateTest` class: +Located here: `Meritoo\Common\Test\Base\BaseTestCase`. + +##### Usage + +1. Just extend the `BaseTestCase` class or implement `Meritoo\Common\Traits\Test\Base\BaseTestCaseTrait` trait. +2. Use one of available data providers, e.g. `@dataProvider provideEmptyValue`, or asserts, +e.g. `static::assertMethodVisibility($method, $visibilityType);` + +##### Examples ```php class DateTest extends BaseTestCase @@ -22,8 +30,6 @@ class DateTest extends BaseTestCase } ``` -or in `Meritoo\Common\Test\Utilities\MimeTypesTest` class: - ```php class MimeTypesTest extends BaseTestCase { diff --git a/src/Traits/Test/Base/BaseTestCaseTrait.php b/src/Traits/Test/Base/BaseTestCaseTrait.php index 23fe294..3a203ef 100644 --- a/src/Traits/Test/Base/BaseTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTestCaseTrait.php @@ -162,28 +162,16 @@ trait BaseTestCaseTrait } /** - * Verifies visibility and arguments of method + * Verifies visibility of method * * @param ReflectionMethod $method Name of method or just the method to verify * @param string $visibilityType Expected visibility of verified method. One of OopVisibilityType * class constants. - * @param int $argumentsCount (optional) Expected count/amount of arguments of the verified - * method - * @param int $requiredArgumentsCount (optional) Expected count/amount of required arguments of the - * verified method * @throws UnknownOopVisibilityTypeException * @throws RuntimeException - * - * Attention. 2nd argument, the $method, may be: - * - string - name of the method - * - instance of ReflectionMethod - just the method (provided by ReflectionClass::getMethod() method) */ - protected static function assertMethodVisibilityAndArguments( - ReflectionMethod $method, - string $visibilityType, - int $argumentsCount = 0, - int $requiredArgumentsCount = 0 - ): void { + protected static function assertMethodVisibility(ReflectionMethod $method, string $visibilityType): void + { // Type of visibility is not correct? if (!OopVisibilityType::isCorrectType($visibilityType)) { throw UnknownOopVisibilityTypeException::createException($visibilityType); @@ -203,9 +191,24 @@ trait BaseTestCaseTrait break; } + } - static::assertEquals($argumentsCount, $method->getNumberOfParameters()); - static::assertEquals($requiredArgumentsCount, $method->getNumberOfRequiredParameters()); + /** + * Verifies count of method's arguments + * + * @param ReflectionMethod $method Name of method or just the method to verify + * @param int $argumentsCount (optional) Expected count/amount of arguments of the verified method + * @param int $requiredCount (optional) Expected count/amount of required arguments of the verified + * method + * @throws RuntimeException + */ + protected static function assertMethodArgumentsCount( + ReflectionMethod $method, + int $argumentsCount = 0, + int $requiredCount = 0 + ): void { + static::assertSame($argumentsCount, $method->getNumberOfParameters()); + static::assertSame($requiredCount, $method->getNumberOfRequiredParameters()); } /** @@ -232,12 +235,8 @@ trait BaseTestCaseTrait throw ClassWithoutConstructorException::create($className); } - static::assertMethodVisibilityAndArguments( - $method, - $visibilityType, - $argumentsCount, - $requiredArgumentsCount - ); + static::assertMethodVisibility($method, $visibilityType); + static::assertMethodArgumentsCount($method, $argumentsCount, $requiredArgumentsCount); } /** diff --git a/tests/Collection/CollectionTest.php b/tests/Collection/CollectionTest.php index 96e61ab..6eb469e 100644 --- a/tests/Collection/CollectionTest.php +++ b/tests/Collection/CollectionTest.php @@ -331,12 +331,8 @@ class CollectionTest extends BaseTestCase $reflectionClass = new ReflectionClass(Collection::class); $method = $reflectionClass->getMethod('exists'); - static::assertMethodVisibilityAndArguments( - $method, - OopVisibilityType::IS_PRIVATE, - 1, - 1 - ); + static::assertMethodVisibility($method, OopVisibilityType::IS_PRIVATE); + static::assertMethodArgumentsCount($method, 1, 1); } /** From ded1a049002f47fa6105dc6137b442d367dd763d Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 6 Sep 2019 11:58:40 +0200 Subject: [PATCH 092/137] Add test for the BaseTestCaseTrait trait --- .../Base/BaseTestCaseTrait/SimpleTestCase.php | 22 +++ .../Test/Base/BaseTestCaseTraitTest.php | 160 ++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 tests/Traits/Test/Base/BaseTestCaseTrait/SimpleTestCase.php create mode 100644 tests/Traits/Test/Base/BaseTestCaseTraitTest.php diff --git a/tests/Traits/Test/Base/BaseTestCaseTrait/SimpleTestCase.php b/tests/Traits/Test/Base/BaseTestCaseTrait/SimpleTestCase.php new file mode 100644 index 0000000..191beb4 --- /dev/null +++ b/tests/Traits/Test/Base/BaseTestCaseTrait/SimpleTestCase.php @@ -0,0 +1,22 @@ + + * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Traits\Test\Base\BaseTestCaseTrait + */ +class BaseTestCaseTraitTest extends BaseTestCase +{ + public function testProvideEmptyValue(): void + { + $testCase = new SimpleTestCase(); + $values = $testCase->provideEmptyValue(); + + $expected = [ + [''], + [' '], + [null], + [0], + [false], + [[]], + ]; + + foreach ($values as $index => $value) { + static::assertSame($expected[$index], $value); + } + } + + public function testProvideEmptyScalarValue(): void + { + $testCase = new SimpleTestCase(); + $values = $testCase->provideEmptyScalarValue(); + + $expected = [ + [''], + [' '], + [null], + [0], + [false], + ]; + + foreach ($values as $index => $value) { + static::assertSame($expected[$index], $value); + } + } + + public function testProvideBooleanValue(): void + { + $testCase = new SimpleTestCase(); + $values = $testCase->provideBooleanValue(); + + $expected = [ + [false], + [true], + ]; + + foreach ($values as $index => $value) { + static::assertSame($expected[$index], $value); + } + } + + public function testProvideDateTimeInstance(): void + { + $testCase = new SimpleTestCase(); + $instances = $testCase->provideDateTimeInstance(); + + $expected = [ + [new DateTime()], + [new DateTime('yesterday')], + [new DateTime('now')], + [new DateTime('tomorrow')], + ]; + + foreach ($instances as $index => $instance) { + /** @var DateTime $expectedInstance */ + $expectedInstance = $expected[$index][0]; + + /** @var DateTime $instance */ + $instance = $instance[0]; + + static::assertInstanceOf(DateTime::class, $instance); + static::assertEquals($expectedInstance->getTimestamp(), $instance->getTimestamp()); + } + } + + public function testProvideDateTimeRelativeFormatInstance(): void + { + $testCase = new SimpleTestCase(); + $formats = $testCase->provideDateTimeRelativeFormat(); + + $expected = [ + ['now'], + ['yesterday'], + ['tomorrow'], + ['back of 10'], + ['front of 10'], + ['last day of February'], + ['first day of next month'], + ['last day of previous month'], + ['last day of next month'], + ['Y-m-d'], + ['Y-m-d 10:00'], + ]; + + foreach ($formats as $index => $format) { + static::assertSame($expected[$index], $format); + } + } + + public function testProvideNotExistingFilePath(): void + { + $testCase = new SimpleTestCase(); + $paths = $testCase->provideNotExistingFilePath(); + + $expected = [ + ['lets-test.doc'], + ['lorem/ipsum.jpg'], + ['surprise/me/one/more/time.txt'], + ]; + + foreach ($paths as $index => $path) { + static::assertSame($expected[$index], $path); + } + } + + public function testProvideNonScalarValue(): void + { + $testCase = new SimpleTestCase(); + $values = $testCase->provideNonScalarValue(); + + $expected = [ + [[]], + [null], + [new stdClass()], + ]; + + foreach ($values as $index => $value) { + static::assertEquals($expected[$index], $value); + } + } +} From 678cdfdf016d23ef6031d76f2b6171fab8277eb3 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 6 Sep 2019 11:58:55 +0200 Subject: [PATCH 093/137] Minor refactoring --- src/Traits/Test/Base/BaseTestCaseTrait.php | 14 +++----------- src/Utilities/Arrays.php | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/Traits/Test/Base/BaseTestCaseTrait.php b/src/Traits/Test/Base/BaseTestCaseTrait.php index 3a203ef..11ec351 100644 --- a/src/Traits/Test/Base/BaseTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTestCaseTrait.php @@ -126,17 +126,9 @@ trait BaseTestCaseTrait */ public function provideNonScalarValue(): ?Generator { - yield[ - [], - ]; - - yield[ - null, - ]; - - yield[ - new stdClass(), - ]; + yield[[]]; + yield[null]; + yield[new stdClass()]; } /** diff --git a/src/Utilities/Arrays.php b/src/Utilities/Arrays.php index b9a9d8e..e3d57f9 100644 --- a/src/Utilities/Arrays.php +++ b/src/Utilities/Arrays.php @@ -1612,7 +1612,7 @@ class Arrays } /** - * Returns information if given value is an empty array + * Returns information if given value is an array and is empty * * @param mixed $value The value to verify * @return bool From 9903c82496af84601d43e3630b400f17b66521d8 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 9 Sep 2019 09:41:07 +0200 Subject: [PATCH 094/137] Add Miscellaneous::calculateGreatestCommonDivisor() method --- src/Utilities/Miscellaneous.php | 5 +++ tests/Utilities/MiscellaneousTest.php | 57 +++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index 4ba0e37..c33290d 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -1319,4 +1319,9 @@ class Miscellaneous return substr($string, 1); } + + public static function calculateGreatestCommonDivisor(int $first, int $second): int + { + return (0 === $second) ? $first : static::calculateGreatestCommonDivisor($second, $first % $second); + } } diff --git a/tests/Utilities/MiscellaneousTest.php b/tests/Utilities/MiscellaneousTest.php index 93af639..25a714f 100644 --- a/tests/Utilities/MiscellaneousTest.php +++ b/tests/Utilities/MiscellaneousTest.php @@ -735,6 +735,18 @@ class MiscellaneousTest extends BaseTestCase self::assertEquals($expected, Miscellaneous::removeMarginalCharacter($string, $last), $description); } + /** + * @param int $first + * @param int $second + * @param int $expected + * + * @dataProvider provideGreatestCommonDivisor + */ + public function testCalculateGreatestCommonDivisor(int $first, int $second, int $expected): void + { + static::assertSame($expected, Miscellaneous::calculateGreatestCommonDivisor($first, $second)); + } + /** * Provides string to convert characters to latin characters and not lower cased and not human-readable * @@ -1506,6 +1518,51 @@ class MiscellaneousTest extends BaseTestCase ]; } + public function provideGreatestCommonDivisor(): ?Generator + { + yield[ + 0, + 0, + 0, + ]; + + yield[ + 1, + 1, + 1, + ]; + + yield[ + 5, + 3, + 1, + ]; + + yield[ + 6, + 3, + 3, + ]; + + yield[ + 12, + 9, + 3, + ]; + + yield[ + 20, + 12, + 4, + ]; + + yield[ + 120, + 80, + 40, + ]; + } + /** * {@inheritdoc} */ From b0e404aeb98c1ed7f329a638a504be7bd21f5e65 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 9 Sep 2019 16:06:20 +0200 Subject: [PATCH 095/137] Minor refactoring --- src/Utilities/Miscellaneous.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index c33290d..dc679e4 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -1322,6 +1322,10 @@ class Miscellaneous public static function calculateGreatestCommonDivisor(int $first, int $second): int { - return (0 === $second) ? $first : static::calculateGreatestCommonDivisor($second, $first % $second); + if (0 === $second) { + return $first; + } + + return static::calculateGreatestCommonDivisor($second, $first % $second); } } From 1f45d38ab81b5751b009d73ab621c6a569f7d8ea Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 15 Sep 2019 13:33:03 +0200 Subject: [PATCH 096/137] Add @internal @coversNothing annotations in PHPUnit tests --- tests/Utilities/Arrays/SimpleToString.php | 2 ++ tests/Utilities/Reflection/A.php | 3 +++ tests/Utilities/Reflection/B.php | 3 +++ tests/Utilities/Reflection/C.php | 3 +++ tests/Utilities/Reflection/D.php | 3 +++ tests/Utilities/Reflection/E.php | 2 ++ tests/Utilities/Reflection/F.php | 3 +++ tests/Utilities/Reflection/G.php | 3 +++ tests/Utilities/Reflection/H.php | 3 +++ tests/Utilities/Reflection/I.php | 2 ++ tests/Utilities/Reflection/J.php | 3 +++ tests/Utilities/Repository/Sortable.php | 3 +++ 12 files changed, 33 insertions(+) diff --git a/tests/Utilities/Arrays/SimpleToString.php b/tests/Utilities/Arrays/SimpleToString.php index dd51827..190f821 100644 --- a/tests/Utilities/Arrays/SimpleToString.php +++ b/tests/Utilities/Arrays/SimpleToString.php @@ -14,6 +14,8 @@ namespace Meritoo\Test\Common\Utilities\Arrays; * * @author Meritoo * @copyright Meritoo + * + * @coversNothing */ class SimpleToString { diff --git a/tests/Utilities/Reflection/A.php b/tests/Utilities/Reflection/A.php index f20ca1a..df948d6 100644 --- a/tests/Utilities/Reflection/A.php +++ b/tests/Utilities/Reflection/A.php @@ -14,6 +14,9 @@ namespace Meritoo\Test\Common\Utilities\Reflection; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @coversNothing */ class A { diff --git a/tests/Utilities/Reflection/B.php b/tests/Utilities/Reflection/B.php index 101cdce..aa676be 100644 --- a/tests/Utilities/Reflection/B.php +++ b/tests/Utilities/Reflection/B.php @@ -14,6 +14,9 @@ namespace Meritoo\Test\Common\Utilities\Reflection; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @coversNothing */ class B extends A implements I { diff --git a/tests/Utilities/Reflection/C.php b/tests/Utilities/Reflection/C.php index 3c4d598..f035b38 100644 --- a/tests/Utilities/Reflection/C.php +++ b/tests/Utilities/Reflection/C.php @@ -14,6 +14,9 @@ namespace Meritoo\Test\Common\Utilities\Reflection; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @coversNothing */ class C extends B { diff --git a/tests/Utilities/Reflection/D.php b/tests/Utilities/Reflection/D.php index 06f6550..2467723 100644 --- a/tests/Utilities/Reflection/D.php +++ b/tests/Utilities/Reflection/D.php @@ -14,6 +14,9 @@ namespace Meritoo\Test\Common\Utilities\Reflection; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @coversNothing */ class D { diff --git a/tests/Utilities/Reflection/E.php b/tests/Utilities/Reflection/E.php index 7a72efc..96afb85 100644 --- a/tests/Utilities/Reflection/E.php +++ b/tests/Utilities/Reflection/E.php @@ -14,6 +14,8 @@ namespace Meritoo\Test\Common\Utilities\Reflection; * * @author Meritoo * @copyright Meritoo + * + * @internal */ trait E { diff --git a/tests/Utilities/Reflection/F.php b/tests/Utilities/Reflection/F.php index de53f7b..03a0c3c 100644 --- a/tests/Utilities/Reflection/F.php +++ b/tests/Utilities/Reflection/F.php @@ -14,6 +14,9 @@ namespace Meritoo\Test\Common\Utilities\Reflection; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @coversNothing */ class F { diff --git a/tests/Utilities/Reflection/G.php b/tests/Utilities/Reflection/G.php index d7f2c54..34fdcf8 100644 --- a/tests/Utilities/Reflection/G.php +++ b/tests/Utilities/Reflection/G.php @@ -14,6 +14,9 @@ namespace Meritoo\Test\Common\Utilities\Reflection; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @coversNothing */ class G { diff --git a/tests/Utilities/Reflection/H.php b/tests/Utilities/Reflection/H.php index bd626c3..a47725b 100644 --- a/tests/Utilities/Reflection/H.php +++ b/tests/Utilities/Reflection/H.php @@ -14,6 +14,9 @@ namespace Meritoo\Test\Common\Utilities\Reflection; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @coversNothing */ class H { diff --git a/tests/Utilities/Reflection/I.php b/tests/Utilities/Reflection/I.php index 020b149..50652a2 100644 --- a/tests/Utilities/Reflection/I.php +++ b/tests/Utilities/Reflection/I.php @@ -14,6 +14,8 @@ namespace Meritoo\Test\Common\Utilities\Reflection; * * @author Meritoo * @copyright Meritoo + * + * @internal */ interface I { diff --git a/tests/Utilities/Reflection/J.php b/tests/Utilities/Reflection/J.php index b646551..3affeb4 100644 --- a/tests/Utilities/Reflection/J.php +++ b/tests/Utilities/Reflection/J.php @@ -14,6 +14,9 @@ namespace Meritoo\Test\Common\Utilities\Reflection; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @coversNothing */ class J { diff --git a/tests/Utilities/Repository/Sortable.php b/tests/Utilities/Repository/Sortable.php index 82b2cfb..728438f 100644 --- a/tests/Utilities/Repository/Sortable.php +++ b/tests/Utilities/Repository/Sortable.php @@ -14,6 +14,9 @@ namespace Meritoo\Test\Common\Utilities\Repository; * * @author Meritoo * @copyright Meritoo + * + * @internal + * @coversNothing */ class Sortable { From b91606ada9c7c9705898764db848a7f6a86b1749 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 15 Sep 2019 20:14:23 +0200 Subject: [PATCH 097/137] Increase Mutation Score Indicator (MSI) by creating stronger tests of Arrays class --- src/Utilities/Arrays.php | 38 +- tests/Utilities/ArraysTest.php | 896 ++++++++++++++++++++++++++++++--- 2 files changed, 853 insertions(+), 81 deletions(-) diff --git a/src/Utilities/Arrays.php b/src/Utilities/Arrays.php index e3d57f9..0a77a3f 100644 --- a/src/Utilities/Arrays.php +++ b/src/Utilities/Arrays.php @@ -116,7 +116,7 @@ class Arrays * @param string $separator (optional) Separator used between values. Default: ",". * @return null|string */ - public static function values2csv(array $array, $separator = ',') + public static function values2csv(array $array, string $separator = ','): ?string { // No elements? Nothing to do if (empty($array)) { @@ -157,9 +157,9 @@ class Arrays * first element is returned (first of the First array). * @return bool */ - public static function isFirstElement(array $array, $element, $firstLevelOnly = true) + public static function isFirstElement(array $array, $element, bool $firstLevelOnly = true): bool { - $firstElement = self::getFirstElement($array, $firstLevelOnly); + $firstElement = static::getFirstElement($array, $firstLevelOnly); return $element === $firstElement; } @@ -175,21 +175,21 @@ class Arrays * first element is returned (first of the first array). * @return mixed */ - public static function getFirstElement(array $array, $firstLevelOnly = true) + public static function getFirstElement(array $array, bool $firstLevelOnly = true) { // No elements? Nothing to do if (empty($array)) { return null; } - $firstKey = self::getFirstKey($array); - $first = $array[$firstKey]; + $firstKey = static::getFirstKey($array); + $result = $array[$firstKey]; - if (!$firstLevelOnly && is_array($first)) { - $first = self::getFirstElement($first, $firstLevelOnly); + if (!$firstLevelOnly && is_array($result)) { + $result = static::getFirstElement($result, $firstLevelOnly); } - return $first; + return $result; } /** @@ -219,9 +219,9 @@ class Arrays * last element is returned (last of the latest array). * @return bool */ - public static function isLastElement(array $array, $element, $firstLevelOnly = true) + public static function isLastElement(array $array, $element, bool $firstLevelOnly = true): bool { - $lastElement = self::getLastElement($array, $firstLevelOnly); + $lastElement = static::getLastElement($array, $firstLevelOnly); return $element === $lastElement; } @@ -237,7 +237,7 @@ class Arrays * last element is returned (last of the latest array). * @return mixed */ - public static function getLastElement(array $array, $firstLevelOnly = true) + public static function getLastElement(array $array, bool $firstLevelOnly = true) { // No elements? Nothing to do if (empty($array)) { @@ -247,7 +247,7 @@ class Arrays $last = end($array); if (!$firstLevelOnly && is_array($last)) { - $last = self::getLastElement($last, $firstLevelOnly); + $last = static::getLastElement($last, $firstLevelOnly); } return $last; @@ -290,30 +290,30 @@ class Arrays * @param array $array The array to get the last row of * @return mixed */ - public static function getLastRow(array $array) + public static function getLastRow(array $array): ?array { // No elements? Nothing to do if (empty($array)) { return null; } - $effect = []; + $result = []; $last = end($array); if (is_array($last)) { // We've got an array, so looking for the last row of array will be done recursively - $effect = self::getLastRow($last); + $result = static::getLastRow($last); /* * The last row is not an array or it's an empty array? * Let's use the previous candidate */ - if (!is_array($effect) || self::isEmptyArray($effect)) { - $effect = $last; + if (!is_array($result) || static::isEmptyArray($result)) { + $result = $last; } } - return $effect; + return $result; } /** diff --git a/tests/Utilities/ArraysTest.php b/tests/Utilities/ArraysTest.php index 82e0c3e..385fc7a 100644 --- a/tests/Utilities/ArraysTest.php +++ b/tests/Utilities/ArraysTest.php @@ -128,7 +128,7 @@ class ArraysTest extends BaseTestCase * * @dataProvider provideArrayValues2csv */ - public function testValues2csv($description, $expected, array $array, $separator = ',') + public function testValues2csv(string $description, ?string $expected, array $array, string $separator = ','): void { // Required to avoid failure: // @@ -137,16 +137,7 @@ class ArraysTest extends BaseTestCase // 1,2,3,45 - actual Locale::setLocale(LC_ALL, 'en', 'US'); - self::assertSame($expected, Arrays::values2csv($array, $separator), $description); - self::assertSame('', Arrays::values2csv($this->simpleArray), 'Simple array'); - - self::assertSame( - "lorem,ipsum,dolor,sit,amet\n" - . "consectetur,adipiscing,elit\n" - . 'donec,sagittis,fringilla,eleifend', - Arrays::values2csv($this->twoDimensionsArray), - 'Two dimensions array' - ); + static::assertSame($expected, Arrays::values2csv($array, $separator), $description); } public function testGetFirstKey() @@ -166,43 +157,100 @@ class ArraysTest extends BaseTestCase self::assertEquals('amet', Arrays::getLastKey($this->complexArray)); } - public function testGetFirstElement() - { - // Negative cases - self::assertNull(Arrays::getFirstElement([])); + /** + * @param string $description + * @param $expected + * @param array $array + * @param null|bool $firstLevelOnly + * + * @dataProvider provideFirstElement + */ + public function testGetFirstElement( + string $description, + $expected, + array $array, + ?bool $firstLevelOnly = null + ): void { + if (null === $firstLevelOnly) { + static::assertSame($expected, Arrays::getFirstElement($array), $description); - // Positive cases - self::assertEquals('Lorem', Arrays::getFirstElement($this->simpleArray)); - self::assertEquals('Lorem', Arrays::getFirstElement($this->simpleArray)); - self::assertEquals('lorem', Arrays::getFirstElement($this->twoDimensionsArray, false)); - self::assertEquals('sit', Arrays::getFirstElement($this->complexArray, false)); + return; + } + + static::assertSame($expected, Arrays::getFirstElement($array, $firstLevelOnly), $description); } - public function testIsFirstElement() - { - self::assertTrue(Arrays::isFirstElement($this->simpleArray, 'Lorem')); - self::assertFalse(Arrays::isFirstElement($this->simpleArray, 'dolor')); - self::assertFalse(Arrays::isFirstElement($this->simpleArray, ' ')); - self::assertFalse(Arrays::isFirstElement($this->simpleArray, null)); + /** + * @param string $description + * @param bool $expected + * @param array $array + * @param $element + * @param bool $firstLevelOnly + * + * @dataProvider provideIsFirstElement + */ + public function testIsFirstElement( + string $description, + bool $expected, + array $array, + $element, + ?bool $firstLevelOnly = null + ): void { + if (null === $firstLevelOnly) { + static::assertSame($expected, Arrays::isFirstElement($array, $element), $description); + + return; + } + + static::assertSame($expected, Arrays::isFirstElement($array, $element, $firstLevelOnly), $description); } - public function testGetLastElement() - { - // Negative cases - self::assertNull(Arrays::getLastElement([])); + /** + * @param string $description + * @param $expected + * @param array $array + * @param null|bool $firstLevelOnly + * + * @dataProvider provideLastElement + */ + public function testGetLastElement( + string $description, + $expected, + array $array, + ?bool $firstLevelOnly = null + ): void { + if (null === $firstLevelOnly) { + static::assertSame($expected, Arrays::getLastElement($array), $description); - // Positive cases - self::assertEquals('amet', Arrays::getLastElement($this->simpleArray)); - self::assertEquals('eleifend', Arrays::getLastElement($this->twoDimensionsArray, false)); - self::assertEquals('primis', Arrays::getLastElement($this->complexArray, false)); + return; + } + + static::assertSame($expected, Arrays::getLastElement($array, $firstLevelOnly), $description); } - public function testIsLastElement() - { - self::assertTrue(Arrays::isLastElement($this->simpleArray, 'amet')); - self::assertFalse(Arrays::isLastElement($this->simpleArray, 'ipsum')); - self::assertFalse(Arrays::isLastElement($this->simpleArray, '')); - self::assertFalse(Arrays::isLastElement($this->simpleArray, null)); + /** + * @param string $description + * @param bool $expected + * @param array $array + * @param $element + * @param null|bool $firstLevelOnly + * + * @dataProvider provideIsLastElement + */ + public function testIsLastElement( + string $description, + bool $expected, + array $array, + $element, + ?bool $firstLevelOnly = null + ): void { + if (null === $firstLevelOnly) { + static::assertSame($expected, Arrays::isLastElement($array, $element), $description); + + return; + } + + static::assertSame($expected, Arrays::isLastElement($array, $element, $firstLevelOnly), $description); } public function testGetLastElementBreadCrumb() @@ -213,26 +261,16 @@ class ArraysTest extends BaseTestCase self::assertEquals('amet/1/primis', Arrays::getLastElementBreadCrumb($this->complexArray)); } - public function testGetLastRow(): void + /** + * @param string $description + * @param null|array $expected + * @param array $array + * + * @dataProvider provideLastRow + */ + public function testGetLastRow(string $description, ?array $expected, array $array): void { - // Negative cases - self::assertNull(Arrays::getLastRow([])); - - // Positive cases - self::assertEquals([], Arrays::getLastRow($this->simpleArray)); - self::assertEquals([], Arrays::getLastRow($this->simpleArrayWithKeys)); - - self::assertEquals([ - 'donec', - 'sagittis', - 'fringilla', - 'eleifend', - ], Arrays::getLastRow($this->twoDimensionsArray)); - - self::assertEquals([ - 'iaculis', - 'primis', - ], Arrays::getLastRow($this->complexArray)); + static::assertSame($expected, Arrays::getLastRow($array), $description); } /** @@ -898,7 +936,7 @@ letsTest[2] = value_2;'; self::assertEquals($effect, Arrays::setPositions($this->twoDimensionsArray)); - // Positive case - multi-level array + // Positive case - multidimensional array $array = [ 'lorem', 'ipsum' => [ @@ -1102,7 +1140,7 @@ letsTest[2] = value_2;'; // Empty array self::assertNull(Arrays::implodeSmart([], $separator)); - // Simple, one-dimension array + // Simple, One-dimensional array self::assertEquals(implode($separator, $this->simpleArray), Arrays::implodeSmart($this->simpleArray, $separator)); // An array with elements that contain separator @@ -2140,7 +2178,7 @@ letsTest[2] = value_2;'; ]; } - public function provideArrayValues2csv() + public function provideArrayValues2csv(): ?Generator { yield[ 'An empty array', @@ -2321,6 +2359,22 @@ letsTest[2] = value_2;'; ], ' // ', ]; + + yield[ + 'With HTML code', + "
abc
,def,
ghi
\nc,d", + [ + [ + '<div>abc</div>', + 'def', + '<div>ghi</div>', + ], + [ + 'c', + 'd', + ], + ], + ]; } public function provideArrayValues2string() @@ -2923,6 +2977,724 @@ letsTest[2] = value_2;'; ]; } + public function provideIsFirstElement(): ?Generator + { + yield[ + 'An empty array (first level only)', + false, + [], + '', + ]; + + yield[ + 'An empty array', + false, + [], + '', + false, + ]; + + yield[ + 'Non-existing integer in array with integers (first level only)', + false, + [ + 1, + 2, + 3, + ], + 4, + ]; + + yield[ + 'Existing integer in array with integers (first level only)', + true, + [ + 1, + 2, + 3, + ], + 1, + ]; + + yield[ + 'Existing integer in array with integers', + true, + [ + 1, + 2, + 3, + ], + 1, + false, + ]; + + yield[ + 'Non-existing integer in multidimensional array with integers (first level only)', + false, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 9, + ]; + + yield[ + 'Non-existing integer in multidimensional array with integers', + false, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 9, + false, + ]; + + yield[ + 'Existing integer in multidimensional array with integers, but first level only checked', + false, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 1, + ]; + + yield[ + 'Existing integer in multidimensional array with integers', + true, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 1, + false, + ]; + + yield[ + 'Non-existing element in multidimensional array (first level only)', + false, + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + 9, + ]; + + yield[ + 'Existing element in multidimensional array, but first level only checked', + false, + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + 'abc', + ]; + + yield[ + 'Existing element in multidimensional array', + true, + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + 'abc', + false, + ]; + } + + public function provideFirstElement(): ?Generator + { + yield[ + 'An empty array (first level only)', + null, + [], + ]; + + yield[ + 'An empty array', + null, + [], + false, + ]; + + yield[ + 'Multidimensional array (first level only)', + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + ]; + + yield[ + 'Multidimensional array', + 'abc', + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + false, + ]; + } + + public function provideIsLastElement(): ?Generator + { + yield[ + 'An empty array (first level only)', + false, + [], + '', + ]; + + yield[ + 'An empty array', + false, + [], + '', + false, + ]; + + yield[ + 'Non-existing integer in array with integers (first level only)', + false, + [ + 1, + 2, + 3, + ], + 4, + ]; + + yield[ + 'Existing integer in array with integers (first level only)', + true, + [ + 1, + 2, + 3, + ], + 3, + ]; + + yield[ + 'Existing integer in array with integers', + true, + [ + 1, + 2, + 3, + ], + 3, + false, + ]; + + yield[ + 'Non-existing integer in multidimensional array with integers (first level only)', + false, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 11, + ]; + + yield[ + 'Non-existing integer in multidimensional array with integers', + false, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 11, + false, + ]; + + yield[ + 'Existing integer in multidimensional array with integers, but first level only checked', + false, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 10, + ]; + + yield[ + 'Existing integer in multidimensional array with integers', + true, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 10, + false, + ]; + + yield[ + 'Non-existing element in multidimensional array (first level only)', + false, + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + 9, + ]; + + yield[ + 'Existing element in multidimensional array, but first level only checked', + false, + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 10, + '...', + 'jkl', + ], + ], + ], + 'jkl', + ]; + + yield[ + 'Existing element in multidimensional array', + true, + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 10, + '...', + 'jkl', + ], + ], + ], + 'jkl', + false, + ]; + } + + public function provideLastElement(): ?Generator + { + yield[ + 'An empty array (first level only)', + null, + [], + ]; + + yield[ + 'An empty array', + null, + [], + false, + ]; + + yield[ + 'One-dimensional array (first level only)', + 3, + [ + 1, + 2, + 3, + ], + ]; + + yield[ + 'One-dimensional array (first level only)', + 3, + [ + 1, + 2, + 3, + ], + false, + ]; + + yield[ + 'Multidimensional array (first level only)', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + ]; + + yield[ + 'Multidimensional array', + 10, + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + false, + ]; + } + + public function provideLastRow(): ?Generator + { + yield[ + 'An empty array', + null, + [], + ]; + + yield[ + 'One-dimensional array', + [], + [ + 'a', + 'b', + 1, + 2, + ], + ]; + + yield[ + 'Multidimensional array with scalar as last element', + [], + [ + 'a', + [ + 'b', + 'c', + ], + [ + 'e', + 'f', + ], + 1, + 2, + ], + ]; + + yield[ + 'Multidimensional array with an empty array as last element', + [], + [ + 'a', + [ + 'b', + 'c', + ], + 1, + 2, + [], + ], + ]; + + yield[ + 'Multidimensional array', + [ + 'e', + 'f', + ], + [ + 'a', + [ + 'b', + 'c', + ], + 1, + 2, + [ + 'e', + 'f', + ], + ], + ]; + } + /** * {@inheritdoc} */ From a7c39b26ba074a38d55cdad03231dd8147389002 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 18 Sep 2019 14:51:09 +0200 Subject: [PATCH 098/137] Rename Collection class to BaseCollection. Add BaseCollection::isValidType() method to validate type of element before add it to collection. Add BaseCollection ::prepareElements() method to allow preparation of elements in custom way. --- CHANGELOG.md | 6 + VERSION | 2 +- src/Collection/BaseCollection.php | 81 ++++++++++ src/Collection/Collection.php | 36 ----- src/Collection/DateTimeCollection.php | 27 ++++ src/Collection/IntegerCollection.php | 25 +++ src/Collection/StringCollection.php | 25 +++ src/Collection/Templates.php | 10 +- src/Traits/Collection/AddTrait.php | 12 +- src/Utilities/Reflection.php | 14 +- ...lectionTest.php => BaseCollectionTest.php} | 144 +++++++++++++----- .../Collection/Collection/ArrayCollection.php | 30 ++++ tests/Collection/DateTimeCollectionTest.php | 86 +++++++++++ tests/Collection/IntegerCollectionTest.php | 85 +++++++++++ tests/Collection/StringCollectionTest.php | 86 +++++++++++ .../Reflection/ObjectsCollection.php | 34 +++++ tests/Utilities/ReflectionTest.php | 22 +-- 17 files changed, 627 insertions(+), 98 deletions(-) create mode 100644 src/Collection/BaseCollection.php delete mode 100644 src/Collection/Collection.php create mode 100644 src/Collection/DateTimeCollection.php create mode 100644 src/Collection/IntegerCollection.php create mode 100644 src/Collection/StringCollection.php rename tests/Collection/{CollectionTest.php => BaseCollectionTest.php} (79%) create mode 100644 tests/Collection/Collection/ArrayCollection.php create mode 100644 tests/Collection/DateTimeCollectionTest.php create mode 100644 tests/Collection/IntegerCollectionTest.php create mode 100644 tests/Collection/StringCollectionTest.php create mode 100644 tests/Utilities/Reflection/ObjectsCollection.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f0876a2..daec50e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ Common and useful classes, methods, exceptions etc. +# 1.1.0 + +1. Rename Meritoo\Common\Collection\Collection class to Meritoo\Common\Collection\BaseCollection. +Add BaseCollection::isValidType() method to validate type of element before add it to collection. +Add BaseCollection ::prepareElements() method to allow preparation of elements in custom way. + # 1.0.6 1. Use `.env` instead of `.env.dist` diff --git a/VERSION b/VERSION index af0b7dd..9084fa2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.6 +1.1.0 diff --git a/src/Collection/BaseCollection.php b/src/Collection/BaseCollection.php new file mode 100644 index 0000000..293df6d --- /dev/null +++ b/src/Collection/BaseCollection.php @@ -0,0 +1,81 @@ + + * @copyright Meritoo + */ +abstract class BaseCollection implements Countable, ArrayAccess, IteratorAggregate +{ + use CollectionTrait; + + /** + * Class constructor + * + * @param array $elements (optional) The elements of collection + */ + public function __construct(array $elements = []) + { + $validated = $this->getElementsWithValidType($elements); + $this->elements = $this->prepareElements($validated); + } + + /** + * Prepares elements to initialize the collection. + * Feel free to override and prepare elements in your way. + * + * @param array $elements The elements of collection to prepare + * @return array + */ + protected function prepareElements(array $elements): array + { + return $elements; + } + + /** + * Returns elements of collection with valid types + * + * @param array $elements The elements of collection to verify + * @return array + */ + protected function getElementsWithValidType(array $elements): array + { + if (empty($elements)) { + return []; + } + + $result = []; + + foreach ($elements as $index => $element) { + if (!$this->isValidType($element)) { + continue; + } + + $result[$index] = $element; + } + + return $result; + } + + /** + * Returns information if given element has valid type + * + * @param mixed $element Element of collection + * @return bool + */ + abstract protected function isValidType($element): bool; +} diff --git a/src/Collection/Collection.php b/src/Collection/Collection.php deleted file mode 100644 index 6206ce5..0000000 --- a/src/Collection/Collection.php +++ /dev/null @@ -1,36 +0,0 @@ - - * @copyright Meritoo - */ -class Collection implements Countable, ArrayAccess, IteratorAggregate -{ - use CollectionTrait; - - /** - * Class constructor - * - * @param array $elements (optional) The elements of collection - */ - public function __construct(array $elements = []) - { - $this->elements = $elements; - } -} diff --git a/src/Collection/DateTimeCollection.php b/src/Collection/DateTimeCollection.php new file mode 100644 index 0000000..f31c4f1 --- /dev/null +++ b/src/Collection/DateTimeCollection.php @@ -0,0 +1,27 @@ + + * @copyright Meritoo + */ +class DateTimeCollection extends BaseCollection +{ + protected function isValidType($element): bool + { + return $element instanceof DateTime; + } +} diff --git a/src/Collection/IntegerCollection.php b/src/Collection/IntegerCollection.php new file mode 100644 index 0000000..d284f71 --- /dev/null +++ b/src/Collection/IntegerCollection.php @@ -0,0 +1,25 @@ + + * @copyright Meritoo + */ +class IntegerCollection extends BaseCollection +{ + protected function isValidType($element): bool + { + return is_int($element); + } +} diff --git a/src/Collection/StringCollection.php b/src/Collection/StringCollection.php new file mode 100644 index 0000000..2d9a191 --- /dev/null +++ b/src/Collection/StringCollection.php @@ -0,0 +1,25 @@ + + * @copyright Meritoo + */ +class StringCollection extends BaseCollection +{ + protected function isValidType($element): bool + { + return is_string($element); + } +} diff --git a/src/Collection/Templates.php b/src/Collection/Templates.php index 0ebe86c..dbda2d0 100644 --- a/src/Collection/Templates.php +++ b/src/Collection/Templates.php @@ -19,7 +19,7 @@ use Meritoo\Common\ValueObject\Template; * @author Meritoo * @copyright Meritoo */ -class Templates extends Collection +class Templates extends BaseCollection { /** * Finds and returns template with given index @@ -61,4 +61,12 @@ class Templates extends Collection return $result; } + + /** + * {@inheritdoc} + */ + protected function isValidType($element): bool + { + return $element instanceof Template; + } } diff --git a/src/Traits/Collection/AddTrait.php b/src/Traits/Collection/AddTrait.php index 0714ec9..1cda8b2 100644 --- a/src/Traits/Collection/AddTrait.php +++ b/src/Traits/Collection/AddTrait.php @@ -8,7 +8,7 @@ namespace Meritoo\Common\Traits\Collection; -use Meritoo\Common\Collection\Collection; +use Meritoo\Common\Collection\BaseCollection; /** * Trait for the Collection with add*() methods @@ -26,6 +26,10 @@ trait AddTrait */ public function add($element, $index = null): void { + if (!$this->isValidType($element)) { + return; + } + if (null === $index || '' === $index) { $this->elements[] = $element; @@ -38,9 +42,9 @@ trait AddTrait /** * Adds given elements (at the end of collection) * - * @param array|Collection $elements The elements to add - * @param bool|false $useIndexes (optional) If is set to true, indexes of given elements will be used in - * this collection. Otherwise - not. + * @param array|BaseCollection $elements The elements to add + * @param bool $useIndexes (optional) If is set to true, indexes of given elements will be used in + * this collection. Otherwise - not. */ public function addMultiple($elements, bool $useIndexes = false): void { diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index 96ccce7..9508ba2 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -10,7 +10,7 @@ namespace Meritoo\Common\Utilities; use Doctrine\Common\Inflector\Inflector; use Doctrine\Common\Persistence\Proxy; -use Meritoo\Common\Collection\Collection; +use Meritoo\Common\Collection\BaseCollection; use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException; use Meritoo\Common\Exception\Reflection\MissingChildClassesException; use Meritoo\Common\Exception\Reflection\NotExistingPropertyException; @@ -207,11 +207,11 @@ class Reflection * Returns values of given property for given objects. * Looks for proper getter for the property. * - * @param array|Collection|object $objects The objects that should contain given property. It may be also one - * object. - * @param string $property Name of the property that contains a value - * @param bool $force (optional) If is set to true, try to retrieve value even if the - * object does not have property. Otherwise - not. + * @param array|BaseCollection|object $objects The objects that should contain given property. It may be also one + * object. + * @param string $property Name of the property that contains a value + * @param bool $force (optional) If is set to true, try to retrieve value even if the + * object does not have property. Otherwise - not. * @return array */ public static function getPropertyValues($objects, string $property, bool $force = false): array @@ -224,7 +224,7 @@ class Reflection return []; } - if ($objects instanceof Collection) { + if ($objects instanceof BaseCollection) { $objects = $objects->toArray(); } diff --git a/tests/Collection/CollectionTest.php b/tests/Collection/BaseCollectionTest.php similarity index 79% rename from tests/Collection/CollectionTest.php rename to tests/Collection/BaseCollectionTest.php index 6eb469e..2906193 100644 --- a/tests/Collection/CollectionTest.php +++ b/tests/Collection/BaseCollectionTest.php @@ -10,9 +10,12 @@ namespace Meritoo\Test\Common\Collection; use ArrayIterator; use Generator; -use Meritoo\Common\Collection\Collection; +use Meritoo\Common\Collection\BaseCollection; +use Meritoo\Common\Collection\DateTimeCollection; +use Meritoo\Common\Collection\StringCollection; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; +use Meritoo\Test\Common\Collection\Collection\ArrayCollection; use ReflectionClass; /** @@ -22,21 +25,21 @@ use ReflectionClass; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Collection\Collection + * @covers \Meritoo\Common\Collection\BaseCollection */ -class CollectionTest extends BaseTestCase +class BaseCollectionTest extends BaseTestCase { /** * An empty collection * - * @var Collection + * @var StringCollection */ private $emptyCollection; /** * Simple collection * - * @var Collection + * @var StringCollection */ private $simpleCollection; @@ -135,14 +138,14 @@ class CollectionTest extends BaseTestCase } /** - * @param mixed $element The element to add - * @param int $expectedCount Expected count of elements in collection - * @param int $expectedIndex Expected index of added element in collection - * @param Collection $collection The collection + * @param mixed $element The element to add + * @param int $expectedCount Expected count of elements in collection + * @param int $expectedIndex Expected index of added element in collection + * @param BaseCollection $collection The collection * * @dataProvider provideElementToAdd */ - public function testAddWithoutIndex($element, $expectedCount, $expectedIndex, Collection $collection) + public function testAddWithoutIndex($element, $expectedCount, $expectedIndex, BaseCollection $collection) { $collection->add($element); @@ -152,15 +155,15 @@ class CollectionTest extends BaseTestCase } /** - * @param mixed $element The element to add - * @param mixed $index Index of element to add - * @param int $expectedCount Expected count of elements in collection - * @param int $expectedIndex Expected index of added element in collection - * @param Collection $collection The collection + * @param mixed $element The element to add + * @param mixed $index Index of element to add + * @param int $expectedCount Expected count of elements in collection + * @param int $expectedIndex Expected index of added element in collection + * @param BaseCollection $collection The collection * * @dataProvider provideElementToAddWithIndex */ - public function testAddWithIndex($element, $index, $expectedCount, $expectedIndex, Collection $collection) + public function testAddWithIndex($element, $index, $expectedCount, $expectedIndex, BaseCollection $collection) { $collection->add($element, $index); @@ -328,7 +331,7 @@ class CollectionTest extends BaseTestCase public function testExistsVisibilityAndArguments() { - $reflectionClass = new ReflectionClass(Collection::class); + $reflectionClass = new ReflectionClass(BaseCollection::class); $method = $reflectionClass->getMethod('exists'); static::assertMethodVisibility($method, OopVisibilityType::IS_PRIVATE); @@ -336,18 +339,31 @@ class CollectionTest extends BaseTestCase } /** - * @param string $description Description of test - * @param Collection $collection Collection to search for element with given index - * @param mixed $index Index / key of the element - * @param mixed $expected Expected element with given index + * @param string $description Description of test + * @param BaseCollection $collection Collection to search for element with given index + * @param mixed $index Index / key of the element + * @param mixed $expected Expected element with given index * * @dataProvider provideElementGetByIndex */ - public function testGetByIndex($description, Collection $collection, $index, $expected) + public function testGetByIndex($description, BaseCollection $collection, $index, $expected) { static::assertEquals($expected, $collection->getByIndex($index), $description); } + /** + * @param string $description + * @param array $elements + * @param array $expected + * + * @dataProvider provideElementsToValidateType + */ + public function testGetElementsWithValidType(string $description, array $elements, array $expected): void + { + $collection = new ArrayCollection($elements); + static::assertSame($expected, $collection->toArray(), $description); + } + /** * Provides element to add to collection * @@ -359,14 +375,14 @@ class CollectionTest extends BaseTestCase 'This is test 1', 1, 0, - new Collection(), + new StringCollection(), ]; yield[ 'This is test 2', 2, 1, - new Collection([ + new StringCollection([ 'I am 1st', ]), ]; @@ -375,7 +391,7 @@ class CollectionTest extends BaseTestCase 'This is test 3', 3, 2, - new Collection([ + new StringCollection([ 'I am 1st', 'I am 2nd', ]), @@ -394,7 +410,7 @@ class CollectionTest extends BaseTestCase 'test1', 1, 'test1', - new Collection(), + new StringCollection(), ]; yield[ @@ -402,7 +418,7 @@ class CollectionTest extends BaseTestCase 'test2', 2, 'test2', - new Collection([ + new StringCollection([ 'test1' => 'I am 1st', ]), ]; @@ -412,7 +428,7 @@ class CollectionTest extends BaseTestCase null, 3, 0, - new Collection([ + new StringCollection([ 'test1' => 'I am 1st', 'test2' => 'I am 2nd', ]), @@ -423,7 +439,7 @@ class CollectionTest extends BaseTestCase '', 4, 1, - new Collection([ + new StringCollection([ 'test1' => 'I am 1st', 'test2' => 'I am 2nd', 'I am 3rd', @@ -435,7 +451,7 @@ class CollectionTest extends BaseTestCase 'test5', 5, 'test5', - new Collection([ + new StringCollection([ 'test1' => 'I am 1st', 'test2' => 'I am 2nd', 2 => 'I am 3rd', @@ -448,7 +464,7 @@ class CollectionTest extends BaseTestCase 'test2', 4, 'test2', - new Collection([ + new StringCollection([ 'test1' => 'I am 1st', 'test2' => 'I am 2nd', 2 => 'I am 3rd', @@ -461,21 +477,21 @@ class CollectionTest extends BaseTestCase { yield[ 'An empty collection and empty index', - new Collection(), + new StringCollection(), '', null, ]; yield[ 'An empty collection and non-empty index', - new Collection(), + new StringCollection(), 'test', null, ]; yield[ 'Non-empty collection and not existing index', - new Collection([ + new StringCollection([ 'lorem' => 'ipsum', 'dolor' => 'sit', ]), @@ -485,7 +501,7 @@ class CollectionTest extends BaseTestCase yield[ 'Collection with existing index', - new Collection([ + new StringCollection([ 'lorem' => 'ipsum', 'dolor' => 'sit', ]), @@ -495,7 +511,7 @@ class CollectionTest extends BaseTestCase yield[ 'Collection with existing index (collection of arrays)', - new Collection([ + new ArrayCollection([ [ 'lorem', 'ipsum', @@ -514,7 +530,7 @@ class CollectionTest extends BaseTestCase yield[ 'Collection with existing index (collection of objects)', - new Collection([ + new DateTimeCollection([ 'x' => new \DateTime(), 'y' => new \DateTime('2001-01-01'), 'z' => new \DateTime('yesterday'), @@ -524,6 +540,56 @@ class CollectionTest extends BaseTestCase ]; } + public function provideElementsToValidateType(): ?Generator + { + yield[ + 'An empty array', + [], + [], + ]; + + yield[ + 'Valid elements only', + [ + [], + [ + '123', + 456, + ], + ], + [ + [], + [ + '123', + 456, + ], + ], + ]; + + yield[ + 'Mixed elements', + [ + 1, + 'test', + '', + [], + 234, + 'test', + [ + '123', + 456, + ], + ], + [ + 3 => [], + 6 => [ + '123', + 456, + ], + ], + ]; + } + /** * {@inheritdoc} */ @@ -538,7 +604,7 @@ class CollectionTest extends BaseTestCase 345 => 'sit', ]; - $this->emptyCollection = new Collection(); - $this->simpleCollection = new Collection($this->simpleElements); + $this->emptyCollection = new StringCollection(); + $this->simpleCollection = new StringCollection($this->simpleElements); } } diff --git a/tests/Collection/Collection/ArrayCollection.php b/tests/Collection/Collection/ArrayCollection.php new file mode 100644 index 0000000..2ad9627 --- /dev/null +++ b/tests/Collection/Collection/ArrayCollection.php @@ -0,0 +1,30 @@ + + * @copyright Meritoo + * + * @internal + * @coversNothing + */ +class ArrayCollection extends BaseCollection +{ + protected function isValidType($element): bool + { + return is_array($element); + } +} diff --git a/tests/Collection/DateTimeCollectionTest.php b/tests/Collection/DateTimeCollectionTest.php new file mode 100644 index 0000000..f8cdd1c --- /dev/null +++ b/tests/Collection/DateTimeCollectionTest.php @@ -0,0 +1,86 @@ + + * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Collection\DateTimeCollection + */ +class DateTimeCollectionTest extends BaseTestCase +{ + public function testConstructor(): void + { + static::assertConstructorVisibilityAndArguments( + DateTimeCollection::class, + OopVisibilityType::IS_PUBLIC, + 1 + ); + } + + /** + * @param string $description + * @param array $elements + * @param array $expectedElements + * + * @dataProvider provideDifferentTypesOfElements + */ + public function testCreateWithDifferentTypesOfElements( + string $description, + array $elements, + array $expectedElements + ): void { + $collection = new DateTimeCollection($elements); + static::assertEquals($expectedElements, $collection->toArray(), $description); + } + + public function provideDifferentTypesOfElements(): ?Generator + { + yield[ + 'An empty array', + [], + [], + ]; + + yield[ + 'Valid elements only', + [ + new DateTime('2001-01-01'), + new DateTime('2001-01-02'), + ], + [ + new DateTime('2001-01-01'), + new DateTime('2001-01-02'), + ], + ]; + + yield[ + 'Mixed elements', + [ + 1, + 'test', + new DateTime('2001-01-01'), + '', + [], + 234, + new DateTime('2001-01-02'), + ], + [ + 2 => new DateTime('2001-01-01'), + 6 => new DateTime('2001-01-02'), + ], + ]; + } +} diff --git a/tests/Collection/IntegerCollectionTest.php b/tests/Collection/IntegerCollectionTest.php new file mode 100644 index 0000000..51d62be --- /dev/null +++ b/tests/Collection/IntegerCollectionTest.php @@ -0,0 +1,85 @@ + + * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Collection\IntegerCollection + */ +class IntegerCollectionTest extends BaseTestCase +{ + public function testConstructor(): void + { + static::assertConstructorVisibilityAndArguments( + IntegerCollection::class, + OopVisibilityType::IS_PUBLIC, + 1 + ); + } + + /** + * @param string $description + * @param array $elements + * @param array $expectedElements + * + * @dataProvider provideDifferentTypesOfElements + */ + public function testCreateWithDifferentTypesOfElements( + string $description, + array $elements, + array $expectedElements + ): void { + $collection = new IntegerCollection($elements); + static::assertSame($expectedElements, $collection->toArray(), $description); + } + + public function provideDifferentTypesOfElements(): ?\Generator + { + yield[ + 'An empty array', + [], + [], + ]; + + yield[ + 'Valid elements only', + [ + 1, + 2, + 3, + ], + [ + 1, + 2, + 3, + ], + ]; + + yield[ + 'Mixed elements', + [ + 1, + 'test', + '', + [], + 234, + 'test', + ], + [ + 0 => 1, + 4 => 234, + ], + ]; + } +} diff --git a/tests/Collection/StringCollectionTest.php b/tests/Collection/StringCollectionTest.php new file mode 100644 index 0000000..96101a5 --- /dev/null +++ b/tests/Collection/StringCollectionTest.php @@ -0,0 +1,86 @@ + + * @copyright Meritoo + * + * @internal + * @covers \Meritoo\Common\Collection\StringCollection + */ +class StringCollectionTest extends BaseTestCase +{ + public function testConstructor(): void + { + static::assertConstructorVisibilityAndArguments( + StringCollection::class, + OopVisibilityType::IS_PUBLIC, + 1 + ); + } + + /** + * @param string $description + * @param array $elements + * @param array $expectedElements + * + * @dataProvider provideDifferentTypesOfElements + */ + public function testCreateWithDifferentTypesOfElements( + string $description, + array $elements, + array $expectedElements + ): void { + $collection = new StringCollection($elements); + static::assertSame($expectedElements, $collection->toArray(), $description); + } + + public function provideDifferentTypesOfElements(): ?\Generator + { + yield[ + 'An empty array', + [], + [], + ]; + + yield[ + 'Valid elements only', + [ + '1', + 'test', + '', + ], + [ + '1', + 'test', + '', + ], + ]; + + yield[ + 'Mixed elements', + [ + 1, + 'test', + '', + [], + 234, + 'test', + ], + [ + 1 => 'test', + 2 => '', + 5 => 'test', + ], + ]; + } +} diff --git a/tests/Utilities/Reflection/ObjectsCollection.php b/tests/Utilities/Reflection/ObjectsCollection.php new file mode 100644 index 0000000..d51ea05 --- /dev/null +++ b/tests/Utilities/Reflection/ObjectsCollection.php @@ -0,0 +1,34 @@ + + * @copyright Meritoo + * + * @internal + * @coversNothing + */ +class ObjectsCollection extends BaseCollection +{ + protected function isValidType($element): bool + { + return $element instanceof A + || $element instanceof B + || $element instanceof C + || $element instanceof D + || $element instanceof F; + } +} diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 5c5b6b1..1f9ff30 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -10,7 +10,8 @@ namespace Meritoo\Test\Common\Utilities; use DateTime; use Generator; -use Meritoo\Common\Collection\Collection; +use Meritoo\Common\Collection\BaseCollection; +use Meritoo\Common\Collection\Templates; use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException; use Meritoo\Common\Exception\Reflection\MissingChildClassesException; use Meritoo\Common\Exception\Reflection\NotExistingPropertyException; @@ -27,6 +28,7 @@ use Meritoo\Test\Common\Utilities\Reflection\G; use Meritoo\Test\Common\Utilities\Reflection\H; use Meritoo\Test\Common\Utilities\Reflection\I; use Meritoo\Test\Common\Utilities\Reflection\J; +use Meritoo\Test\Common\Utilities\Reflection\ObjectsCollection; use ReflectionProperty; use stdClass; @@ -83,13 +85,13 @@ class ReflectionTest extends BaseTestCase public function testGetClassWhileNamespaceContainsClassName(): void { self::assertEquals( - Collection::class, - Reflection::getClassName(Collection::class) + BaseCollection::class, + Reflection::getClassName(BaseCollection::class) ); self::assertEquals( - 'Collection', - Reflection::getClassName(Collection::class, true) + 'BaseCollection', + Reflection::getClassName(BaseCollection::class, true) ); } @@ -118,7 +120,7 @@ class ReflectionTest extends BaseTestCase { self::assertEquals( 'Meritoo\Common\Collection', - Reflection::getClassNamespace(Collection::class) + Reflection::getClassNamespace(BaseCollection::class) ); } @@ -320,7 +322,7 @@ class ReflectionTest extends BaseTestCase public function testGetPropertyValuesFromEmptySource(): void { self::assertEquals([], Reflection::getPropertyValues([], 'something')); - self::assertEquals([], Reflection::getPropertyValues(new Collection(), 'something')); + self::assertEquals([], Reflection::getPropertyValues(new Templates(), 'something')); } public function testGetPropertyValuesOfNotExistingPropertyFromSingleObject(): void @@ -344,7 +346,7 @@ class ReflectionTest extends BaseTestCase self::assertEquals([], Reflection::getPropertyValues($objects, 'something')); self::assertEquals([], Reflection::getPropertyValues($objects, 'something', true)); - $collection = new Collection($objects); + $collection = new ObjectsCollection($objects); self::assertEquals([], Reflection::getPropertyValues($collection, 'something')); self::assertEquals([], Reflection::getPropertyValues($collection, 'something', true)); @@ -373,7 +375,7 @@ class ReflectionTest extends BaseTestCase self::assertEquals($expected, Reflection::getPropertyValues($objects, 'city')); self::assertEquals($expected, Reflection::getPropertyValues($objects, 'city', true)); - $collection = new Collection($objects); + $collection = new ObjectsCollection($objects); self::assertEquals($expected, Reflection::getPropertyValues($collection, 'city')); self::assertEquals($expected, Reflection::getPropertyValues($collection, 'city', true)); @@ -408,7 +410,7 @@ class ReflectionTest extends BaseTestCase self::assertEquals($expected, Reflection::getPropertyValues($objects, 'g.firstName')); self::assertEquals($expected, Reflection::getPropertyValues($objects, 'g.firstName', true)); - $collection = new Collection($objects); + $collection = new ObjectsCollection($objects); self::assertEquals($expected, Reflection::getPropertyValues($collection, 'g.firstName')); self::assertEquals($expected, Reflection::getPropertyValues($collection, 'g.firstName', true)); From 2fdb18312dfbdf97155ccc2eb703f57a270f075b Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 18 Sep 2019 14:54:02 +0200 Subject: [PATCH 099/137] Remove project configuration (project files related to IDE) --- .idea/.name | 1 - .idea/Meritoo Common Library.iml | 112 ----------- .idea/composerJson.xml | 10 - .idea/inspectionProfiles/Project_Default.xml | 127 ------------ .idea/misc.xml | 6 - .idea/modules.xml | 8 - .idea/php-test-framework.xml | 14 -- .idea/php.xml | 198 ------------------- .idea/symfony2.xml | 6 - .idea/vcs.xml | 6 - 10 files changed, 488 deletions(-) delete mode 100644 .idea/.name delete mode 100644 .idea/Meritoo Common Library.iml delete mode 100644 .idea/composerJson.xml delete mode 100644 .idea/inspectionProfiles/Project_Default.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/php-test-framework.xml delete mode 100644 .idea/php.xml delete mode 100644 .idea/symfony2.xml delete mode 100644 .idea/vcs.xml diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index af2d727..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -Meritoo Common Library \ No newline at end of file diff --git a/.idea/Meritoo Common Library.iml b/.idea/Meritoo Common Library.iml deleted file mode 100644 index b0760a9..0000000 --- a/.idea/Meritoo Common Library.iml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/composerJson.xml b/.idea/composerJson.xml deleted file mode 100644 index 1b07430..0000000 --- a/.idea/composerJson.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 82b4c38..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,127 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 28a804d..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 2ae0b8c..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/php-test-framework.xml b/.idea/php-test-framework.xml deleted file mode 100644 index fd66dd0..0000000 --- a/.idea/php-test-framework.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/php.xml b/.idea/php.xml deleted file mode 100644 index 0b27612..0000000 --- a/.idea/php.xml +++ /dev/null @@ -1,198 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /usr/local/etc/php/conf.d/docker-php-ext-imagick.ini, /usr/local/etc/php/conf.d/docker-php-ext-intl.ini, /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini, /usr/local/etc/php/conf.d/docker-php-ext-pdo_mysql.ini, /usr/local/etc/php/conf.d/docker-php-ext-sodium.ini, /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini, /usr/local/etc/php/conf.d/docker-php-ext-zip.ini, /usr/local/etc/php/conf.d/tzone.ini - /usr/local/etc/php/php.ini - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/symfony2.xml b/.idea/symfony2.xml deleted file mode 100644 index 632dba4..0000000 --- a/.idea/symfony2.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From d8e3d5e7cb7c91fc31aa560966289831979d01f8 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 18 Sep 2019 15:11:51 +0200 Subject: [PATCH 100/137] Update documentation of BaseCollection class --- README.md | 2 +- docs/Base-test-case.md | 2 +- .../{Collection.md => BaseCollection.md} | 55 ++++++++++++++----- docs/Collection/Templates.md | 2 +- docs/Exceptions.md | 2 +- docs/Static-methods.md | 2 +- docs/Static-methods/Arrays.md | 2 +- docs/Static-methods/Regex.md | 2 +- docs/Static-methods/Uri.md | 2 +- docs/Value-Objects.md | 2 +- 10 files changed, 51 insertions(+), 22 deletions(-) rename docs/Collection/{Collection.md => BaseCollection.md} (50%) diff --git a/README.md b/README.md index b8fe66f..1155ac4 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ composer require meritoo/common-library # Usage 1. [Base test case (with common methods and data providers)](docs/Base-test-case.md) -2. [Collection of elements](docs/Collection/Collection.md) +2. [Collection of elements](docs/Collection/BaseCollection.md) 3. [Exceptions](docs/Static-methods.md) 4. [Static methods](docs/Static-methods.md) 1. [Arrays](docs/Static-methods/Arrays.md) diff --git a/docs/Base-test-case.md b/docs/Base-test-case.md index 3f7ef40..05b7ce3 100644 --- a/docs/Base-test-case.md +++ b/docs/Base-test-case.md @@ -51,7 +51,7 @@ class MimeTypesTest extends BaseTestCase # More 1. [**Base test case (with common methods and data providers)**](Base-test-case.md) -2. [Collection of elements](Collection/Collection.md) +2. [Collection of elements](Collection/BaseCollection.md) 3. [Templates](Collection/Templates.md) 4. [Exceptions](Exceptions.md) 5. [Static methods](Static-methods.md) diff --git a/docs/Collection/Collection.md b/docs/Collection/BaseCollection.md similarity index 50% rename from docs/Collection/Collection.md rename to docs/Collection/BaseCollection.md index c2f8f61..63003b4 100644 --- a/docs/Collection/Collection.md +++ b/docs/Collection/BaseCollection.md @@ -2,15 +2,16 @@ Common and useful classes, methods, exceptions etc. -# Collection +# BaseCollection ### Namespace -`Meritoo\Common\Collection\Collection` +`Meritoo\Common\Collection\BaseCollection` ### Info -It's a set of some elements, e.g. objects. It's iterable and countable. Provides very useful methods. Some of them: +It's a set of some elements with the same type, e.g. objects. It's iterable and countable. Provides very useful +methods. Some of them: - `getFirst()` - returns the first element in the collection - `getLast()` - returns the last element in the collection - `isEmpty()` - returns information if collection is empty @@ -19,21 +20,49 @@ It's a set of some elements, e.g. objects. It's iterable and countable. Provides - `prepend($element)` - prepends given element (adds given element at the beginning of collection) - `remove($element)` - removes given element -Examples of usage below. +### Implementation -### An empty collection +You have to implement: ```php -use Meritoo\Common\Collection\Collection; - -$emptyCollection = new Collection(); -var_dump($emptyCollection->isEmpty()); // bool(true) +abstract protected function isValidType($element): bool; ``` -### Simple collection +This method verifies 1 element before it will be added to collection. Returns information if the element has valid, +expected type. + +Example (from `Meritoo\Common\Collection\Templates` class): ```php -use Meritoo\Common\Collection\Collection; +protected function isValidType($element): bool +{ + return $element instanceof Template; +} +``` + +### Methods to overwrite + +You can, if you wish, overwrite these methods: + +1. To prepare elements used to initialize the collection in your own way: + + ```php + protected function prepareElements(array $elements): array + ``` + +2. To validate type of elements in your own way: + + ```php + protected function getElementsWithValidType(array $elements): array + ``` + +### Examples of usage + +```php +use Meritoo\Common\Collection\StringCollection; + +$emptyCollection = new StringCollection(); +var_dump($emptyCollection->isEmpty()); // bool(true) $elements = [ 'lorem', @@ -42,14 +71,14 @@ $elements = [ 345 => 'sit', ]; -$simpleCollection = new Collection($elements); +$simpleCollection = new StringCollection($elements); var_dump($simpleCollection->has('dolor')); // bool(true) ``` # More 1. [Base test case (with common methods and data providers)](../Base-test-case.md) -2. [**Collection of elements**](Collection.md) +2. [**Collection of elements**](BaseCollection.md) 3. [Templates](Templates.md) 4. [Exceptions](../Exceptions.md) 5. [Static methods](../Static-methods.md) diff --git a/docs/Collection/Templates.md b/docs/Collection/Templates.md index c4fa36a..276b3d2 100644 --- a/docs/Collection/Templates.md +++ b/docs/Collection/Templates.md @@ -54,7 +54,7 @@ Throws an `Meritoo\Common\Exception\ValueObject\Template\TemplateNotFoundExcepti # More 1. [Base test case (with common methods and data providers)](../Base-test-case.md) -2. [Collection of elements](Collection.md) +2. [Collection of elements](BaseCollection.md) 3. [**Templates**](Templates.md) 4. [Exceptions](../Exceptions.md) 5. [Static methods](../Static-methods.md) diff --git a/docs/Exceptions.md b/docs/Exceptions.md index 49c38f2..1c70d23 100644 --- a/docs/Exceptions.md +++ b/docs/Exceptions.md @@ -54,7 +54,7 @@ class UnknownSimpleTypeException extends UnknownTypeException # More 1. [Base test case (with common methods and data providers)](Base-test-case.md) -2. [Collection of elements](Collection/Collection.md) +2. [Collection of elements](Collection/BaseCollection.md) 3. [Templates](Collection/Templates.md) 4. [**Exceptions**](Exceptions.md) 5. [Static methods](Static-methods.md) diff --git a/docs/Static-methods.md b/docs/Static-methods.md index 0b225e0..9cf5f65 100644 --- a/docs/Static-methods.md +++ b/docs/Static-methods.md @@ -16,7 +16,7 @@ var_dump($firstElement); // string(5) "lorem" # More 1. [Base test case (with common methods and data providers)](Base-test-case.md) -2. [Collection of elements](Collection/Collection.md) +2. [Collection of elements](Collection/BaseCollection.md) 3. [Templates](Collection/Templates.md) 4. [Exceptions](Exceptions.md) 5. [**Static methods**](Static-methods.md) diff --git a/docs/Static-methods/Arrays.md b/docs/Static-methods/Arrays.md index 7169a55..c50cd16 100644 --- a/docs/Static-methods/Arrays.md +++ b/docs/Static-methods/Arrays.md @@ -95,7 +95,7 @@ File: `src/Utilities/Arrays.php` # More 1. [Base test case (with common methods and data providers)](../Base-test-case.md) -2. [Collection of elements](../Collection/Collection.md) +2. [Collection of elements](../Collection/BaseCollection.md) 3. [Templates](../Collection/Templates.md) 4. [Exceptions](../Exceptions.md) 5. [Static methods](../Static-methods.md) diff --git a/docs/Static-methods/Regex.md b/docs/Static-methods/Regex.md index 1a4a48b..6c0d0c4 100644 --- a/docs/Static-methods/Regex.md +++ b/docs/Static-methods/Regex.md @@ -87,7 +87,7 @@ File: `src/Utilities/Regex.php` # More 1. [Base test case (with common methods and data providers)](../Base-test-case.md) -2. [Collection of elements](../Collection/Collection.md) +2. [Collection of elements](../Collection/BaseCollection.md) 3. [Templates](../Collection/Templates.md) 4. [Exceptions](../Exceptions.md) 5. [Static methods](../Static-methods.md) diff --git a/docs/Static-methods/Uri.md b/docs/Static-methods/Uri.md index 5808d31..0d64259 100644 --- a/docs/Static-methods/Uri.md +++ b/docs/Static-methods/Uri.md @@ -35,7 +35,7 @@ File: `src/Utilities/Uri.php` # More 1. [Base test case (with common methods and data providers)](../Base-test-case.md) -2. [Collection of elements](../Collection/Collection.md) +2. [Collection of elements](../Collection/BaseCollection.md) 3. [Templates](../Collection/Templates.md) 4. [Exceptions](../Exceptions.md) 5. [Static methods](../Static-methods.md) diff --git a/docs/Value-Objects.md b/docs/Value-Objects.md index 83184de..47777f2 100644 --- a/docs/Value-Objects.md +++ b/docs/Value-Objects.md @@ -338,7 +338,7 @@ $asString = (string)$version; // "1.0.2" # More 1. [Base test case (with common methods and data providers)](Base-test-case.md) -2. [Collection of elements](Collection/Collection.md) +2. [Collection of elements](Collection/BaseCollection.md) 3. [Templates](Collection/Templates.md) 4. [Exceptions](Exceptions.md) 5. [Static methods](Static-methods.md) From 872259e63d1dcd8214e3e3f52a763f718576801a Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 19 Sep 2019 12:33:03 +0200 Subject: [PATCH 101/137] [BaseCollection] Treat the `null` index as "no index" only while adding new element, iow. do not treat empty string as "no index" behaviour --- CHANGELOG.md | 5 +++++ VERSION | 2 +- src/Traits/Collection/AddTrait.php | 2 +- tests/Collection/BaseCollectionTest.php | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index daec50e..f3f4780 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Common and useful classes, methods, exceptions etc. +# 1.1.1 + +1. [BaseCollection] Treat the `null` index as "no index" only while adding new element, iow. do not treat empty +string as "no index" behaviour. + # 1.1.0 1. Rename Meritoo\Common\Collection\Collection class to Meritoo\Common\Collection\BaseCollection. diff --git a/VERSION b/VERSION index 9084fa2..524cb55 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.0 +1.1.1 diff --git a/src/Traits/Collection/AddTrait.php b/src/Traits/Collection/AddTrait.php index 1cda8b2..4ac35aa 100644 --- a/src/Traits/Collection/AddTrait.php +++ b/src/Traits/Collection/AddTrait.php @@ -30,7 +30,7 @@ trait AddTrait return; } - if (null === $index || '' === $index) { + if (null === $index) { $this->elements[] = $element; return; diff --git a/tests/Collection/BaseCollectionTest.php b/tests/Collection/BaseCollectionTest.php index 2906193..0f7a482 100644 --- a/tests/Collection/BaseCollectionTest.php +++ b/tests/Collection/BaseCollectionTest.php @@ -438,7 +438,7 @@ class BaseCollectionTest extends BaseTestCase 'This is test 4', '', 4, - 1, + '', new StringCollection([ 'test1' => 'I am 1st', 'test2' => 'I am 2nd', From ddb3f0a544f41be7ade45eaec4a52e7828c1cbde Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 18 Dec 2019 20:25:06 +0100 Subject: [PATCH 102/137] [Miscellaneous] [Regex] Use simpler & stronger pattern to match name of file --- CHANGELOG.md | 1 + src/Utilities/Miscellaneous.php | 8 ++++---- src/Utilities/Regex.php | 6 +++--- tests/Utilities/MiscellaneousTest.php | 5 ++++- tests/Utilities/RegexTest.php | 5 ++++- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3f4780..6dae0a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Common and useful classes, methods, exceptions etc. 1. [BaseCollection] Treat the `null` index as "no index" only while adding new element, iow. do not treat empty string as "no index" behaviour. +2. [Miscellaneous] [Regex] Use simpler & stronger pattern to match name of file # 1.1.0 diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index dc679e4..8d56048 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -200,13 +200,13 @@ class Miscellaneous * @param string $path A path that contains file name * @return string */ - public static function getFileNameFromPath($path) + public static function getFileNameFromPath(string $path): string { $matches = []; - $pattern = sprintf('|([^\%s.]+\.[A-Za-z0-9.]+)$|', DIRECTORY_SEPARATOR); + $pattern = Regex::getFileNamePattern(); if ((bool)preg_match($pattern, $path, $matches)) { - return $matches[1]; + return $matches[0]; } return ''; @@ -229,7 +229,7 @@ class Miscellaneous * Let's clear name of file * * Attention. - * The name without extension may be cleared / urlized only to avoid incorrect name by replacing "." with "-". + * The name without extension should be cleared to avoid incorrect name by replacing "." with "-". */ $withoutExtension = Urlizer::urlize($withoutExtension); diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index 1077bda..e605dd5 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -33,7 +33,7 @@ class Regex 'letterOrDigit' => '/[a-zA-Z0-9]+/', 'htmlEntity' => '/&[a-z0-9]+;/', 'htmlAttribute' => '/([\w-]+)="([\w -]+)"/', - 'fileName' => '/.+\.\w+$/', + 'fileName' => '/[\w.\- +=!@$&()?]+\.\w+$/', // e.g. "this-1_2 3 & my! 4+file.jpg" 'isQuoted' => '/^[\'"]{1}.+[\'"]{1}$/', 'windowsBasedPath' => '/^[A-Z]{1}:\\\.*$/', 'money' => '/^[-+]?\d+([\.,]{1}\d*)?$/', @@ -625,7 +625,7 @@ class Regex * * @return string */ - public static function getFileNamePattern() + public static function getFileNamePattern(): string { return self::$patterns['fileName']; } @@ -637,7 +637,7 @@ class Regex * @param string $fileName Name of file to check. It may be path of file also. * @return bool */ - public static function isFileName($fileName) + public static function isFileName(string $fileName): bool { $pattern = self::getFileNamePattern(); diff --git a/tests/Utilities/MiscellaneousTest.php b/tests/Utilities/MiscellaneousTest.php index 25a714f..d3e3dd7 100644 --- a/tests/Utilities/MiscellaneousTest.php +++ b/tests/Utilities/MiscellaneousTest.php @@ -94,11 +94,14 @@ class MiscellaneousTest extends BaseTestCase self::assertEquals($withoutExtension, Miscellaneous::getFileNameWithoutExtension($fileName)); } - public function testGetFileNameFromPath() + public function testGetFileNameFromPath(): void { // Path with file self::assertEquals('sit.amet.JPG', Miscellaneous::getFileNameFromPath('lorem/ipsum-dolor/sit.amet.JPG')); + // Path with complicated name of file + self::assertEquals('this-1_2 3 & my! 4+file.jpg', Miscellaneous::getFileNameFromPath('lorem/ipsum-dolor/this-1_2 3 & my! 4+file.jpg')); + // Path without file self::assertEquals('', Miscellaneous::getFileNameFromPath('lorem/ipsum-dolor/sit-amet')); diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index 3c404ea..cda237c 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -244,13 +244,16 @@ class RegexTest extends BaseTestCase self::assertTrue(Regex::contains($this->simpleText, 'l')); } - public function testIsFileName() + public function testIsFileName(): void { $filePath = __FILE__; $directoryPath = dirname($filePath); self::assertTrue(Regex::isFileName($filePath)); + self::assertTrue(Regex::isFileName('this-1_2 3 & my! 4+file.jpg')); + self::assertFalse(Regex::isFileName($directoryPath)); + self::assertTrue(Regex::isFileName('directory1/directory2/this-1_2 3 & my! 4+file.jpg')); } public function testIsQuoted() From 5cd58aec25c3072e0318b8d975e7b0d06797db18 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 18 Dec 2019 20:32:21 +0100 Subject: [PATCH 103/137] [Miscellaneous] [Regex] Implement data providers in tests --- src/Utilities/Miscellaneous.php | 16 +- tests/Utilities/MiscellaneousTest.php | 208 ++++++++++++++++++++++---- tests/Utilities/RegexTest.php | 51 +++++-- 3 files changed, 227 insertions(+), 48 deletions(-) diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index 8d56048..6d888b3 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -889,8 +889,12 @@ class Miscellaneous * @param string $separator The separator which divides elements of string * @return array */ - public static function getStringElements($string, $separator) + public static function getStringElements(string $string, string $separator): array { + if (empty($string) || empty($separator)) { + return []; + } + $matches = []; $pattern = sprintf('|[^\%s]+|', $separator); $matchCount = preg_match_all($pattern, $string, $matches); @@ -909,21 +913,15 @@ class Miscellaneous * @param string $separator The separator which divides elements of string * @return null|string */ - public static function getLastElementOfString($string, $separator) + public static function getLastElementOfString($string, $separator): ?string { $elements = self::getStringElements($string, $separator); - /* - * No elements? - * Nothing to do - */ if (empty($elements)) { return null; } - $element = Arrays::getLastElement($elements); - - return trim($element); + return Arrays::getLastElement($elements); } /** diff --git a/tests/Utilities/MiscellaneousTest.php b/tests/Utilities/MiscellaneousTest.php index d3e3dd7..a95f30a 100644 --- a/tests/Utilities/MiscellaneousTest.php +++ b/tests/Utilities/MiscellaneousTest.php @@ -94,22 +94,16 @@ class MiscellaneousTest extends BaseTestCase self::assertEquals($withoutExtension, Miscellaneous::getFileNameWithoutExtension($fileName)); } - public function testGetFileNameFromPath(): void + /** + * @param string $description Description of test + * @param string $path A path that contains file name + * @param string $expected Expected file name + * + * @dataProvider provideFilePath + */ + public function testGetFileNameFromPath(string $description, string $path, string $expected): void { - // Path with file - self::assertEquals('sit.amet.JPG', Miscellaneous::getFileNameFromPath('lorem/ipsum-dolor/sit.amet.JPG')); - - // Path with complicated name of file - self::assertEquals('this-1_2 3 & my! 4+file.jpg', Miscellaneous::getFileNameFromPath('lorem/ipsum-dolor/this-1_2 3 & my! 4+file.jpg')); - - // Path without file - self::assertEquals('', Miscellaneous::getFileNameFromPath('lorem/ipsum-dolor/sit-amet')); - - // Path with a dot "." in name of directory - self::assertEquals('sit.amet.JPG', Miscellaneous::getFileNameFromPath('lorem/ipsum.dolor/sit.amet.JPG')); - - // Relative path - self::assertEquals('sit.amet.JPG', Miscellaneous::getFileNameFromPath('lorem/ipsum/../dolor/sit.amet.JPG')); + static::assertEquals($expected, Miscellaneous::getFileNameFromPath($path), $description); } public function testGetUniqueFileName() @@ -480,12 +474,21 @@ class MiscellaneousTest extends BaseTestCase self::assertEquals('1.75 MB', Miscellaneous::getHumanReadableSize(1024 * 1024 * 1.75)); } - public function testGetLastElementOfString() - { - self::assertEquals('elit', Miscellaneous::getLastElementOfString($this->stringCommaSeparated, ' ')); - self::assertEquals('consectetur adipiscing elit', Miscellaneous::getLastElementOfString($this->stringCommaSeparated, ',')); - self::assertEquals(null, Miscellaneous::getLastElementOfString($this->stringCommaSeparated, ';')); - self::assertEquals(null, Miscellaneous::getLastElementOfString($this->stringCommaSeparated, '.')); + /** + * @param string $description + * @param string $string + * @param string $separator + * @param string|null $expected + * + * @dataProvider provideLastElementOfString + */ + public function testGetLastElementOfString( + string $description, + string $string, + string $separator, + ?string $expected + ): void { + self::assertEquals($expected, Miscellaneous::getLastElementOfString($string, $separator), $description); } public function testTrimSmart() @@ -554,15 +557,21 @@ class MiscellaneousTest extends BaseTestCase self::assertEquals(sprintf('%s.%s', $fileName, 'txt'), Miscellaneous::includeFileExtension($fileName, 'txt')); } - public function testGetStringElements() - { - $elements = [ - 'Lorem ipsum dolor sit amet', - ' consectetur adipiscing elit', - ]; - - self::assertEquals($elements, Miscellaneous::getStringElements($this->stringCommaSeparated, ',')); - self::assertEquals([], Miscellaneous::getStringElements($this->stringCommaSeparated, ';')); + /** + * @param string $description + * @param string $string + * @param string $separator + * @param array $expected + * + * @dataProvider provideStringElements + */ + public function testGetStringElements( + string $description, + string $string, + string $separator, + array $expected + ): void { + self::assertEquals($expected, Miscellaneous::getStringElements($string, $separator), $description); } public function testGetStringWithoutLastElement() @@ -1566,6 +1575,145 @@ class MiscellaneousTest extends BaseTestCase ]; } + public function provideFilePath(): ?Generator + { + yield[ + 'Path with file', + 'lorem/ipsum-dolor/sit.amet.JPG', + 'sit.amet.JPG', + ]; + + yield[ + 'Path with complicated name of file', + 'lorem/ipsum-dolor/this-1_2 3 & my! 4+file.jpg', + 'this-1_2 3 & my! 4+file.jpg', + ]; + + yield[ + 'Path without file', + 'lorem/ipsum-dolor/sit-amet', + '', + ]; + + yield[ + 'Path with a dot "." in name of directory', + 'lorem/ipsum.dolor/sit.amet.JPG', + 'sit.amet.JPG', + ]; + + yield[ + 'Relative path', + 'lorem/ipsum/../dolor/sit.amet.JPG', + 'sit.amet.JPG', + ]; + } + + public function provideStringElements(): ?Generator + { + yield[ + 'An empty string', + '', + '', + [], + ]; + + yield[ + 'One-character string', + 'a', + ',', + [], + ]; + + yield[ + 'String without given separator', + 'abc', + ',', + [], + ]; + + yield[ + 'Simple, short string', + 'a, b, c', + ',', + [ + 'a', + ' b', + ' c', + ], + ]; + + yield[ + 'A sentence', + 'Lorem ipsum - dolor sit - amet, consectetur adipiscing - elit.', + '-', + [ + 'Lorem ipsum ', + ' dolor sit ', + ' amet, consectetur adipiscing ', + ' elit.', + ], + ]; + + yield[ + 'A class namespace', + 'This\\Is\\My\\Class\\For\\Testing', + '\\', + [ + 'This', + 'Is', + 'My', + 'Class', + 'For', + 'Testing', + ], + ]; + } + + public function provideLastElementOfString(): ?Generator + { + yield[ + 'An empty string', + '', + '', + null, + ]; + + yield[ + 'One-character string', + 'a', + ',', + null, + ]; + + yield[ + 'String without given separator', + 'abc', + ',', + null, + ]; + + yield[ + 'Simple, short string', + 'a, b, c', + ',', + ' c', + ]; + + yield[ + 'A sentence', + 'Lorem ipsum - dolor sit - amet, consectetur adipiscing - elit.', + '-', + ' elit.', + ]; + + yield[ + 'A class namespace', + 'This\\Is\\My\\Class\\For\\Testing', + '\\', + 'Testing', + ]; + } + /** * {@inheritdoc} */ diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index cda237c..48c61d5 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -244,16 +244,16 @@ class RegexTest extends BaseTestCase self::assertTrue(Regex::contains($this->simpleText, 'l')); } - public function testIsFileName(): void + /** + * @param string $description Description of test + * @param string $fileName + * @param bool $expected Expected result + * + * @dataProvider provideFileName + */ + public function testIsFileName(string $description, string $fileName, bool $expected): void { - $filePath = __FILE__; - $directoryPath = dirname($filePath); - - self::assertTrue(Regex::isFileName($filePath)); - self::assertTrue(Regex::isFileName('this-1_2 3 & my! 4+file.jpg')); - - self::assertFalse(Regex::isFileName($directoryPath)); - self::assertTrue(Regex::isFileName('directory1/directory2/this-1_2 3 & my! 4+file.jpg')); + static::assertSame($expected, Regex::isFileName($fileName), $description); } public function testIsQuoted() @@ -2214,6 +2214,39 @@ class RegexTest extends BaseTestCase ]; } + public function provideFileName(): ?Generator + { + yield[ + 'An empty string', + '', + false, + ]; + + yield[ + 'Path of this file, of file with test case', + __DIR__, + false, + ]; + + yield[ + 'Name of this file, of file with test case', + __FILE__, + true, + ]; + + yield[ + 'Complicated name of file', + 'this-1_2 3 & my! 4+file.jpg', + true, + ]; + + yield[ + 'Complicated name of file', + 'directory1/directory2/this-1_2 3 & my! 4+file.jpg', + true, + ]; + } + /** * {@inheritdoc} */ From 8fec0db05f3b643b5b51c73f3cc6f4e8a4d7dd2a Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 24 Oct 2020 17:29:50 +0200 Subject: [PATCH 104/137] Increase Mutation Score Indicator (MSI) by creating stronger tests of BaseCollection class --- src/Collection/BaseCollection.php | 18 +++--- .../FirstNamesCollection.php} | 20 +++++-- tests/Collection/BaseCollection/User.php | 45 ++++++++++++++ tests/Collection/BaseCollectionTest.php | 59 ++++++++----------- tests/Collection/DateTimeCollectionTest.php | 6 ++ tests/Collection/IntegerCollectionTest.php | 6 ++ tests/Collection/StringCollectionTest.php | 6 ++ 7 files changed, 113 insertions(+), 47 deletions(-) rename tests/Collection/{Collection/ArrayCollection.php => BaseCollection/FirstNamesCollection.php} (51%) create mode 100644 tests/Collection/BaseCollection/User.php diff --git a/src/Collection/BaseCollection.php b/src/Collection/BaseCollection.php index 293df6d..6ae692c 100644 --- a/src/Collection/BaseCollection.php +++ b/src/Collection/BaseCollection.php @@ -46,13 +46,21 @@ abstract class BaseCollection implements Countable, ArrayAccess, IteratorAggrega return $elements; } + /** + * Returns information if given element has valid type + * + * @param mixed $element Element of collection + * @return bool + */ + abstract protected function isValidType($element): bool; + /** * Returns elements of collection with valid types * * @param array $elements The elements of collection to verify * @return array */ - protected function getElementsWithValidType(array $elements): array + private function getElementsWithValidType(array $elements): array { if (empty($elements)) { return []; @@ -70,12 +78,4 @@ abstract class BaseCollection implements Countable, ArrayAccess, IteratorAggrega return $result; } - - /** - * Returns information if given element has valid type - * - * @param mixed $element Element of collection - * @return bool - */ - abstract protected function isValidType($element): bool; } diff --git a/tests/Collection/Collection/ArrayCollection.php b/tests/Collection/BaseCollection/FirstNamesCollection.php similarity index 51% rename from tests/Collection/Collection/ArrayCollection.php rename to tests/Collection/BaseCollection/FirstNamesCollection.php index 2ad9627..1dc7c56 100644 --- a/tests/Collection/Collection/ArrayCollection.php +++ b/tests/Collection/BaseCollection/FirstNamesCollection.php @@ -8,12 +8,12 @@ declare(strict_types=1); -namespace Meritoo\Test\Common\Collection\Collection; +namespace Meritoo\Test\Common\Collection\BaseCollection; use Meritoo\Common\Collection\BaseCollection; /** - * Collection of arrays + * Collection of first names * * @author Meritoo * @copyright Meritoo @@ -21,10 +21,22 @@ use Meritoo\Common\Collection\BaseCollection; * @internal * @coversNothing */ -class ArrayCollection extends BaseCollection +class FirstNamesCollection extends BaseCollection { protected function isValidType($element): bool { - return is_array($element); + return $element instanceof User; + } + + protected function prepareElements(array $elements): array + { + $result = []; + + /** @var User $element */ + foreach ($elements as $element) { + $result[] = $element->getFirstName(); + } + + return $result; } } diff --git a/tests/Collection/BaseCollection/User.php b/tests/Collection/BaseCollection/User.php new file mode 100644 index 0000000..642ef56 --- /dev/null +++ b/tests/Collection/BaseCollection/User.php @@ -0,0 +1,45 @@ + + * @copyright Meritoo + * + * @internal + * @coversNothing + */ +final class User +{ + /** @var string */ + private $firstName; + + /** @var string */ + private $lastName; + + public function __construct(string $firstName, string $lastName) + { + $this->firstName = $firstName; + $this->lastName = $lastName; + } + + public function getFirstName(): string + { + return $this->firstName; + } + + public function getLastName(): string + { + return $this->lastName; + } +} diff --git a/tests/Collection/BaseCollectionTest.php b/tests/Collection/BaseCollectionTest.php index 0f7a482..1883e8b 100644 --- a/tests/Collection/BaseCollectionTest.php +++ b/tests/Collection/BaseCollectionTest.php @@ -15,7 +15,8 @@ use Meritoo\Common\Collection\DateTimeCollection; use Meritoo\Common\Collection\StringCollection; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; -use Meritoo\Test\Common\Collection\Collection\ArrayCollection; +use Meritoo\Test\Common\Collection\BaseCollection\FirstNamesCollection; +use Meritoo\Test\Common\Collection\BaseCollection\User; use ReflectionClass; /** @@ -360,7 +361,7 @@ class BaseCollectionTest extends BaseTestCase */ public function testGetElementsWithValidType(string $description, array $elements, array $expected): void { - $collection = new ArrayCollection($elements); + $collection = new FirstNamesCollection($elements); static::assertSame($expected, $collection->toArray(), $description); } @@ -511,21 +512,12 @@ class BaseCollectionTest extends BaseTestCase yield[ 'Collection with existing index (collection of arrays)', - new ArrayCollection([ - [ - 'lorem', - 'ipsum', - ], - [ - 'dolor', - 'sit', - ], + new FirstNamesCollection([ + new User('John', 'Scott'), + new User('Jane', 'Brown'), ]), 0, - [ - 'lorem', - 'ipsum', - ], + 'John', ]; yield[ @@ -538,6 +530,16 @@ class BaseCollectionTest extends BaseTestCase 'y', new \DateTime('2001-01-01'), ]; + + yield[ + 'Collection with first names', + new FirstNamesCollection([ + new User('John', 'Scott'), + new User('Jane', 'Brown'), + ]), + 1, + 'Jane', + ]; } public function provideElementsToValidateType(): ?Generator @@ -551,18 +553,12 @@ class BaseCollectionTest extends BaseTestCase yield[ 'Valid elements only', [ - [], - [ - '123', - 456, - ], + new User('John', 'Scott'), + new User('Jane', 'Brown'), ], [ - [], - [ - '123', - 456, - ], + 'John', + 'Jane', ], ]; @@ -572,20 +568,15 @@ class BaseCollectionTest extends BaseTestCase 1, 'test', '', + new User('John', 'Scott'), [], 234, 'test', - [ - '123', - 456, - ], + new User('Jane', 'Brown'), ], [ - 3 => [], - 6 => [ - '123', - 456, - ], + 'John', + 'Jane', ], ]; } diff --git a/tests/Collection/DateTimeCollectionTest.php b/tests/Collection/DateTimeCollectionTest.php index f8cdd1c..ea6fd48 100644 --- a/tests/Collection/DateTimeCollectionTest.php +++ b/tests/Collection/DateTimeCollectionTest.php @@ -1,5 +1,11 @@ Date: Sat, 20 Feb 2021 16:20:57 +0100 Subject: [PATCH 105/137] Use meritoo/php Docker image (instead of deprecated meritoo/php7) --- docker-compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 3b4cd6a..87a080c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ services: # Required to run project # php: - image: meritoo/php7 + image: meritoo/php container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-php entrypoint: php command: -S 0.0.0.0:9999 @@ -14,7 +14,7 @@ services: volumes: - .:/var/www/application:cached composer: - image: meritoo/php7 + image: meritoo/php container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-composer entrypoint: php -d memory_limit=-1 /usr/local/bin/composer volumes: @@ -23,7 +23,7 @@ services: # Required to run PHPUnit's tests # phpunit: - image: meritoo/php7 + image: meritoo/php container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-phpunit entrypoint: ./vendor/bin/phpunit command: --version From 416f0cd8af2791b15f7f0bb9c43509c73cd2f2aa Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 20 Feb 2021 16:26:07 +0100 Subject: [PATCH 106/137] Do not install hirak/prestissimo package while running build in Travis CI --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 19f4e72..02126bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,6 @@ php: before_install: - sudo locale-gen de_DE.UTF-8 es_ES.UTF-8 en_GB.UTF-8 en_US.UTF-8 fr_FR.UTF-8 it_IT.UTF-8 pl_PL.UTF-8 ru_RU.UTF-8 - - composer global require hirak/prestissimo - pear channel-discover pear.phing.info install: From 351224f1f9ec9b2ba56f9aedac4b05aa79807980 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 20 Feb 2021 16:37:06 +0100 Subject: [PATCH 107/137] Use PHP 7.4 while running build in Travis CI --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 02126bd..8f3d997 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: php php: - 7.2 - 7.3 + - 7.4 before_install: - sudo locale-gen de_DE.UTF-8 es_ES.UTF-8 en_GB.UTF-8 en_US.UTF-8 fr_FR.UTF-8 it_IT.UTF-8 pl_PL.UTF-8 ru_RU.UTF-8 From ab0c0e6e89abaedafa5e3f2ce44345563a8da467 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 20 Feb 2021 16:39:40 +0100 Subject: [PATCH 108/137] Update Changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dae0a9..d538927 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ Common and useful classes, methods, exceptions etc. 1. [BaseCollection] Treat the `null` index as "no index" only while adding new element, iow. do not treat empty string as "no index" behaviour. 2. [Miscellaneous] [Regex] Use simpler & stronger pattern to match name of file +3. Do not install `hirak/prestissimo` package while running Travis CI (incompatible with your PHP version, PHP + extensions and Composer version) +4. Use PHP `7.4` while running build in Travis CI # 1.1.0 From c6efc30872bd0a26ef07d18d19fb12ca0e54957e Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 26 Feb 2021 15:09:02 +0100 Subject: [PATCH 109/137] Fix "Array and string offset access syntax with curly braces is deprecated" error while running tests (using PHP 7.4) --- composer.json | 2 +- src/Utilities/Miscellaneous.php | 2 +- src/Utilities/Reflection.php | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 90a54b8..89009ba 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "ext-pcre": "*", "ext-simplexml": "*", "doctrine/orm": "^2.6", - "gedmo/doctrine-extensions": "^2.4" + "gedmo/doctrine-extensions": "^3.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index 6d888b3..39681ed 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -574,7 +574,7 @@ class Miscellaneous if ($textLength > $maxLength) { $effect = mb_substr($text, 0, $maxLength, 'utf-8'); - $lastSpacePosition = mb_strrpos($effect, ' ', 'utf-8'); + $lastSpacePosition = mb_strrpos($effect, ' ', 0, 'utf-8'); if (false !== $lastSpacePosition) { $effect = mb_substr($effect, 0, $lastSpacePosition, 'utf-8'); diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index 9508ba2..e641338 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -8,8 +8,8 @@ namespace Meritoo\Common\Utilities; -use Doctrine\Common\Inflector\Inflector; -use Doctrine\Common\Persistence\Proxy; +use Doctrine\Inflector\InflectorFactory; +use Doctrine\Persistence\Proxy; use Meritoo\Common\Collection\BaseCollection; use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException; use Meritoo\Common\Exception\Reflection\MissingChildClassesException; @@ -418,8 +418,8 @@ class Reflection * * @param array|object|string $class Class who child classes should be returned. An array of objects, strings, * object or string. - * @throws CannotResolveClassNameException * @return null|array + * @throws CannotResolveClassNameException */ public static function getChildClasses($class): ?array { @@ -471,9 +471,8 @@ class Reflection * * @param array|object|string $parentClass Class who child class should be returned. An array of objects, * namespaces, object or namespace. - * @throws MissingChildClassesException - * @throws TooManyChildClassesException * @return mixed + * @throws TooManyChildClassesException|MissingChildClassesException|CannotResolveClassNameException */ public static function getOneChildClass($parentClass) { @@ -531,8 +530,8 @@ class Reflection * @param array|string $trait An array of strings or string * @param bool $verifyParents If is set to true, parent classes are verified if they use given * trait. Otherwise - not. - * @throws CannotResolveClassNameException * @return null|bool + * @throws CannotResolveClassNameException|ReflectionException */ public static function usesTrait($class, $trait, bool $verifyParents = false): ?bool { @@ -711,7 +710,8 @@ class Reflection $valueFound = false; $reflectionObject = new ReflectionObject($source); - $property = Inflector::classify($property); + $inflector = InflectorFactory::create()->build(); + $property = $inflector->classify($property); $gettersPrefixes = [ 'get', From 47d07150d352183ec7bdddcab3f05f0c8199cbd8 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 26 Feb 2021 15:13:33 +0100 Subject: [PATCH 110/137] Minor refactoring --- src/Utilities/Miscellaneous.php | 13 +++++++------ src/Utilities/Reflection.php | 3 +-- tests/Utilities/ReflectionTest.php | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index 39681ed..3038711 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -563,21 +563,22 @@ class Miscellaneous * @param string $suffix (optional) The suffix to add at the end of string * @return string */ - public static function substringToWord($text, $maxLength, $suffix = '...') + public static function substringToWord(string $text, int $maxLength, string $suffix = '...'): string { $effect = $text; + $encoding = 'utf-8'; - $textLength = mb_strlen($text, 'utf-8'); - $suffixLength = mb_strlen($suffix, 'utf-8'); + $textLength = mb_strlen($text, $encoding); + $suffixLength = mb_strlen($suffix, $encoding); $maxLength -= $suffixLength; if ($textLength > $maxLength) { - $effect = mb_substr($text, 0, $maxLength, 'utf-8'); - $lastSpacePosition = mb_strrpos($effect, ' ', 0, 'utf-8'); + $effect = mb_substr($text, 0, $maxLength, $encoding); + $lastSpacePosition = mb_strrpos($effect, ' ', 0, $encoding); if (false !== $lastSpacePosition) { - $effect = mb_substr($effect, 0, $lastSpacePosition, 'utf-8'); + $effect = mb_substr($effect, 0, $lastSpacePosition, $encoding); } $effect .= $suffix; diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index e641338..90ed38a 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -502,7 +502,7 @@ class Reflection * * @param array|object|string $class An array of objects, namespaces, object or namespace * @param string $property Name of the property - * @param int $filter (optional) Filter of properties. Uses \ReflectionProperty class constants. + * @param int|null $filter (optional) Filter of properties. Uses \ReflectionProperty class constants. * By default all properties are allowed / processed. * @return null|ReflectionProperty */ @@ -512,7 +512,6 @@ class Reflection $properties = self::getProperties($className, $filter); if (!empty($properties)) { - /** @var ReflectionProperty $reflectionProperty */ foreach ($properties as $reflectionProperty) { if ($reflectionProperty->getName() === $property) { return $reflectionProperty; diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 1f9ff30..c7adbbe 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -222,7 +222,7 @@ class ReflectionTest extends BaseTestCase public function testUsesTraitInvalidTrait($trait): void { $this->expectException(CannotResolveClassNameException::class); - self::assertNull(Reflection::usesTrait(DateTime::class, $trait)); + Reflection::usesTrait(DateTime::class, $trait); } public function testUsesTraitExistingClass(): void From 64f474fcf1519b0201c4dd80b1ec814e3729663b Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 28 Mar 2021 22:15:51 +0200 Subject: [PATCH 111/137] Change mode of Xdebug to "coverage" in Docker's configuration to make it possible to generate code coverage by PHPUnit --- CHANGELOG.md | 5 +++++ VERSION | 2 +- docker-compose.yml | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d538927..5b9bc87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Common and useful classes, methods, exceptions etc. +# 1.1.2 + +1. Change mode of `Xdebug` to `coverage` in Docker's configuration to make it possible to generate code coverage by + `PHPUnit` + # 1.1.1 1. [BaseCollection] Treat the `null` index as "no index" only while adding new element, iow. do not treat empty diff --git a/VERSION b/VERSION index 524cb55..45a1b3f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.1 +1.1.2 diff --git a/docker-compose.yml b/docker-compose.yml index 87a080c..d725bfa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,3 +29,5 @@ services: command: --version volumes: - .:/var/www/application:cached + environment: + XDEBUG_MODE: coverage From 1116034fe6eaad0679d99084a87d07d3220ad935 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 28 Mar 2021 22:18:54 +0200 Subject: [PATCH 112/137] Mark PHPUnit test as risky when it does not have a @covers annotation --- CHANGELOG.md | 1 + phpunit.xml.dist | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b9bc87..109000a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Common and useful classes, methods, exceptions etc. 1. Change mode of `Xdebug` to `coverage` in Docker's configuration to make it possible to generate code coverage by `PHPUnit` +2. Mark PHPUnit test as risky when it does not have a `@covers` annotation # 1.1.1 diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 13fe570..acd207b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -7,6 +7,7 @@ bootstrap="vendor/autoload.php" colors="true" executionOrder="random" + forceCoversAnnotation="true" verbose="true" > From e47eaae8b23708ae1bfb9437e65e1f9e75426cc4 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 28 Mar 2021 22:34:25 +0200 Subject: [PATCH 113/137] Move Renderable class: Meritoo\Common -> Meritoo\Common\Contract --- CHANGELOG.md | 4 ++++ VERSION | 2 +- src/{ => Contract}/Renderable/RenderableInterface.php | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) rename src/{ => Contract}/Renderable/RenderableInterface.php (94%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 109000a..fae7b31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Common and useful classes, methods, exceptions etc. +# 1.1.3 + +1. Move `Renderable` class: `Meritoo\Common` -> `Meritoo\Common\Contract` + # 1.1.2 1. Change mode of `Xdebug` to `coverage` in Docker's configuration to make it possible to generate code coverage by diff --git a/VERSION b/VERSION index 45a1b3f..781dcb0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.2 +1.1.3 diff --git a/src/Renderable/RenderableInterface.php b/src/Contract/Renderable/RenderableInterface.php similarity index 94% rename from src/Renderable/RenderableInterface.php rename to src/Contract/Renderable/RenderableInterface.php index de10afa..2fb041a 100644 --- a/src/Renderable/RenderableInterface.php +++ b/src/Contract/Renderable/RenderableInterface.php @@ -8,7 +8,7 @@ declare(strict_types=1); -namespace Meritoo\Common\Renderable; +namespace Meritoo\Common\Contract\Renderable; use Meritoo\Common\Collection\Templates; From 4f8c355d1bae51adea0af4a7fbfa25b9add406b2 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 29 Mar 2021 19:02:28 +0200 Subject: [PATCH 114/137] Create and implement CollectionInterface as contract of all collections (e.g. based on the BaseCollection class) --- CHANGELOG.md | 1 + src/Collection/BaseCollection.php | 8 +-- .../Collection/CollectionInterface.php | 52 +++++++++++++++++++ .../Renderable/RenderableInterface.php | 2 +- src/Traits/Collection/AddTrait.php | 8 +-- src/Traits/CollectionTrait.php | 2 + src/Utilities/Reflection.php | 14 ++--- tests/Collection/BaseCollectionTest.php | 39 ++++++++------ 8 files changed, 93 insertions(+), 33 deletions(-) create mode 100644 src/Contract/Collection/CollectionInterface.php diff --git a/CHANGELOG.md b/CHANGELOG.md index fae7b31..be146a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Common and useful classes, methods, exceptions etc. # 1.1.3 1. Move `Renderable` class: `Meritoo\Common` -> `Meritoo\Common\Contract` +2. Create and implement `CollectionInterface` as contract of all collections (e.g. based on the `BaseCollection` class) # 1.1.2 diff --git a/src/Collection/BaseCollection.php b/src/Collection/BaseCollection.php index 6ae692c..5eb5c3e 100644 --- a/src/Collection/BaseCollection.php +++ b/src/Collection/BaseCollection.php @@ -6,11 +6,11 @@ * file that was distributed with this source code. */ +declare(strict_types=1); + namespace Meritoo\Common\Collection; -use ArrayAccess; -use Countable; -use IteratorAggregate; +use Meritoo\Common\Contract\Collection\CollectionInterface; use Meritoo\Common\Traits\CollectionTrait; /** @@ -19,7 +19,7 @@ use Meritoo\Common\Traits\CollectionTrait; * @author Meritoo * @copyright Meritoo */ -abstract class BaseCollection implements Countable, ArrayAccess, IteratorAggregate +abstract class BaseCollection implements CollectionInterface { use CollectionTrait; diff --git a/src/Contract/Collection/CollectionInterface.php b/src/Contract/Collection/CollectionInterface.php new file mode 100644 index 0000000..df84414 --- /dev/null +++ b/src/Contract/Collection/CollectionInterface.php @@ -0,0 +1,52 @@ + + * @copyright Meritoo + */ +interface CollectionInterface extends Countable, ArrayAccess, IteratorAggregate +{ + public function toArray(): array; + + public function add($element, $index = null): void; + + public function addMultiple($elements, bool $useIndexes = false): void; + + public function prepend($element): void; + + public function remove($element): void; + + public function getPrevious($element); + + public function getNext($element); + + public function getFirst(); + + public function getLast(); + + public function getByIndex($index); + + public function isEmpty(): bool; + + public function isFirst($element): bool; + + public function isLast($element): bool; + + public function has($element): bool; +} diff --git a/src/Contract/Renderable/RenderableInterface.php b/src/Contract/Renderable/RenderableInterface.php index 2fb041a..12581b0 100644 --- a/src/Contract/Renderable/RenderableInterface.php +++ b/src/Contract/Renderable/RenderableInterface.php @@ -13,7 +13,7 @@ namespace Meritoo\Common\Contract\Renderable; use Meritoo\Common\Collection\Templates; /** - * Something that may be rendered + * Interface/Contract of something that may be rendered * * @author Meritoo * @copyright Meritoo diff --git a/src/Traits/Collection/AddTrait.php b/src/Traits/Collection/AddTrait.php index 4ac35aa..62b715d 100644 --- a/src/Traits/Collection/AddTrait.php +++ b/src/Traits/Collection/AddTrait.php @@ -8,7 +8,7 @@ namespace Meritoo\Common\Traits\Collection; -use Meritoo\Common\Collection\BaseCollection; +use Meritoo\Common\Contract\Collection\CollectionInterface; /** * Trait for the Collection with add*() methods @@ -42,9 +42,9 @@ trait AddTrait /** * Adds given elements (at the end of collection) * - * @param array|BaseCollection $elements The elements to add - * @param bool $useIndexes (optional) If is set to true, indexes of given elements will be used in - * this collection. Otherwise - not. + * @param array|CollectionInterface $elements The elements to add + * @param bool $useIndexes (optional) If is set to true, indexes of given elements will be + * used in this collection. Otherwise - not. */ public function addMultiple($elements, bool $useIndexes = false): void { diff --git a/src/Traits/CollectionTrait.php b/src/Traits/CollectionTrait.php index d7ac305..4ffafa1 100644 --- a/src/Traits/CollectionTrait.php +++ b/src/Traits/CollectionTrait.php @@ -6,6 +6,8 @@ * file that was distributed with this source code. */ +declare(strict_types=1); + namespace Meritoo\Common\Traits; use Meritoo\Common\Traits\Collection\AddTrait; diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index 90ed38a..d6f7ebc 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -10,7 +10,7 @@ namespace Meritoo\Common\Utilities; use Doctrine\Inflector\InflectorFactory; use Doctrine\Persistence\Proxy; -use Meritoo\Common\Collection\BaseCollection; +use Meritoo\Common\Contract\Collection\CollectionInterface; use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException; use Meritoo\Common\Exception\Reflection\MissingChildClassesException; use Meritoo\Common\Exception\Reflection\NotExistingPropertyException; @@ -207,11 +207,11 @@ class Reflection * Returns values of given property for given objects. * Looks for proper getter for the property. * - * @param array|BaseCollection|object $objects The objects that should contain given property. It may be also one - * object. - * @param string $property Name of the property that contains a value - * @param bool $force (optional) If is set to true, try to retrieve value even if the - * object does not have property. Otherwise - not. + * @param array|CollectionInterface|object $objects The objects that should contain given property. It may be also + * one object. + * @param string $property Name of the property that contains a value + * @param bool $force (optional) If is set to true, try to retrieve value even if + * the object does not have property. Otherwise - not. * @return array */ public static function getPropertyValues($objects, string $property, bool $force = false): array @@ -224,7 +224,7 @@ class Reflection return []; } - if ($objects instanceof BaseCollection) { + if ($objects instanceof CollectionInterface) { $objects = $objects->toArray(); } diff --git a/tests/Collection/BaseCollectionTest.php b/tests/Collection/BaseCollectionTest.php index 1883e8b..798362b 100644 --- a/tests/Collection/BaseCollectionTest.php +++ b/tests/Collection/BaseCollectionTest.php @@ -13,6 +13,7 @@ use Generator; use Meritoo\Common\Collection\BaseCollection; use Meritoo\Common\Collection\DateTimeCollection; use Meritoo\Common\Collection\StringCollection; +use Meritoo\Common\Contract\Collection\CollectionInterface; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; use Meritoo\Test\Common\Collection\BaseCollection\FirstNamesCollection; @@ -139,15 +140,19 @@ class BaseCollectionTest extends BaseTestCase } /** - * @param mixed $element The element to add - * @param int $expectedCount Expected count of elements in collection - * @param int $expectedIndex Expected index of added element in collection - * @param BaseCollection $collection The collection + * @param mixed $element The element to add + * @param int $expectedCount Expected count of elements in collection + * @param int $expectedIndex Expected index of added element in collection + * @param CollectionInterface $collection The collection * * @dataProvider provideElementToAdd */ - public function testAddWithoutIndex($element, $expectedCount, $expectedIndex, BaseCollection $collection) - { + public function testAddWithoutIndex( + $element, + int $expectedCount, + int $expectedIndex, + CollectionInterface $collection + ) { $collection->add($element); static::assertTrue($collection->has($element)); @@ -156,15 +161,15 @@ class BaseCollectionTest extends BaseTestCase } /** - * @param mixed $element The element to add - * @param mixed $index Index of element to add - * @param int $expectedCount Expected count of elements in collection - * @param int $expectedIndex Expected index of added element in collection - * @param BaseCollection $collection The collection + * @param mixed $element The element to add + * @param mixed $index Index of element to add + * @param int $expectedCount Expected count of elements in collection + * @param int $expectedIndex Expected index of added element in collection + * @param CollectionInterface $collection The collection * * @dataProvider provideElementToAddWithIndex */ - public function testAddWithIndex($element, $index, $expectedCount, $expectedIndex, BaseCollection $collection) + public function testAddWithIndex($element, $index, $expectedCount, $expectedIndex, CollectionInterface $collection) { $collection->add($element, $index); @@ -340,14 +345,14 @@ class BaseCollectionTest extends BaseTestCase } /** - * @param string $description Description of test - * @param BaseCollection $collection Collection to search for element with given index - * @param mixed $index Index / key of the element - * @param mixed $expected Expected element with given index + * @param string $description Description of test + * @param CollectionInterface $collection Collection to search for element with given index + * @param mixed $index Index / key of the element + * @param mixed $expected Expected element with given index * * @dataProvider provideElementGetByIndex */ - public function testGetByIndex($description, BaseCollection $collection, $index, $expected) + public function testGetByIndex($description, CollectionInterface $collection, $index, $expected) { static::assertEquals($expected, $collection->getByIndex($index), $description); } From a4d24a788bf737720f6b76461c4348972dee919e Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 29 Mar 2021 19:03:45 +0200 Subject: [PATCH 115/137] Reformat code --- tests/Collection/BaseCollectionTest.php | 47 +++++++++++++------------ 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/tests/Collection/BaseCollectionTest.php b/tests/Collection/BaseCollectionTest.php index 798362b..0b64961 100644 --- a/tests/Collection/BaseCollectionTest.php +++ b/tests/Collection/BaseCollectionTest.php @@ -9,6 +9,7 @@ namespace Meritoo\Test\Common\Collection; use ArrayIterator; +use DateTime; use Generator; use Meritoo\Common\Collection\BaseCollection; use Meritoo\Common\Collection\DateTimeCollection; @@ -377,14 +378,14 @@ class BaseCollectionTest extends BaseTestCase */ public function provideElementToAdd() { - yield[ + yield [ 'This is test 1', 1, 0, new StringCollection(), ]; - yield[ + yield [ 'This is test 2', 2, 1, @@ -393,7 +394,7 @@ class BaseCollectionTest extends BaseTestCase ]), ]; - yield[ + yield [ 'This is test 3', 3, 2, @@ -411,7 +412,7 @@ class BaseCollectionTest extends BaseTestCase */ public function provideElementToAddWithIndex() { - yield[ + yield [ 'This is test 1', 'test1', 1, @@ -419,7 +420,7 @@ class BaseCollectionTest extends BaseTestCase new StringCollection(), ]; - yield[ + yield [ 'This is test 2', 'test2', 2, @@ -429,7 +430,7 @@ class BaseCollectionTest extends BaseTestCase ]), ]; - yield[ + yield [ 'This is test 3', null, 3, @@ -440,7 +441,7 @@ class BaseCollectionTest extends BaseTestCase ]), ]; - yield[ + yield [ 'This is test 4', '', 4, @@ -452,7 +453,7 @@ class BaseCollectionTest extends BaseTestCase ]), ]; - yield[ + yield [ 'This is test 5', 'test5', 5, @@ -465,7 +466,7 @@ class BaseCollectionTest extends BaseTestCase ]), ]; - yield[ + yield [ 'This is test 6', 'test2', 4, @@ -481,21 +482,21 @@ class BaseCollectionTest extends BaseTestCase public function provideElementGetByIndex() { - yield[ + yield [ 'An empty collection and empty index', new StringCollection(), '', null, ]; - yield[ + yield [ 'An empty collection and non-empty index', new StringCollection(), 'test', null, ]; - yield[ + yield [ 'Non-empty collection and not existing index', new StringCollection([ 'lorem' => 'ipsum', @@ -505,7 +506,7 @@ class BaseCollectionTest extends BaseTestCase null, ]; - yield[ + yield [ 'Collection with existing index', new StringCollection([ 'lorem' => 'ipsum', @@ -515,7 +516,7 @@ class BaseCollectionTest extends BaseTestCase 'ipsum', ]; - yield[ + yield [ 'Collection with existing index (collection of arrays)', new FirstNamesCollection([ new User('John', 'Scott'), @@ -525,18 +526,18 @@ class BaseCollectionTest extends BaseTestCase 'John', ]; - yield[ + yield [ 'Collection with existing index (collection of objects)', new DateTimeCollection([ - 'x' => new \DateTime(), - 'y' => new \DateTime('2001-01-01'), - 'z' => new \DateTime('yesterday'), + 'x' => new DateTime(), + 'y' => new DateTime('2001-01-01'), + 'z' => new DateTime('yesterday'), ]), 'y', - new \DateTime('2001-01-01'), + new DateTime('2001-01-01'), ]; - yield[ + yield [ 'Collection with first names', new FirstNamesCollection([ new User('John', 'Scott'), @@ -549,13 +550,13 @@ class BaseCollectionTest extends BaseTestCase public function provideElementsToValidateType(): ?Generator { - yield[ + yield [ 'An empty array', [], [], ]; - yield[ + yield [ 'Valid elements only', [ new User('John', 'Scott'), @@ -567,7 +568,7 @@ class BaseCollectionTest extends BaseTestCase ], ]; - yield[ + yield [ 'Mixed elements', [ 1, From d5542b60e3ff78a276779e5c3ae278de0bdd49d5 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 4 Apr 2021 22:59:59 +0200 Subject: [PATCH 116/137] Implement methods of CollectionInterface directly in BaseCollection class (instead of traits) --- src/Collection/BaseCollection.php | 240 +++++++++++++++++- src/Traits/Collection/AddTrait.php | 65 ----- src/Traits/Collection/ArrayAccessTrait.php | 67 ----- src/Traits/Collection/CountableTrait.php | 26 -- src/Traits/Collection/GetTrait.php | 73 ------ .../Collection/IteratorAggregateTrait.php | 28 -- src/Traits/Collection/MainTrait.php | 35 --- src/Traits/Collection/ModifyTrait.php | 48 ---- src/Traits/Collection/VerifyTrait.php | 65 ----- src/Traits/CollectionTrait.php | 38 --- 10 files changed, 238 insertions(+), 447 deletions(-) delete mode 100644 src/Traits/Collection/AddTrait.php delete mode 100644 src/Traits/Collection/ArrayAccessTrait.php delete mode 100644 src/Traits/Collection/CountableTrait.php delete mode 100644 src/Traits/Collection/GetTrait.php delete mode 100644 src/Traits/Collection/IteratorAggregateTrait.php delete mode 100644 src/Traits/Collection/MainTrait.php delete mode 100644 src/Traits/Collection/ModifyTrait.php delete mode 100644 src/Traits/Collection/VerifyTrait.php delete mode 100644 src/Traits/CollectionTrait.php diff --git a/src/Collection/BaseCollection.php b/src/Collection/BaseCollection.php index 5eb5c3e..36e46b7 100644 --- a/src/Collection/BaseCollection.php +++ b/src/Collection/BaseCollection.php @@ -10,8 +10,9 @@ declare(strict_types=1); namespace Meritoo\Common\Collection; +use ArrayIterator; use Meritoo\Common\Contract\Collection\CollectionInterface; -use Meritoo\Common\Traits\CollectionTrait; +use Meritoo\Common\Utilities\Arrays; /** * Collection of elements with the same type @@ -21,7 +22,12 @@ use Meritoo\Common\Traits\CollectionTrait; */ abstract class BaseCollection implements CollectionInterface { - use CollectionTrait; + /** + * The elements of collection + * + * @var array + */ + private $elements; /** * Class constructor @@ -34,6 +40,225 @@ abstract class BaseCollection implements CollectionInterface $this->elements = $this->prepareElements($validated); } + /** + * Returns representation of object as array + * + * @return array + */ + public function toArray(): array + { + return $this->elements; + } + + /** + * Adds given element (at the end of collection) + * + * @param mixed $element The element to add + * @param mixed $index (optional) Index / key of the element + */ + public function add($element, $index = null): void + { + if (!$this->isValidType($element)) { + return; + } + + if (null === $index) { + $this->elements[] = $element; + + return; + } + + $this->elements[$index] = $element; + } + + /** + * Adds given elements (at the end of collection) + * + * @param array|CollectionInterface $elements The elements to add + * @param bool $useIndexes (optional) If is set to true, indexes of given elements will be + * used in this collection. Otherwise - not. + */ + public function addMultiple($elements, bool $useIndexes = false): void + { + if (empty($elements)) { + return; + } + + foreach ($elements as $index => $element) { + if ($useIndexes) { + $this->add($element, $index); + + continue; + } + + $this->add($element); + } + } + + /** + * Prepends given element (adds given element at the beginning of collection) + * + * @param mixed $element The element to prepend + */ + public function prepend($element): void + { + array_unshift($this->elements, $element); + } + + /** + * Removes given element + * + * @param mixed $element The element to remove + */ + public function remove($element): void + { + if (0 === $this->count()) { + return; + } + + foreach ($this->elements as $index => $existing) { + if ($element === $existing) { + unset($this->elements[$index]); + + break; + } + } + } + + /** + * Returns previous element for given element + * + * @param mixed $element The element to verify + * @return null|mixed + */ + public function getPrevious($element) + { + return Arrays::getPreviousElement($this->elements, $element); + } + + /** + * Returns next element for given element + * + * @param mixed $element The element to verify + * @return null|mixed + */ + public function getNext($element) + { + return Arrays::getNextElement($this->elements, $element); + } + + /** + * Returns the first element in the collection + * + * @return mixed + */ + public function getFirst() + { + return Arrays::getFirstElement($this->elements); + } + + /** + * Returns the last element in the collection + * + * @return mixed + */ + public function getLast() + { + return Arrays::getLastElement($this->elements); + } + + /** + * Returns element with given index + * + * @param mixed $index Index / key of the element + * @return null|mixed + */ + public function getByIndex($index) + { + return $this->elements[$index] ?? null; + } + + /** + * Returns information if collection is empty + * + * @return bool + */ + public function isEmpty(): bool + { + return empty($this->elements); + } + + /** + * Returns information if given element is first in the collection + * + * @param mixed $element The element to verify + * @return bool + */ + public function isFirst($element): bool + { + return reset($this->elements) === $element; + } + + /** + * Returns information if given element is last in the collection + * + * @param mixed $element The element to verify + * @return bool + */ + public function isLast($element): bool + { + return end($this->elements) === $element; + } + + /** + * Returns information if the collection has given element, iow. if given element exists in the collection + * + * @param mixed $element The element to verify + * @return bool + */ + public function has($element): bool + { + $index = Arrays::getIndexOf($this->elements, $element); + + return null !== $index && false !== $index; + } + + public function count(): int + { + return count($this->elements); + } + + public function offsetExists($offset): bool + { + return $this->exists($offset); + } + + public function offsetGet($offset) + { + if ($this->exists($offset)) { + return $this->elements[$offset]; + } + + return null; + } + + public function offsetSet($offset, $value): void + { + $this->elements[$offset] = $value; + } + + public function offsetUnset($offset): void + { + if ($this->exists($offset)) { + unset($this->elements[$offset]); + } + } + + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->elements); + } + /** * Prepares elements to initialize the collection. * Feel free to override and prepare elements in your way. @@ -78,4 +303,15 @@ abstract class BaseCollection implements CollectionInterface return $result; } + + /** + * Returns information if element with given index/key exists + * + * @param int|string $index The index/key of element + * @return bool + */ + private function exists($index): bool + { + return isset($this->elements[$index]) || array_key_exists($index, $this->elements); + } } diff --git a/src/Traits/Collection/AddTrait.php b/src/Traits/Collection/AddTrait.php deleted file mode 100644 index 62b715d..0000000 --- a/src/Traits/Collection/AddTrait.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @copyright Meritoo - */ -trait AddTrait -{ - /** - * Adds given element (at the end of collection) - * - * @param mixed $element The element to add - * @param mixed $index (optional) Index / key of the element - */ - public function add($element, $index = null): void - { - if (!$this->isValidType($element)) { - return; - } - - if (null === $index) { - $this->elements[] = $element; - - return; - } - - $this->elements[$index] = $element; - } - - /** - * Adds given elements (at the end of collection) - * - * @param array|CollectionInterface $elements The elements to add - * @param bool $useIndexes (optional) If is set to true, indexes of given elements will be - * used in this collection. Otherwise - not. - */ - public function addMultiple($elements, bool $useIndexes = false): void - { - if (empty($elements)) { - return; - } - - foreach ($elements as $index => $element) { - if ($useIndexes) { - $this->add($element, $index); - - continue; - } - - $this->add($element); - } - } -} diff --git a/src/Traits/Collection/ArrayAccessTrait.php b/src/Traits/Collection/ArrayAccessTrait.php deleted file mode 100644 index faa6076..0000000 --- a/src/Traits/Collection/ArrayAccessTrait.php +++ /dev/null @@ -1,67 +0,0 @@ - - * @copyright Meritoo - */ -trait ArrayAccessTrait -{ - /** - * {@inheritdoc} - */ - public function offsetExists($offset): bool - { - return $this->exists($offset); - } - - /** - * {@inheritdoc} - */ - public function offsetGet($offset) - { - if ($this->exists($offset)) { - return $this->elements[$offset]; - } - - return null; - } - - /** - * {@inheritdoc} - */ - public function offsetSet($offset, $value): void - { - $this->elements[$offset] = $value; - } - - /** - * {@inheritdoc} - */ - public function offsetUnset($offset): void - { - if ($this->exists($offset)) { - unset($this->elements[$offset]); - } - } - - /** - * Returns information if element with given index/key exists - * - * @param int|string $index The index/key of element - * @return bool - */ - private function exists($index): bool - { - return isset($this->elements[$index]) || array_key_exists($index, $this->elements); - } -} diff --git a/src/Traits/Collection/CountableTrait.php b/src/Traits/Collection/CountableTrait.php deleted file mode 100644 index 761581f..0000000 --- a/src/Traits/Collection/CountableTrait.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @copyright Meritoo - */ -trait CountableTrait -{ - /** - * {@inheritdoc} - */ - public function count(): int - { - return count($this->elements); - } -} diff --git a/src/Traits/Collection/GetTrait.php b/src/Traits/Collection/GetTrait.php deleted file mode 100644 index 4cba31b..0000000 --- a/src/Traits/Collection/GetTrait.php +++ /dev/null @@ -1,73 +0,0 @@ - - * @copyright Meritoo - */ -trait GetTrait -{ - /** - * Returns previous element for given element - * - * @param mixed $element The element to verify - * @return null|mixed - */ - public function getPrevious($element) - { - return Arrays::getPreviousElement($this->elements, $element); - } - - /** - * Returns next element for given element - * - * @param mixed $element The element to verify - * @return null|mixed - */ - public function getNext($element) - { - return Arrays::getNextElement($this->elements, $element); - } - - /** - * Returns the first element in the collection - * - * @return mixed - */ - public function getFirst() - { - return Arrays::getFirstElement($this->elements); - } - - /** - * Returns the last element in the collection - * - * @return mixed - */ - public function getLast() - { - return Arrays::getLastElement($this->elements); - } - - /** - * Returns element with given index - * - * @param mixed $index Index / key of the element - * @return null|mixed - */ - public function getByIndex($index) - { - return $this->elements[$index] ?? null; - } -} diff --git a/src/Traits/Collection/IteratorAggregateTrait.php b/src/Traits/Collection/IteratorAggregateTrait.php deleted file mode 100644 index 7430212..0000000 --- a/src/Traits/Collection/IteratorAggregateTrait.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @copyright Meritoo - */ -trait IteratorAggregateTrait -{ - /** - * {@inheritdoc} - */ - public function getIterator(): ArrayIterator - { - return new ArrayIterator($this->elements); - } -} diff --git a/src/Traits/Collection/MainTrait.php b/src/Traits/Collection/MainTrait.php deleted file mode 100644 index 8b08e6c..0000000 --- a/src/Traits/Collection/MainTrait.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright Meritoo - */ -trait MainTrait -{ - /** - * The elements of collection - * - * @var array - */ - private $elements; - - /** - * Returns representation of object as array - * - * @return array - */ - public function toArray(): array - { - return $this->elements; - } -} diff --git a/src/Traits/Collection/ModifyTrait.php b/src/Traits/Collection/ModifyTrait.php deleted file mode 100644 index c08e677..0000000 --- a/src/Traits/Collection/ModifyTrait.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @copyright Meritoo - */ -trait ModifyTrait -{ - /** - * Prepends given element (adds given element at the beginning of collection) - * - * @param mixed $element The element to prepend - */ - public function prepend($element): void - { - array_unshift($this->elements, $element); - } - - /** - * Removes given element - * - * @param mixed $element The element to remove - */ - public function remove($element): void - { - if (0 === $this->count()) { - return; - } - - foreach ($this->elements as $index => $existing) { - if ($element === $existing) { - unset($this->elements[$index]); - - break; - } - } - } -} diff --git a/src/Traits/Collection/VerifyTrait.php b/src/Traits/Collection/VerifyTrait.php deleted file mode 100644 index b88d821..0000000 --- a/src/Traits/Collection/VerifyTrait.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @copyright Meritoo - */ -trait VerifyTrait -{ - /** - * Returns information if collection is empty - * - * @return bool - */ - public function isEmpty(): bool - { - return empty($this->elements); - } - - /** - * Returns information if given element is first in the collection - * - * @param mixed $element The element to verify - * @return bool - */ - public function isFirst($element): bool - { - return reset($this->elements) === $element; - } - - /** - * Returns information if given element is last in the collection - * - * @param mixed $element The element to verify - * @return bool - */ - public function isLast($element): bool - { - return end($this->elements) === $element; - } - - /** - * Returns information if the collection has given element, iow. if given element exists in the collection - * - * @param mixed $element The element to verify - * @return bool - */ - public function has($element): bool - { - $index = Arrays::getIndexOf($this->elements, $element); - - return null !== $index && false !== $index; - } -} diff --git a/src/Traits/CollectionTrait.php b/src/Traits/CollectionTrait.php deleted file mode 100644 index 4ffafa1..0000000 --- a/src/Traits/CollectionTrait.php +++ /dev/null @@ -1,38 +0,0 @@ - - * @copyright Meritoo - */ -trait CollectionTrait -{ - use MainTrait; - use AddTrait; - use ModifyTrait; - use GetTrait; - use VerifyTrait; - use CountableTrait; - use ArrayAccessTrait; - use IteratorAggregateTrait; -} From 118fa6477212e115a866ec8d75a43881840d1e0e Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 4 Apr 2021 23:06:36 +0200 Subject: [PATCH 117/137] Increase code coverage of the BaseCollection class --- phpunit.xml.dist | 3 +++ tests/Collection/BaseCollectionTest.php | 36 +++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index acd207b..a6964df 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -18,6 +18,9 @@ tests + + tests/Collection + diff --git a/tests/Collection/BaseCollectionTest.php b/tests/Collection/BaseCollectionTest.php index 0b64961..f6ea186 100644 --- a/tests/Collection/BaseCollectionTest.php +++ b/tests/Collection/BaseCollectionTest.php @@ -140,6 +140,24 @@ class BaseCollectionTest extends BaseTestCase static::assertInstanceOf(ArrayIterator::class, $this->simpleCollection->getIterator()); } + /** + * @param mixed $element The element to add + * @param int $expectedCount Expected count of elements in collection + * @param CollectionInterface $collection The collection + * + * @dataProvider provideElementToAddWithInvalidType + */ + public function testAddWithInvalidType( + $element, + int $expectedCount, + CollectionInterface $collection + ): void { + $collection->add($element); + + static::assertFalse($collection->has($element)); + static::assertSame($expectedCount, $collection->count()); + } + /** * @param mixed $element The element to add * @param int $expectedCount Expected count of elements in collection @@ -371,6 +389,24 @@ class BaseCollectionTest extends BaseTestCase static::assertSame($expected, $collection->toArray(), $description); } + public function provideElementToAddWithInvalidType(): ?Generator + { + yield [ + ['test'], + 0, + new StringCollection(), + ]; + + yield [ + 123, + 2, + new StringCollection([ + 'I am 1st', + 'I am 2nd', + ]), + ]; + } + /** * Provides element to add to collection * From 95b0cf6cabca51f30dac5ab14a9fff989e9f7950 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 4 Apr 2021 23:09:13 +0200 Subject: [PATCH 118/137] Create clear() & limit() methods in BaseCollection class --- src/Collection/BaseCollection.php | 35 +++++ .../Collection/CollectionInterface.php | 4 + tests/Collection/BaseCollectionTest.php | 133 ++++++++++++++++++ 3 files changed, 172 insertions(+) diff --git a/src/Collection/BaseCollection.php b/src/Collection/BaseCollection.php index 36e46b7..fc9b141 100644 --- a/src/Collection/BaseCollection.php +++ b/src/Collection/BaseCollection.php @@ -223,6 +223,41 @@ abstract class BaseCollection implements CollectionInterface return null !== $index && false !== $index; } + public function clear(): void + { + $this->elements = []; + } + + public function limit(int $max, int $offset = 0): CollectionInterface + { + $result = clone $this; + + $negativeMax = $max <= 0; + $exceededMax = $max >= $this->count(); + + if ($negativeMax || $exceededMax) { + if ($negativeMax) { + $result->clear(); + } + + return $result; + } + + $iteration = -1; + + foreach ($result as $index => $element) { + $iteration++; + + if ($iteration < $offset || ($iteration >= $offset && $iteration < $max)) { + continue; + } + + unset($result[$index]); + } + + return $result; + } + public function count(): int { return count($this->elements); diff --git a/src/Contract/Collection/CollectionInterface.php b/src/Contract/Collection/CollectionInterface.php index df84414..2c5988d 100644 --- a/src/Contract/Collection/CollectionInterface.php +++ b/src/Contract/Collection/CollectionInterface.php @@ -49,4 +49,8 @@ interface CollectionInterface extends Countable, ArrayAccess, IteratorAggregate public function isLast($element): bool; public function has($element): bool; + + public function clear(): void; + + public function limit(int $max, int $offset = 0): self; } diff --git a/tests/Collection/BaseCollectionTest.php b/tests/Collection/BaseCollectionTest.php index f6ea186..5cb8259 100644 --- a/tests/Collection/BaseCollectionTest.php +++ b/tests/Collection/BaseCollectionTest.php @@ -389,6 +389,51 @@ class BaseCollectionTest extends BaseTestCase static::assertSame($expected, $collection->toArray(), $description); } + public function testClearIfIsEmpty(): void + { + self::assertCount(0, $this->emptyCollection); + $this->emptyCollection->clear(); + self::assertCount(0, $this->emptyCollection); + } + + public function testClear(): void + { + self::assertCount(4, $this->simpleCollection); + $this->simpleCollection->clear(); + self::assertCount(0, $this->simpleCollection); + } + + public function testLimitIfIsEmpty(): void + { + $result = $this->emptyCollection->limit(10); + self::assertEquals(new StringCollection(), $result); + } + + /** + * @param array $expected + * @param int $max + * + * @dataProvider provideResultOfLimitWithDefaultOffset + */ + public function testLimitWithDefaultOffset(array $expected, int $max): void + { + $result = $this->simpleCollection->limit($max); + self::assertSame($expected, $result->toArray()); + } + + /** + * @param array $expected + * @param int $max + * @param int $offset + * + * @dataProvider provideResultOfLimit + */ + public function testLimit(array $expected, int $max, int $offset): void + { + $result = $this->simpleCollection->limit($max, $offset); + self::assertSame($expected, $result->toArray()); + } + public function provideElementToAddWithInvalidType(): ?Generator { yield [ @@ -623,6 +668,94 @@ class BaseCollectionTest extends BaseTestCase ]; } + public function provideResultOfLimitWithDefaultOffset(): ?Generator + { + yield 'Negative value of maximum' => [ + [], + -1, + ]; + + yield 'Maximum set to 0' => [ + [], + 0, + ]; + + yield 'Maximum set to 1' => [ + [ + 'lorem', + ], + 1, + ]; + + yield 'Maximum greater than size of collection' => [ + [ + 'lorem', + 'ipsum', + 123 => 'dolor', + 345 => 'sit', + ], + 10, + ]; + } + + public function provideResultOfLimit(): ?Generator + { + yield 'Negative value of maximum & negative offset' => [ + [], + -1, + -2, + ]; + + yield 'Negative value of maximum & positive offset' => [ + [], + -1, + 2, + ]; + + yield 'Maximum set to 0 & negative offset' => [ + [], + 0, + -2, + ]; + + yield 'Maximum set to 0 & positive offset' => [ + [], + 0, + 2, + ]; + + yield 'Maximum set to 1 & offset smaller than size of collection' => [ + [ + 'lorem', + 'ipsum', + ], + 1, + 2, + ]; + + yield 'Maximum set to 1 & offset equal size of collection' => [ + [ + 'lorem', + 'ipsum', + 123 => 'dolor', + 345 => 'sit', + ], + 1, + 4, + ]; + + yield 'Maximum set to 1 & offset greater than size of collection' => [ + [ + 'lorem', + 'ipsum', + 123 => 'dolor', + 345 => 'sit', + ], + 1, + 10, + ]; + } + /** * {@inheritdoc} */ From 598f1731be280e8fd95a77a33ad596ae8e3f7447 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 4 Apr 2021 23:09:50 +0200 Subject: [PATCH 119/137] Add missing "declare(strict_types=1)" --- src/Traits/Test/Base/BaseTestCaseTrait.php | 2 ++ src/Traits/Test/Base/BaseTypeTestCaseTrait.php | 2 ++ src/Traits/ValueObject/HumanTrait.php | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/Traits/Test/Base/BaseTestCaseTrait.php b/src/Traits/Test/Base/BaseTestCaseTrait.php index 11ec351..bdf852b 100644 --- a/src/Traits/Test/Base/BaseTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTestCaseTrait.php @@ -6,6 +6,8 @@ * file that was distributed with this source code. */ +declare(strict_types=1); + namespace Meritoo\Common\Traits\Test\Base; use DateTime; diff --git a/src/Traits/Test/Base/BaseTypeTestCaseTrait.php b/src/Traits/Test/Base/BaseTypeTestCaseTrait.php index e08c7b4..9a86368 100644 --- a/src/Traits/Test/Base/BaseTypeTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTypeTestCaseTrait.php @@ -6,6 +6,8 @@ * file that was distributed with this source code. */ +declare(strict_types=1); + namespace Meritoo\Common\Traits\Test\Base; use Generator; diff --git a/src/Traits/ValueObject/HumanTrait.php b/src/Traits/ValueObject/HumanTrait.php index a75bfa6..bfaea59 100644 --- a/src/Traits/ValueObject/HumanTrait.php +++ b/src/Traits/ValueObject/HumanTrait.php @@ -6,6 +6,8 @@ * file that was distributed with this source code. */ +declare(strict_types=1); + namespace Meritoo\Common\Traits\ValueObject; use DateTime; From 0d3265d7b6c8239124e2f5de0afc78486f7b28ff Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 4 Apr 2021 23:26:35 +0200 Subject: [PATCH 120/137] Increase code coverage of the BaseTestCaseTrait --- .../Base/BaseTestCaseTrait/SimpleTestCase.php | 4 ++ .../Test/Base/BaseTestCaseTraitTest.php | 38 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/tests/Traits/Test/Base/BaseTestCaseTrait/SimpleTestCase.php b/tests/Traits/Test/Base/BaseTestCaseTrait/SimpleTestCase.php index 191beb4..02258b6 100644 --- a/tests/Traits/Test/Base/BaseTestCaseTrait/SimpleTestCase.php +++ b/tests/Traits/Test/Base/BaseTestCaseTrait/SimpleTestCase.php @@ -19,4 +19,8 @@ use Meritoo\Common\Traits\Test\Base\BaseTestCaseTrait; class SimpleTestCase { use BaseTestCaseTrait; + + private function thePrivateMethod(): void + { + } } diff --git a/tests/Traits/Test/Base/BaseTestCaseTraitTest.php b/tests/Traits/Test/Base/BaseTestCaseTraitTest.php index a74e6fd..7b9bf4b 100644 --- a/tests/Traits/Test/Base/BaseTestCaseTraitTest.php +++ b/tests/Traits/Test/Base/BaseTestCaseTraitTest.php @@ -11,8 +11,13 @@ declare(strict_types=1); namespace Meritoo\Test\Common\Traits\Test\Base; use DateTime; +use Meritoo\Common\Exception\Reflection\ClassWithoutConstructorException; +use Meritoo\Common\Exception\Type\UnknownOopVisibilityTypeException; use Meritoo\Common\Test\Base\BaseTestCase; +use Meritoo\Common\Traits\Test\Base\BaseTestCaseTrait; +use Meritoo\Common\Type\OopVisibilityType; use Meritoo\Test\Common\Traits\Test\Base\BaseTestCaseTrait\SimpleTestCase; +use ReflectionMethod; use stdClass; /** @@ -26,6 +31,39 @@ use stdClass; */ class BaseTestCaseTraitTest extends BaseTestCase { + use BaseTestCaseTrait; + + public function testAssertMethodVisibility(): void + { + $method = new ReflectionMethod(SimpleTestCase::class, 'assertMethodVisibility'); + static::assertMethodVisibility($method, OopVisibilityType::IS_PROTECTED); + } + + public function testAssertMethodVisibilityUsingIncorrectVisibility(): void + { + $this->expectException(UnknownOopVisibilityTypeException::class); + + $method = new ReflectionMethod(SimpleTestCase::class, 'assertMethodVisibility'); + static::assertMethodVisibility($method, '4'); + } + + public function testAssertMethodVisibilityUsingPrivate(): void + { + $method = new ReflectionMethod(SimpleTestCase::class, 'thePrivateMethod'); + static::assertMethodVisibility($method, OopVisibilityType::IS_PRIVATE); + } + + public function testAssertConstructorVisibilityAndArgumentsUsingClassWithoutConstructor(): void + { + $this->expectException(ClassWithoutConstructorException::class); + static::assertConstructorVisibilityAndArguments(SimpleTestCase::class, OopVisibilityType::IS_PUBLIC); + } + + public function testAssertHasNoConstructor(): void + { + static::assertHasNoConstructor(SimpleTestCase::class); + } + public function testProvideEmptyValue(): void { $testCase = new SimpleTestCase(); From 1eb86cf102cc6e7a55848cb910a734bfe5049002 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 11 Apr 2021 21:45:29 +0200 Subject: [PATCH 121/137] [BaseCollection] Fix incorrectly working limit() method --- CHANGELOG.md | 4 ++++ VERSION | 2 +- src/Collection/BaseCollection.php | 2 +- tests/Collection/BaseCollectionTest.php | 21 ++++++--------------- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be146a5..c9ddf64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Common and useful classes, methods, exceptions etc. +# 1.1.4 + +1. [BaseCollection] Fix incorrectly working limit() method + # 1.1.3 1. Move `Renderable` class: `Meritoo\Common` -> `Meritoo\Common\Contract` diff --git a/VERSION b/VERSION index 781dcb0..65087b4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.3 +1.1.4 diff --git a/src/Collection/BaseCollection.php b/src/Collection/BaseCollection.php index fc9b141..0b1f3dd 100644 --- a/src/Collection/BaseCollection.php +++ b/src/Collection/BaseCollection.php @@ -248,7 +248,7 @@ abstract class BaseCollection implements CollectionInterface foreach ($result as $index => $element) { $iteration++; - if ($iteration < $offset || ($iteration >= $offset && $iteration < $max)) { + if ($iteration >= $offset && $iteration < $offset + $max) { continue; } diff --git a/tests/Collection/BaseCollectionTest.php b/tests/Collection/BaseCollectionTest.php index 5cb8259..cdb5c01 100644 --- a/tests/Collection/BaseCollectionTest.php +++ b/tests/Collection/BaseCollectionTest.php @@ -724,33 +724,24 @@ class BaseCollectionTest extends BaseTestCase 2, ]; - yield 'Maximum set to 1 & offset smaller than size of collection' => [ + yield 'Maximum set to 1 & offset set to 2' => [ [ - 'lorem', - 'ipsum', + 123 => 'dolor', ], 1, 2, ]; - yield 'Maximum set to 1 & offset equal size of collection' => [ + yield 'Maximum set to 1 & offset set to 3' => [ [ - 'lorem', - 'ipsum', - 123 => 'dolor', 345 => 'sit', ], 1, - 4, + 3, ]; - yield 'Maximum set to 1 & offset greater than size of collection' => [ - [ - 'lorem', - 'ipsum', - 123 => 'dolor', - 345 => 'sit', - ], + yield 'Maximum set to 1 & offset set to 10' => [ + [], 1, 10, ]; From a459bfe1ce38ab17e9da58cfeea74e9dfd3a79a9 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 11 Apr 2021 22:22:36 +0200 Subject: [PATCH 122/137] Use larger collection while testing the BaseCollection class --- tests/Collection/BaseCollectionTest.php | 60 +++++++++++++++++-------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/tests/Collection/BaseCollectionTest.php b/tests/Collection/BaseCollectionTest.php index cdb5c01..062b931 100644 --- a/tests/Collection/BaseCollectionTest.php +++ b/tests/Collection/BaseCollectionTest.php @@ -71,8 +71,8 @@ class BaseCollectionTest extends BaseTestCase public function testNotEmptyCollection() { - static::assertSame(4, $this->simpleCollection->count()); - static::assertCount(4, $this->simpleCollection); + static::assertSame(7, $this->simpleCollection->count()); + static::assertCount(7, $this->simpleCollection); static::assertNotEmpty($this->simpleCollection); static::assertFalse($this->simpleCollection->isEmpty()); @@ -80,14 +80,14 @@ class BaseCollectionTest extends BaseTestCase static::assertNotEmpty($this->simpleCollection->toArray()); static::assertSame('lorem', $this->simpleCollection->getFirst()); - static::assertSame('sit', $this->simpleCollection->getLast()); + static::assertSame('adipiscing elit', $this->simpleCollection->getLast()); static::assertSame('dolor', $this->simpleCollection[123]); } public function testCount() { static::assertSame(0, $this->emptyCollection->count()); - static::assertSame(4, $this->simpleCollection->count()); + static::assertSame(7, $this->simpleCollection->count()); } public function testOffsetExists() @@ -126,13 +126,13 @@ class BaseCollectionTest extends BaseTestCase static::assertFalse($this->simpleCollection->has('lorem')); static::assertSame('ipsum', $this->simpleCollection[1]); - static::assertSame(3, $this->simpleCollection->count()); + static::assertSame(6, $this->simpleCollection->count()); unset($this->simpleCollection[123]); static::assertFalse($this->simpleCollection->has('dolor')); static::assertSame('ipsum', $this->simpleCollection[1]); - static::assertSame(2, $this->simpleCollection->count()); + static::assertSame(5, $this->simpleCollection->count()); } public function testGetIterator() @@ -256,7 +256,7 @@ class BaseCollectionTest extends BaseTestCase $this->simpleCollection->prepend('lorem-ipsum'); static::assertFalse($this->simpleCollection->isEmpty()); - static::assertSame(5, $this->simpleCollection->count()); + static::assertSame(8, $this->simpleCollection->count()); static::assertSame('lorem-ipsum', $this->simpleCollection[0]); } @@ -270,19 +270,19 @@ class BaseCollectionTest extends BaseTestCase $this->simpleCollection->remove('abc'); static::assertFalse($this->simpleCollection->isEmpty()); - static::assertSame(4, $this->simpleCollection->count()); + static::assertSame(7, $this->simpleCollection->count()); } public function testRemove() { static::assertFalse($this->simpleCollection->isEmpty()); - static::assertSame(4, $this->simpleCollection->count()); + static::assertSame(7, $this->simpleCollection->count()); static::assertSame('ipsum', $this->simpleCollection[1]); $this->simpleCollection->remove('ipsum'); static::assertFalse($this->simpleCollection->isEmpty()); - static::assertSame(3, $this->simpleCollection->count()); + static::assertSame(6, $this->simpleCollection->count()); static::assertNull($this->simpleCollection[1]); } @@ -305,7 +305,7 @@ class BaseCollectionTest extends BaseTestCase static::assertFalse($this->emptyCollection->isLast('abc')); static::assertFalse($this->simpleCollection->isLast('abc')); static::assertFalse($this->simpleCollection->isLast('dolor')); - static::assertTrue($this->simpleCollection->isLast('sit')); + static::assertTrue($this->simpleCollection->isLast('adipiscing elit')); } public function testHas() @@ -330,7 +330,7 @@ class BaseCollectionTest extends BaseTestCase { static::assertNull($this->emptyCollection->getNext('abc')); static::assertNull($this->simpleCollection->getNext('abc')); - static::assertNull($this->simpleCollection->getNext('sit')); + static::assertNull($this->simpleCollection->getNext('adipiscing elit')); static::assertSame('dolor', $this->simpleCollection->getNext('ipsum')); static::assertSame('sit', $this->simpleCollection->getNext('dolor')); @@ -345,7 +345,7 @@ class BaseCollectionTest extends BaseTestCase public function testGetLast() { static::assertNull($this->emptyCollection->getLast()); - static::assertSame('sit', $this->simpleCollection->getLast()); + static::assertSame('adipiscing elit', $this->simpleCollection->getLast()); } public function testToArray() @@ -398,7 +398,7 @@ class BaseCollectionTest extends BaseTestCase public function testClear(): void { - self::assertCount(4, $this->simpleCollection); + self::assertCount(7, $this->simpleCollection); $this->simpleCollection->clear(); self::assertCount(0, $this->simpleCollection); } @@ -687,12 +687,24 @@ class BaseCollectionTest extends BaseTestCase 1, ]; + yield 'Maximum set to 3' => [ + [ + 'lorem', + 'ipsum', + 123 => 'dolor', + ], + 3, + ]; + yield 'Maximum greater than size of collection' => [ [ 'lorem', 'ipsum', 123 => 'dolor', 345 => 'sit', + 'a' => 'amet', + 'c' => 'consectetur', + 346 => 'adipiscing elit', ], 10, ]; @@ -732,15 +744,24 @@ class BaseCollectionTest extends BaseTestCase 2, ]; - yield 'Maximum set to 1 & offset set to 3' => [ + yield 'Maximum set to 2 & offset set to 2' => [ [ + 123 => 'dolor', 345 => 'sit', ], - 1, - 3, + 2, + 2, ]; - yield 'Maximum set to 1 & offset set to 10' => [ + yield 'Maximum set to 3 & offset set to latest element' => [ + [ + 346 => 'adipiscing elit', + ], + 3, + 6, + ]; + + yield 'Maximum set to 1 & offset greater than size of collection' => [ [], 1, 10, @@ -759,6 +780,9 @@ class BaseCollectionTest extends BaseTestCase 'ipsum', 123 => 'dolor', 345 => 'sit', + 'a' => 'amet', + 'c' => 'consectetur', + 'adipiscing elit', ]; $this->emptyCollection = new StringCollection(); From fcaae95810dac8f9789fcadb1c10a427aa8bdf30 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 27 Apr 2021 22:13:11 +0200 Subject: [PATCH 123/137] [BaseCollection] Prepare elements while adding them by addMultiple() method in the same way as passing them in constructor --- CHANGELOG.md | 5 +++++ VERSION | 2 +- src/Collection/BaseCollection.php | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9ddf64..82e49bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Common and useful classes, methods, exceptions etc. +# 1.1.5 + +1. [BaseCollection] Prepare elements while adding them by `addMultiple()` method in the same way as passing them in + constructor. + # 1.1.4 1. [BaseCollection] Fix incorrectly working limit() method diff --git a/VERSION b/VERSION index 65087b4..e25d8d9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.4 +1.1.5 diff --git a/src/Collection/BaseCollection.php b/src/Collection/BaseCollection.php index 0b1f3dd..f2539dc 100644 --- a/src/Collection/BaseCollection.php +++ b/src/Collection/BaseCollection.php @@ -84,7 +84,9 @@ abstract class BaseCollection implements CollectionInterface return; } - foreach ($elements as $index => $element) { + $prepared = $this->prepareElements($elements); + + foreach ($prepared as $index => $element) { if ($useIndexes) { $this->add($element, $index); From feb8fc293b48df2a6f40b75da68f964917b268f5 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 5 Feb 2022 16:54:36 +0100 Subject: [PATCH 124/137] Fix "floor(): Argument #1 ($num) must be of type int|float, string given" TypeError while running test of Meritoo\Common\Utilities\Miscellaneous::isDecimal() --- VERSION | 2 +- src/Utilities/Miscellaneous.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index e25d8d9..0664a8f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.5 +1.1.6 diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index 3038711..3068405 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -729,7 +729,7 @@ class Miscellaneous */ public static function isDecimal($value) { - return is_scalar($value) && floor($value) !== (float)$value; + return is_scalar($value) && is_numeric($value)&&floor($value) !== (float)$value; } /** From 151ce39226d67b2e604d39dd4026651816832ef9 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 5 Feb 2022 16:57:12 +0100 Subject: [PATCH 125/137] Fix "str_replace(): Argument #2 ($replace) must be of type array|string, int given" TypeError while running test of Meritoo\Common\ValueObject\Template::fill() --- src/ValueObject/Template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ValueObject/Template.php b/src/ValueObject/Template.php index 15bcd57..e06dff6 100644 --- a/src/ValueObject/Template.php +++ b/src/ValueObject/Template.php @@ -75,7 +75,7 @@ class Template if (isset($values[$placeholderName])) { $value = $values[$placeholderName]; - $result = str_replace($placeholder, $value, $result); + $result = str_replace($placeholder, (string)$value, $result); } } From 067be1ab1d90cc6caf84b709db67692cd85d7cf1 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 5 Feb 2022 19:50:36 +0100 Subject: [PATCH 126/137] [Arrays] Function that returns elements from given level --- CHANGELOG.md | 4 ++ src/Utilities/Arrays.php | 37 +++++++++++ tests/Utilities/ArraysTest.php | 110 +++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82e49bd..f986f09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Common and useful classes, methods, exceptions etc. +# 1.1.6 + +1. [Arrays] Function that returns elements from given level + # 1.1.5 1. [BaseCollection] Prepare elements while adding them by `addMultiple()` method in the same way as passing them in diff --git a/src/Utilities/Arrays.php b/src/Utilities/Arrays.php index 0a77a3f..3d6e302 100644 --- a/src/Utilities/Arrays.php +++ b/src/Utilities/Arrays.php @@ -1642,6 +1642,43 @@ class Arrays return '' === trim(implode('', $array)); } + public static function getElementsFromLevel(array $array, int $level): ?array + { + if (empty($array) || $level <= 0) { + return null; + } + + $result = []; + + foreach ($array as $value) { + // This is the expected level (the deepest). Comparing with 1, because level will be decreased by 1, and + // finally we will get the latest/deepest level that equals 1. + if ($level === 1) { + $result[] = $value; + continue; + } + + // There is no deeper level + if (!is_array($value)) { + continue; + } + + // Let's dive one level down + $elements = self::getElementsFromLevel($value, $level - 1); + + if ($elements === null) { + continue; + } + + // I have to load each element separately to avoid issue with incorrectly nested values + foreach ($elements as $element) { + $result[] = $element; + } + } + + return $result; + } + /** * Returns neighbour (next or previous element) for given element * diff --git a/tests/Utilities/ArraysTest.php b/tests/Utilities/ArraysTest.php index 385fc7a..377210c 100644 --- a/tests/Utilities/ArraysTest.php +++ b/tests/Utilities/ArraysTest.php @@ -1535,6 +1535,116 @@ letsTest[2] = value_2;'; static::assertSame($expected, Arrays::containsEmptyStringsOnly($array)); } + public function testGetElementsFromLevelIfArrayIsEmpty(): void + { + self::assertNull(Arrays::getElementsFromLevel([], -1)); + self::assertNull(Arrays::getElementsFromLevel([], 0)); + self::assertNull(Arrays::getElementsFromLevel([], 1)); + } + + public function testGetElementsFromLevelIfThereIsNoGivenLevel(): void + { + self::assertSame([], Arrays::getElementsFromLevel([1, 2, 3], 9999)); + } + + public function testGetElementsFromLevelIfGivenLevelIsNotPositiveValue(): void + { + self::assertNull(Arrays::getElementsFromLevel([1, 2, 3], -1)); + self::assertNull(Arrays::getElementsFromLevel([1, 2, 3], 0)); + } + + public function testGetElementsFromLevelIfArrayHasOneLevelOnly(): void + { + $array = [ + // Level 1: + 'ab', + 'cd', + 'ef', + ]; + + self::assertSame($array, Arrays::getElementsFromLevel($array, 1)); + } + + public function testGetElementsFromLevel(): void + { + $array = [ + // Level 1: + 'ab', + [ + // Level 2: + 'cd', + 'ef', + ], + + // Level 1: + [ + // Level 2: + 'gh', + [ + // Level 3: + 'ij', + 'kl', + ], + ], + + // Level 1: + [ + // Level 2: + [ + // Level 3: + 'mn', + 'op', + ], + ], + ]; + + $expectedLevel1 = [ + 'ab', + [ + 'cd', + 'ef', + ], + [ + 'gh', + [ + 'ij', + 'kl', + ], + ], + [ + [ + 'mn', + 'op', + ], + ], + ]; + + $expectedLevel2 = [ + 'cd', + 'ef', + 'gh', + [ + 'ij', + 'kl', + ], + [ + 'mn', + 'op', + ], + ]; + + $expectedLevel3 = [ + 'ij', + 'kl', + 'mn', + 'op', + ]; + + self::assertSame($expectedLevel1, Arrays::getElementsFromLevel($array, 1)); + self::assertSame($expectedLevel2, Arrays::getElementsFromLevel($array, 2)); + self::assertSame($expectedLevel3, Arrays::getElementsFromLevel($array, 3)); + } + /** * Provides simple array to set/replace values with keys * From ae72d582e6cef6eb4b2d39e533648ba77f9bae9c Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 5 Feb 2022 21:24:19 +0100 Subject: [PATCH 127/137] Reformat code --- VERSION | 2 +- src/Utilities/Miscellaneous.php | 2 +- src/ValueObject/Template.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 0664a8f..2bf1ca5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.6 +1.1.7 diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index 3068405..f760215 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -729,7 +729,7 @@ class Miscellaneous */ public static function isDecimal($value) { - return is_scalar($value) && is_numeric($value)&&floor($value) !== (float)$value; + return is_scalar($value) && is_numeric($value) && floor($value) !== (float) $value; } /** diff --git a/src/ValueObject/Template.php b/src/ValueObject/Template.php index e06dff6..db22fc9 100644 --- a/src/ValueObject/Template.php +++ b/src/ValueObject/Template.php @@ -75,7 +75,7 @@ class Template if (isset($values[$placeholderName])) { $value = $values[$placeholderName]; - $result = str_replace($placeholder, (string)$value, $result); + $result = str_replace($placeholder, (string) $value, $result); } } From ba24e2de233c66844437f38dafb2b8a9ab3e085d Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 6 Feb 2022 15:28:35 +0100 Subject: [PATCH 128/137] [Arrays] Allow to define a key of next level elements in a function that returns elements from given level --- CHANGELOG.md | 6 ++- src/Utilities/Arrays.php | 19 ++++++---- tests/Utilities/ArraysTest.php | 67 ++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f986f09..009e565 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,17 @@ Common and useful classes, methods, exceptions etc. +# 1.1.7 + +1. [Arrays] Allow to define a key of next level elements in a function that returns elements from given level + # 1.1.6 1. [Arrays] Function that returns elements from given level # 1.1.5 -1. [BaseCollection] Prepare elements while adding them by `addMultiple()` method in the same way as passing them in +1. [BaseCollection] Prepare elements while adding them by `addMultiple()` method in the same way as passing them in constructor. # 1.1.4 diff --git a/src/Utilities/Arrays.php b/src/Utilities/Arrays.php index 3d6e302..7e49461 100644 --- a/src/Utilities/Arrays.php +++ b/src/Utilities/Arrays.php @@ -1642,7 +1642,7 @@ class Arrays return '' === trim(implode('', $array)); } - public static function getElementsFromLevel(array $array, int $level): ?array + public static function getElementsFromLevel(array $array, int $level, ?string $childrenKey = null): ?array { if (empty($array) || $level <= 0) { return null; @@ -1650,11 +1650,16 @@ class Arrays $result = []; - foreach ($array as $value) { - // This is the expected level (the deepest). Comparing with 1, because level will be decreased by 1, and - // finally we will get the latest/deepest level that equals 1. + foreach ($array as $key => $value) { + // This is the expected level (the deepest). Comparing with 1, because level will be decreased by 1 (later), + // and finally we will get the latest/deepest level that equals 1. if ($level === 1) { - $result[] = $value; + // No key of children (next level) provided or this is the same key as processed? + // We've got the expected value + if ($childrenKey === null || $key === $childrenKey) { + $result[] = $value; + } + continue; } @@ -1663,8 +1668,8 @@ class Arrays continue; } - // Let's dive one level down - $elements = self::getElementsFromLevel($value, $level - 1); + // Let's dive one level down/deeper + $elements = self::getElementsFromLevel($value, $level - 1, $childrenKey); if ($elements === null) { continue; diff --git a/tests/Utilities/ArraysTest.php b/tests/Utilities/ArraysTest.php index 377210c..1f65326 100644 --- a/tests/Utilities/ArraysTest.php +++ b/tests/Utilities/ArraysTest.php @@ -1645,6 +1645,73 @@ letsTest[2] = value_2;'; self::assertSame($expectedLevel3, Arrays::getElementsFromLevel($array, 3)); } + public function testGetElementsFromLevelIfGivenKeyDoesNotExist(): void + { + $array = [ + 'test1' => [1, 2, 3], + 'test2' => [4, 5, 6], + 'test3' => [ + 'xy', + 'test4' => [7, 8, 9], + 'test5' => [ + 'test6' => [10, 11, 12], + ], + ], + ]; + + self::assertSame([], Arrays::getElementsFromLevel($array, 2, 'X')); + } + + public function testGetElementsFromLevelWithGivenKey(): void + { + $array = [ + // Level 1: + [ + 'a', + 'b', + + // Level 2: + 'c' => [ + 1, + 2, + 'c' => [ + 4, + 5, + ], + ], + ], + + // Level 1: + [ + 'd', + 'e', + + // Level 2: + 'c' => [ + 6, + 7, + ], + ], + ]; + + $expected = [ + [ + 1, + 2, + 'c' => [ + 4, + 5, + ], + ], + [ + 6, + 7, + ], + ]; + + self::assertSame($expected, Arrays::getElementsFromLevel($array, 2, 'c')); + } + /** * Provides simple array to set/replace values with keys * From 31a7ca6d1abe3df74e829f2a998558b723d42faf Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 6 Feb 2022 17:47:43 +0100 Subject: [PATCH 129/137] [Arrays] Improve tests of function that returns elements from given level --- VERSION | 2 +- tests/Utilities/ArraysTest.php | 30 ++++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 2bf1ca5..18efdb9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.7 +1.1.8 diff --git a/tests/Utilities/ArraysTest.php b/tests/Utilities/ArraysTest.php index 1f65326..1c2d442 100644 --- a/tests/Utilities/ArraysTest.php +++ b/tests/Utilities/ArraysTest.php @@ -1674,6 +1674,8 @@ letsTest[2] = value_2;'; 'c' => [ 1, 2, + + // Level 3: 'c' => [ 4, 5, @@ -1690,11 +1692,17 @@ letsTest[2] = value_2;'; 'c' => [ 6, 7, + + // Level 3: + 'c' => [ + 8, + 9, + ], ], ], ]; - $expected = [ + $expected2 = [ [ 1, 2, @@ -1706,10 +1714,28 @@ letsTest[2] = value_2;'; [ 6, 7, + 'c' => [ + 8, + 9, + ], ], ]; - self::assertSame($expected, Arrays::getElementsFromLevel($array, 2, 'c')); + $expected3 = [ + [ + 4, + 5, + ], + [ + 8, + 9, + ], + ]; + + self::assertSame([], Arrays::getElementsFromLevel($array, 1, 'c')); + self::assertSame($expected2, Arrays::getElementsFromLevel($array, 2, 'c')); + self::assertSame($expected3, Arrays::getElementsFromLevel($array, 3, 'c')); + self::assertSame([], Arrays::getElementsFromLevel($array, 4, 'c')); } /** From a3af138f0cfd26fac799f6af8c3b1ba401576f1b Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 12 Feb 2022 13:33:30 +0100 Subject: [PATCH 130/137] Update documentation for Infection (Mutation Testing) and use the "nproc" command that returns the number of processors available --- docs/Development.md | 8 +++++--- phing/properties.dist | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/Development.md b/docs/Development.md index 19c6632..e2fce80 100644 --- a/docs/Development.md +++ b/docs/Development.md @@ -105,20 +105,22 @@ docker-compose exec php phing -f phing/tests.xml test:phpunit docker-compose run --rm phpunit --verbose --no-coverage ``` -# Mutation Tests +# Infection - Mutation Testing Served by [Infection — Mutation Testing Framework](https://infection.github.io). ### Running tests ```bash -docker-compose exec php vendor/bin/infection --threads=5 +$ docker-compose exec php bash +root@18f2f0cfaa5d:/var/www/application# XDEBUG_MODE=coverage ./vendor/bin/infection --threads=$(nproc) ``` or ```bash -docker-compose exec php phing -f phing/tests.xml test:infection +$ docker-compose exec php bash +root@18f2f0cfaa5d:/var/www/application# XDEBUG_MODE=coverage phing -f phing/tests.xml test:infection ``` ### Result of testing diff --git a/phing/properties.dist b/phing/properties.dist index c287955..76237a2 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -86,4 +86,4 @@ tests.database = ${dir.data.temporary}/database.sqlite # - Infection (mutation tests) # tests.phpunit.command = ./vendor/bin/phpunit --verbose -tests.mutation.command = ./vendor/bin/infection --ansi --threads=5 --coverage=build/reports/infection +tests.mutation.command = ./vendor/bin/infection --ansi --threads=$(nproc) --coverage=build/reports/infection From a3adae50b8586f84e831fcb3f0a92e87491b9a4a Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 12 Feb 2022 14:46:47 +0100 Subject: [PATCH 131/137] Reformat code automatically --- .php_cs.dist | 31 +- CHANGELOG.md | 30 +- README.md | 6 +- build.xml | 10 +- docs/Base-test-case.md | 8 +- docs/Collection/BaseCollection.md | 9 +- docs/Collection/Templates.md | 34 +- docs/Development.md | 7 +- docs/Exceptions.md | 16 +- docs/Static-methods.md | 9 +- docs/Static-methods/Arrays.md | 56 +- docs/Static-methods/Regex.md | 42 +- docs/Static-methods/Uri.md | 18 +- docs/Value-Objects.md | 55 +- phing/app.xml | 80 +- phing/tests.xml | 58 +- phpunit.xml.dist | 10 +- psalm.xml | 8 +- src/Collection/BaseCollection.php | 208 +- src/Collection/Templates.php | 2 +- .../Collection/CollectionInterface.php | 26 +- src/Exception/Base/UnknownTypeException.php | 2 +- .../Bundle/IncorrectBundleNameException.php | 2 +- src/Exception/File/EmptyFileException.php | 4 +- src/Exception/File/EmptyFilePathException.php | 4 +- .../File/NotExistingFileException.php | 4 +- .../MissingChildClassesException.php | 2 +- .../NotExistingPropertyException.php | 4 +- .../TooManyChildClassesException.php | 2 +- .../IncorrectColorHexLengthException.php | 6 +- .../Regex/InvalidColorHexValueException.php | 4 +- .../Regex/InvalidHtmlAttributesException.php | 4 +- src/Exception/Regex/InvalidUrlException.php | 4 +- .../InvalidSizeDimensionsException.php | 4 +- .../MissingPlaceholdersInValuesException.php | 2 +- src/Traits/CssSelector/FormCssSelector.php | 74 +- src/Traits/Test/Base/BaseTestCaseTrait.php | 240 +- .../Test/Base/BaseTypeTestCaseTrait.php | 20 +- src/Traits/ValueObject/HumanTrait.php | 36 +- src/Type/Base/BaseType.php | 22 +- src/Type/DatePeriod.php | 46 +- src/Utilities/Arrays.php | 2584 +++---- src/Utilities/Bootstrap4CssSelector.php | 34 +- src/Utilities/Bundle.php | 4 +- src/Utilities/Date.php | 584 +- src/Utilities/Locale.php | 90 +- src/Utilities/MimeTypes.php | 1421 ++-- src/Utilities/Miscellaneous.php | 1864 ++--- src/Utilities/QueryBuilderUtility.php | 152 +- src/Utilities/Reflection.php | 814 +- src/Utilities/Regex.php | 1217 +-- src/Utilities/Repository.php | 160 +- src/Utilities/Uri.php | 288 +- src/ValueObject/Address.php | 52 +- src/ValueObject/BankAccount.php | 20 +- src/ValueObject/Company.php | 20 +- src/ValueObject/Size.php | 178 +- src/ValueObject/Template.php | 72 +- src/ValueObject/Version.php | 116 +- tests/Collection/BaseCollectionTest.php | 984 +-- tests/Collection/DateTimeCollectionTest.php | 76 +- tests/Collection/IntegerCollectionTest.php | 79 +- tests/Collection/StringCollectionTest.php | 81 +- tests/Collection/TemplatesTest.php | 214 +- .../Base/UnknownTypeExceptionTest.php | 12 +- .../IncorrectBundleNameExceptionTest.php | 50 +- .../Date/UnknownDatePartTypeExceptionTest.php | 60 +- .../Exception/File/EmptyFileExceptionTest.php | 42 +- .../File/EmptyFilePathExceptionTest.php | 12 +- .../File/NotExistingFileExceptionTest.php | 40 +- .../Method/DisabledMethodExceptionTest.php | 46 +- .../CannotResolveClassNameExceptionTest.php | 62 +- .../ClassWithoutConstructorExceptionTest.php | 34 +- .../MissingChildClassesExceptionTest.php | 49 +- .../NotExistingPropertyExceptionTest.php | 68 +- .../TooManyChildClassesExceptionTest.php | 65 +- .../IncorrectColorHexLengthExceptionTest.php | 40 +- .../InvalidColorHexValueExceptionTest.php | 40 +- .../InvalidHtmlAttributesExceptionTest.php | 50 +- .../Regex/InvalidUrlExceptionTest.php | 40 +- .../UnknownOopVisibilityTypeExceptionTest.php | 52 +- .../InvalidSizeDimensionsExceptionTest.php | 48 +- .../Template/InvalidContentExceptionTest.php | 46 +- ...ssingPlaceholdersInValuesExceptionTest.php | 67 +- .../TemplateNotFoundExceptionTest.php | 46 +- tests/Test/Base/BaseTestCaseTest.php | 116 +- .../Test/Base/BaseTestCaseTraitTest.php | 110 +- tests/Type/Base/BaseTypeTest.php | 264 +- tests/Type/DatePartTypeTest.php | 30 +- tests/Type/DatePeriodTest.php | 556 +- tests/Type/OopVisibilityTypeTest.php | 16 +- tests/Utilities/ArraysTest.php | 6630 ++++++++--------- tests/Utilities/Bootstrap4CssSelectorTest.php | 257 +- tests/Utilities/BundleTest.php | 332 +- tests/Utilities/ComposerTest.php | 60 +- tests/Utilities/CssSelectorTest.php | 431 +- tests/Utilities/DateTest.php | 1406 ++-- tests/Utilities/GeneratorUtilityTest.php | 2 +- tests/Utilities/LocaleTest.php | 330 +- tests/Utilities/MimeTypesTest.php | 646 +- tests/Utilities/MiscellaneousTest.php | 3016 ++++---- tests/Utilities/QueryBuilderUtilityTest.php | 540 +- tests/Utilities/Reflection/A.php | 10 +- tests/Utilities/Reflection/C.php | 10 +- tests/Utilities/ReflectionTest.php | 994 +-- tests/Utilities/RegexTest.php | 4169 +++++------ tests/Utilities/RepositoryTest.php | 1632 ++-- tests/Utilities/UriTest.php | 530 +- tests/Utilities/XmlTest.php | 6 +- tests/ValueObject/AddressTest.php | 38 +- tests/ValueObject/BankAccountTest.php | 6 +- tests/ValueObject/CompanyTest.php | 18 +- tests/ValueObject/HumanTest.php | 127 +- tests/ValueObject/SizeTest.php | 1985 ++--- tests/ValueObject/TemplateTest.php | 414 +- tests/ValueObject/VersionTest.php | 280 +- 116 files changed, 19152 insertions(+), 19091 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index 242844f..d925f44 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -8,24 +8,23 @@ $finder = PhpCsFixer\Finder::create() ]) ->notPath([ 'tests/Resources/var/', - ]) -; + ]); return PhpCsFixer\Config::create() ->setRules([ - '@Symfony' => true, - '@PhpCsFixer' => true, - '@PHP71Migration' => true, - 'array_syntax' => ['syntax' => 'short'], - 'binary_operator_spaces' => [ + '@Symfony' => true, + '@PhpCsFixer' => true, + '@PHP71Migration' => true, + 'array_syntax' => ['syntax' => 'short'], + 'binary_operator_spaces' => [ 'align_double_arrow' => true, ], - 'blank_line_before_return' => false, - 'cast_spaces' => false, - 'concat_space' => [ + 'blank_line_before_return' => false, + 'cast_spaces' => false, + 'concat_space' => [ 'spacing' => 'one', ], - 'ordered_class_elements' => [ + 'ordered_class_elements' => [ 'order' => [ 'use_trait', 'constant_public', @@ -43,11 +42,11 @@ return PhpCsFixer\Config::create() ], ], 'phpdoc_add_missing_param_annotation' => true, - 'phpdoc_align' => false, - 'phpdoc_order' => true, - 'phpdoc_separation' => false, - 'phpdoc_summary' => false, - 'trim_array_spaces' => false, + 'phpdoc_align' => false, + 'phpdoc_order' => true, + 'phpdoc_separation' => false, + 'phpdoc_summary' => false, + 'trim_array_spaces' => false, ]) ->setFinder($finder) ; diff --git a/CHANGELOG.md b/CHANGELOG.md index 009e565..d04411f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Common and useful classes, methods, exceptions etc. +# 1.1.8 + +1. + # 1.1.7 1. [Arrays] Allow to define a key of next level elements in a function that returns elements from given level @@ -32,8 +36,8 @@ Common and useful classes, methods, exceptions etc. # 1.1.1 -1. [BaseCollection] Treat the `null` index as "no index" only while adding new element, iow. do not treat empty -string as "no index" behaviour. +1. [BaseCollection] Treat the `null` index as "no index" only while adding new element, iow. do not treat empty string + as "no index" behaviour. 2. [Miscellaneous] [Regex] Use simpler & stronger pattern to match name of file 3. Do not install `hirak/prestissimo` package while running Travis CI (incompatible with your PHP version, PHP extensions and Composer version) @@ -41,9 +45,9 @@ string as "no index" behaviour. # 1.1.0 -1. Rename Meritoo\Common\Collection\Collection class to Meritoo\Common\Collection\BaseCollection. -Add BaseCollection::isValidType() method to validate type of element before add it to collection. -Add BaseCollection ::prepareElements() method to allow preparation of elements in custom way. +1. Rename Meritoo\Common\Collection\Collection class to Meritoo\Common\Collection\BaseCollection. Add BaseCollection:: + isValidType() method to validate type of element before add it to collection. Add BaseCollection ::prepareElements() + method to allow preparation of elements in custom way. # 1.0.6 @@ -67,8 +71,8 @@ Add BaseCollection ::prepareElements() method to allow preparation of elements i # 1.0.3 1. Travis CI > run many tasks using Phing > update configuration -2. Template with placeholders > verification of placeholders without values > make stronger and point out which are -missing +2. Template with placeholders > verification of placeholders without values > make stronger and point out which are + missing 3. Reflection > getPropertyValue() method > look for the property in parent classes # 1.0.2 @@ -82,13 +86,13 @@ missing 7. PHPUnit > execute tests in random order 8. Implement [Psalm](https://github.com/vimeo/psalm) 9. Infection (Mutation Testing Framework) > fix bugs while running (generate proper code coverage, bugs while running -tests randomly) + tests randomly) 10. Phing > php-coveralls > add task # 1.0.1 -1. Regex > make compatible with PHP 7.3 Tests > Regex > fix "preg_match(): Compilation failed: invalid range in -character class at offset 4" bug +1. Regex > make compatible with PHP 7.3 Tests > Regex > fix "preg_match(): Compilation failed: invalid range in + character class at offset 4" bug 2. Collection/storage of templates 3. Template with placeholders that may be filled by real data 4. RenderableInterface > something that may be rendered @@ -135,7 +139,8 @@ character class at offset 4" bug 1. Tests > refactoring & minor improvements 2. Utilities > CssSelector > useful methods related to CSS selectors -3. Utilities > Bootstrap4CssSelector > useful methods related to CSS selectors and the Bootstrap4 (front-end component library) +3. Utilities > Bootstrap4CssSelector > useful methods related to CSS selectors and the Bootstrap4 (front-end component + library) # 0.1.2 @@ -174,5 +179,6 @@ character class at offset 4" bug 4. StyleCI & PHP Coding Standards Fixer: update configuration 5. Documentation > Docker > add paragraph for PHP Coding Standards Fixer 6. Coding standard > fix automatically -7. StyleCI configuration > fix bug "The provided fixer 'binary_operator_spaces' cannot be enabled again because it was already enabled" +7. StyleCI configuration > fix bug "The provided fixer 'binary_operator_spaces' cannot be enabled again because it was + already enabled" 8. StyleCI > disable & remove diff --git a/README.md b/README.md index 1155ac4..466a93e 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,9 @@ composer require meritoo/common-library 2. [Collection of elements](docs/Collection/BaseCollection.md) 3. [Exceptions](docs/Static-methods.md) 4. [Static methods](docs/Static-methods.md) - 1. [Arrays](docs/Static-methods/Arrays.md) - 2. [Regex](docs/Static-methods/Regex.md) - 3. [Uri](docs/Static-methods/Uri.md) + 1. [Arrays](docs/Static-methods/Arrays.md) + 2. [Regex](docs/Static-methods/Regex.md) + 3. [Uri](docs/Static-methods/Uri.md) 5. [Value Objects](docs/Value-Objects.md) # Development diff --git a/build.xml b/build.xml index 594cf4b..5275a88 100644 --- a/build.xml +++ b/build.xml @@ -3,12 +3,12 @@ - + - + - + @@ -20,11 +20,11 @@ - + - + diff --git a/docs/Base-test-case.md b/docs/Base-test-case.md index 05b7ce3..87e2a04 100644 --- a/docs/Base-test-case.md +++ b/docs/Base-test-case.md @@ -10,7 +10,7 @@ Located here: `Meritoo\Common\Test\Base\BaseTestCase`. 1. Just extend the `BaseTestCase` class or implement `Meritoo\Common\Traits\Test\Base\BaseTestCaseTrait` trait. 2. Use one of available data providers, e.g. `@dataProvider provideEmptyValue`, or asserts, -e.g. `static::assertMethodVisibility($method, $visibilityType);` + e.g. `static::assertMethodVisibility($method, $visibilityType);` ##### Examples @@ -55,9 +55,9 @@ class MimeTypesTest extends BaseTestCase 3. [Templates](Collection/Templates.md) 4. [Exceptions](Exceptions.md) 5. [Static methods](Static-methods.md) - 1. [Arrays](Static-methods/Arrays.md) - 2. [Regex](Static-methods/Regex.md) - 3. [Uri](Static-methods/Uri.md) + 1. [Arrays](Static-methods/Arrays.md) + 2. [Regex](Static-methods/Regex.md) + 3. [Uri](Static-methods/Uri.md) 6. [Value Objects](Value-Objects.md) [‹ Back to `Readme`](../README.md) diff --git a/docs/Collection/BaseCollection.md b/docs/Collection/BaseCollection.md index 63003b4..b31e6a9 100644 --- a/docs/Collection/BaseCollection.md +++ b/docs/Collection/BaseCollection.md @@ -10,8 +10,9 @@ Common and useful classes, methods, exceptions etc. ### Info -It's a set of some elements with the same type, e.g. objects. It's iterable and countable. Provides very useful -methods. Some of them: +It's a set of some elements with the same type, e.g. objects. It's iterable and countable. Provides very useful methods. +Some of them: + - `getFirst()` - returns the first element in the collection - `getLast()` - returns the last element in the collection - `isEmpty()` - returns information if collection is empty @@ -82,8 +83,8 @@ var_dump($simpleCollection->has('dolor')); // bool(true) 3. [Templates](Templates.md) 4. [Exceptions](../Exceptions.md) 5. [Static methods](../Static-methods.md) - 1. [Arrays](../Static-methods/Arrays.md) - 2. [Regex](../Static-methods/Regex.md) + 1. [Arrays](../Static-methods/Arrays.md) + 2. [Regex](../Static-methods/Regex.md) 6. [Value Objects](../Value-Objects.md) [‹ Back to `Readme`](../../README.md) diff --git a/docs/Collection/Templates.md b/docs/Collection/Templates.md index 276b3d2..48258f5 100644 --- a/docs/Collection/Templates.md +++ b/docs/Collection/Templates.md @@ -18,25 +18,26 @@ New instance can be created using: 1. Constructor: - ```php - new Templates([ - 'first' => new Template('First name: %first_name%'), - 'last' => new Template('Last name: %last_name%'), - ]); - ``` + ```php + new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), + ]); + ``` 2. Static method `fromArray(array $templates)` - creates and returns the collection from given array - ```php - Templates::fromArray([ - 'first' => 'First name: %first_name%', - 'last' => 'Last name: %last_name%', - ]); - ``` + ```php + Templates::fromArray([ + 'first' => 'First name: %first_name%', + 'last' => 'Last name: %last_name%', + ]); + ``` ##### Methods -Has all methods of parent class `Meritoo\Common\Collection\Collection` + `findTemplate(string $index)` method that finds and returns template with given index. +Has all methods of parent class `Meritoo\Common\Collection\Collection` + `findTemplate(string $index)` method that finds +and returns template with given index. Example of usage: @@ -49,7 +50,8 @@ $templates = new Templates([ $template = $templates->findTemplate('first'); // new Template('First name: %first_name%') ``` -Throws an `Meritoo\Common\Exception\ValueObject\Template\TemplateNotFoundException` exception if template with given index was not found. +Throws an `Meritoo\Common\Exception\ValueObject\Template\TemplateNotFoundException` exception if template with given +index was not found. # More @@ -58,8 +60,8 @@ Throws an `Meritoo\Common\Exception\ValueObject\Template\TemplateNotFoundExcepti 3. [**Templates**](Templates.md) 4. [Exceptions](../Exceptions.md) 5. [Static methods](../Static-methods.md) - 1. [Arrays](../Static-methods/Arrays.md) - 2. [Regex](../Static-methods/Regex.md) + 1. [Arrays](../Static-methods/Arrays.md) + 2. [Regex](../Static-methods/Regex.md) 6. [Value Objects](../Value-Objects.md) [‹ Back to `Readme`](../../README.md) diff --git a/docs/Development.md b/docs/Development.md index e2fce80..589a44c 100644 --- a/docs/Development.md +++ b/docs/Development.md @@ -17,9 +17,9 @@ Development-related information 2. Rebuild project by running command (installs packages, prepares required directories and runs tests): - ```bash - docker-compose exec php phing - ``` + ```bash + docker-compose exec php phing + ``` > [What is Docker?](https://www.docker.com/what-docker) @@ -128,6 +128,7 @@ root@18f2f0cfaa5d:/var/www/application# XDEBUG_MODE=coverage phing -f phing/test ##### Terminal Example of output: + ```bash 125 mutations were generated: 105 mutants were killed diff --git a/docs/Exceptions.md b/docs/Exceptions.md index 1c70d23..ccbb022 100644 --- a/docs/Exceptions.md +++ b/docs/Exceptions.md @@ -6,7 +6,8 @@ Common and useful classes, methods, exceptions etc. ### Create instance of exception -This package contains a lot of exceptions. Each of them contains static method `create()` with proper arguments that is used to create instance of the exception. Example: +This package contains a lot of exceptions. Each of them contains static method `create()` with proper arguments that is +used to create instance of the exception. Example: ```php use Meritoo\Common\Exception\Bundle\IncorrectBundleNameException; @@ -17,11 +18,14 @@ throw IncorrectBundleNameException::create('RisusIpsum'); ##### Short description -It's a `Meritoo\Common\Exception\Base\UnknownTypeException` class. Related to `Meritoo\Common\Type\Base\BaseType` class that represents type of something, e.g. type of button, order. +It's a `Meritoo\Common\Exception\Base\UnknownTypeException` class. Related to `Meritoo\Common\Type\Base\BaseType` class +that represents type of something, e.g. type of button, order. ##### Usage -You can extend `Meritoo\Common\Exception\Base\UnknownTypeException` class and create your own static method, e.g. `createException()`, which will be used create instance of the exception. Inside the `createException()` method you can call `parent::create()` method. +You can extend `Meritoo\Common\Exception\Base\UnknownTypeException` class and create your own static method, +e.g. `createException()`, which will be used create instance of the exception. Inside the `createException()` method you +can call `parent::create()` method. ##### Example @@ -58,9 +62,9 @@ class UnknownSimpleTypeException extends UnknownTypeException 3. [Templates](Collection/Templates.md) 4. [**Exceptions**](Exceptions.md) 5. [Static methods](Static-methods.md) - 1. [Arrays](Static-methods/Arrays.md) - 2. [Regex](Static-methods/Regex.md) - 3. [Uri](Static-methods/Uri.md) + 1. [Arrays](Static-methods/Arrays.md) + 2. [Regex](Static-methods/Regex.md) + 3. [Uri](Static-methods/Uri.md) 6. [Value Objects](Value-Objects.md) [‹ Back to `Readme`](../README.md) diff --git a/docs/Static-methods.md b/docs/Static-methods.md index 9cf5f65..19c8fff 100644 --- a/docs/Static-methods.md +++ b/docs/Static-methods.md @@ -4,7 +4,8 @@ Common and useful classes, methods, exceptions etc. # Static methods -This package contains a lot of class with static methods, so usage is not so complicated. Just run the static method who would you like to use. Example: +This package contains a lot of class with static methods, so usage is not so complicated. Just run the static method who +would you like to use. Example: ```php use Meritoo\Common\Utilities\Arrays; @@ -20,9 +21,9 @@ var_dump($firstElement); // string(5) "lorem" 3. [Templates](Collection/Templates.md) 4. [Exceptions](Exceptions.md) 5. [**Static methods**](Static-methods.md) - 1. [Arrays](Static-methods/Arrays.md) - 2. [Regex](Static-methods/Regex.md) - 3. [Uri](Static-methods/Uri.md) + 1. [Arrays](Static-methods/Arrays.md) + 2. [Regex](Static-methods/Regex.md) + 3. [Uri](Static-methods/Uri.md) 6. [Value Objects](Value-Objects.md) [‹ Back to `Readme`](../README.md) diff --git a/docs/Static-methods/Arrays.md b/docs/Static-methods/Arrays.md index c50cd16..ade1780 100644 --- a/docs/Static-methods/Arrays.md +++ b/docs/Static-methods/Arrays.md @@ -21,16 +21,18 @@ File: `src/Utilities/Arrays.php` 1) - - array: `[]` (an empty array) - - result: `false` +- array: `[]` (an empty array) +- result: `false` 2) - - array: `["", -1]` - - result: `false` + +- array: `["", -1]` +- result: `false` 3) - - array: `["", null, ""]` - - result: `true` + +- array: `["", null, ""]` +- result: `true` ### getNonEmptyValues(array $values) @@ -44,18 +46,18 @@ File: `src/Utilities/Arrays.php` 1) - - values: `[]` (no values) - - result: `[]` (an empty array) +- values: `[]` (no values) +- result: `[]` (an empty array) 2) - - values: `[null, ""]` (all empty values) - - result: `[]` (an empty array) +- values: `[null, ""]` (all empty values) +- result: `[]` (an empty array) 3) - - values: `["test 1", "", 123, null, 0]` - - result: `["test 1", 123, 0]` +- values: `["test 1", "", 123, null, 0]` +- result: `["test 1", 123, 0]` ### getNonEmptyValuesAsString(array $values, $separator = ', ') @@ -70,27 +72,27 @@ File: `src/Utilities/Arrays.php` 1) - - values: `[]` (no values) - - separator: default or any other string - - result: `""` (an empty string) +- values: `[]` (no values) +- separator: default or any other string +- result: `""` (an empty string) 2) - - values: `[null, ""]` (all empty values) - - separator: default or any other string - - result: `""` (an empty string) +- values: `[null, ""]` (all empty values) +- separator: default or any other string +- result: `""` (an empty string) 3) - - values: `["test 1", "", 123, null, 0]` - - separator: `", "` (default) - - result: `"test 1, 123, 0"` +- values: `["test 1", "", 123, null, 0]` +- separator: `", "` (default) +- result: `"test 1, 123, 0"` 4) - - values: `["test 1", "", 123, null, 0]` - - separator: `" | "` - - result: `"test 1 | 123 | 0"` +- values: `["test 1", "", 123, null, 0]` +- separator: `" | "` +- result: `"test 1 | 123 | 0"` # More @@ -99,9 +101,9 @@ File: `src/Utilities/Arrays.php` 3. [Templates](../Collection/Templates.md) 4. [Exceptions](../Exceptions.md) 5. [Static methods](../Static-methods.md) - 1. [**Arrays**](Arrays.md) - 2. [Regex](Regex.md) - 3. [Uri](Uri.md) + 1. [**Arrays**](Arrays.md) + 2. [Regex](Regex.md) + 3. [Uri](Uri.md) 6. [Value Objects](../Value-Objects.md) [‹ Back to `Readme`](../../README.md) diff --git a/docs/Static-methods/Regex.md b/docs/Static-methods/Regex.md index 6c0d0c4..7e5e697 100644 --- a/docs/Static-methods/Regex.md +++ b/docs/Static-methods/Regex.md @@ -21,18 +21,18 @@ File: `src/Utilities/Regex.php` 1) - - value: non-scalar or `null` - - result: `false` +- value: non-scalar or `null` +- result: `false` 2) - - value: `""` (an empty string) - - result: `""` (an empty string) +- value: `""` (an empty string) +- result: `""` (an empty string) 3) - - value: `"Lorem ipsum. Dolor sit 12.34 amet."` - - result: `"lorem-ipsum-dolor-sit-1234-amet"` +- value: `"Lorem ipsum. Dolor sit 12.34 amet."` +- result: `"lorem-ipsum-dolor-sit-1234-amet"` ### clearBeginningSlash(string): string @@ -46,18 +46,18 @@ File: `src/Utilities/Regex.php` 1) - - string: `"lorem ipsum"` - - result: `"lorem ipsum"` +- string: `"lorem ipsum"` +- result: `"lorem ipsum"` 2) - - string: `"/lorem ipsum"` - - result: `"lorem ipsum"` +- string: `"/lorem ipsum"` +- result: `"lorem ipsum"` 3) - - string: `"/ lorem 123 ipsum"` - - result: `" lorem 123 ipsum"` +- string: `"/ lorem 123 ipsum"` +- result: `" lorem 123 ipsum"` ### clearEndingSlash(string): string @@ -71,18 +71,18 @@ File: `src/Utilities/Regex.php` 1) - - string: `"lorem ipsum"` - - result: `"lorem ipsum"` +- string: `"lorem ipsum"` +- result: `"lorem ipsum"` 2) - - string: `"lorem ipsum/"` - - result: `"lorem ipsum"` +- string: `"lorem ipsum/"` +- result: `"lorem ipsum"` 3) - - string: `"lorem 123 ipsum /"` - - result: `"lorem 123 ipsum "` +- string: `"lorem 123 ipsum /"` +- result: `"lorem 123 ipsum "` # More @@ -91,9 +91,9 @@ File: `src/Utilities/Regex.php` 3. [Templates](../Collection/Templates.md) 4. [Exceptions](../Exceptions.md) 5. [Static methods](../Static-methods.md) - 1. [Arrays](../Static-methods/Arrays.md) - 2. [**Regex**](Regex.md) - 3. [Uri](Uri.md) + 1. [Arrays](../Static-methods/Arrays.md) + 2. [**Regex**](Regex.md) + 3. [Uri](Uri.md) 6. [Value Objects](../Value-Objects.md) [‹ Back to `Readme`](../../README.md) diff --git a/docs/Static-methods/Uri.md b/docs/Static-methods/Uri.md index 0d64259..33cd80c 100644 --- a/docs/Static-methods/Uri.md +++ b/docs/Static-methods/Uri.md @@ -22,15 +22,15 @@ File: `src/Utilities/Uri.php` 1) - - rootUrl: `"http://my.example"` - - urlParts: `""` (an empty string) - - result: `"http://my.example"` +- rootUrl: `"http://my.example"` +- urlParts: `""` (an empty string) +- result: `"http://my.example"` 2) - - rootUrl: `"http://my.example"` - - urlParts: `"/test", "/123"` - - result: `"http://my.example/test/123"` +- rootUrl: `"http://my.example"` +- urlParts: `"/test", "/123"` +- result: `"http://my.example/test/123"` # More @@ -39,9 +39,9 @@ File: `src/Utilities/Uri.php` 3. [Templates](../Collection/Templates.md) 4. [Exceptions](../Exceptions.md) 5. [Static methods](../Static-methods.md) - 1. [Arrays](Arrays.md) - 2. [Regex](Regex.md) - 3. [**Uri**](Uri.md) + 1. [Arrays](Arrays.md) + 2. [Regex](Regex.md) + 3. [**Uri**](Uri.md) 6. [Value Objects](../Value-Objects.md) [‹ Back to `Readme`](../../README.md) diff --git a/docs/Value-Objects.md b/docs/Value-Objects.md index 47777f2..77a47dc 100644 --- a/docs/Value-Objects.md +++ b/docs/Value-Objects.md @@ -15,6 +15,7 @@ Located in `Meritoo\Common\ValueObject` namespace and in `src/ValueObject/` dire ##### Info Represents address of company, institution, user etc. Contains properties: + 1. `$street` - the street 2. `$buildingNumber` - the number of building 3. `$flatNumber` - the number of flat @@ -66,6 +67,7 @@ $asString = (string)$address; // "4th Avenue 10/200, 00123, New York" ##### Info Represents bank account. Contains properties: + 1. `$bankName` - name of bank 2. `$accountNumber` - number of bank's account @@ -101,6 +103,7 @@ $asString = (string)$bank; // "Bank of America, 1234567890" ##### Info Represents a company. Contains properties: + 1. `$name` - name of company 2. `$address` - address of company 3. `$bankAccount` - bank account of company @@ -145,7 +148,9 @@ $asString = (string)$company; // "Test 1, 4th Avenue 10/200, 00123, New York, Ba ##### Info -Represents human. Based on `\Meritoo\Common\Traits\ValueObject\HumanTrait` trait. Contains properties same as `HumanTrait` trait: +Represents human. Based on `\Meritoo\Common\Traits\ValueObject\HumanTrait` trait. Contains properties same +as `HumanTrait` trait: + 1. `$firstName` - first name 2. `$lastName` - last name 3. `$email` - email address @@ -186,6 +191,7 @@ $asString2 = (string)$human2; // "John Scott " ##### Info Size, e.g. of image. Contains properties: + 1. `width` - the width 2. `height` - the height 3. `unit` - unit used when width or height should be returned with unit, default: `"px"` @@ -218,13 +224,15 @@ New instance can be created using static methods: ##### Methods Has: + - getters and setters for `width` and `height` properties. - setter for `separator` property - `toString()` and `toArray()` methods that returns size represented as string and array ##### Conversion to string (using `__toString()` method) -Instance of `Size` may be represented as string that contains width and height separated by separator (default: `" x "`). +Instance of `Size` may be represented as string that contains width and height separated by separator (default: `" x "`) +. Example: @@ -248,6 +256,7 @@ $asString2 = (string)$size; // "200X100" ##### Info Template with placeholders that may be filled by real data. Contains properties: + 1. `$content` - raw string with placeholders (content of the template) ##### New instance @@ -258,7 +267,9 @@ New instance can be created using constructor: new Template('First name: %first_name%'); ``` -Each placeholder should be wrapped by `%` character, e.g. `%first_name%`. If content of template is an empty string or does not contain 1 placeholder at least, an `Meritoo\Common\Exception\ValueObject\Template\InvalidContentException` exception will be thrown. +Each placeholder should be wrapped by `%` character, e.g. `%first_name%`. If content of template is an empty string or +does not contain 1 placeholder at least, an `Meritoo\Common\Exception\ValueObject\Template\InvalidContentException` +exception will be thrown. Examples of invalid content of template: @@ -270,7 +281,8 @@ new Template('This is %test'); // With starting tag only (invalid placeholder) ##### Methods -Has 1 public method: `fill(array $values)`. Returns content of the template filled with given values (by replacing placeholders with their proper values). +Has 1 public method: `fill(array $values)`. Returns content of the template filled with given values (by replacing +placeholders with their proper values). Example of usage: @@ -282,7 +294,8 @@ $result = $template->fill([ ]); // "My name is Jane and I am photographer" ``` -Throws an `Meritoo\Common\Exception\ValueObject\Template\NotEnoughValuesException` exception if there is not enough values (iow. more placeholders than values). +Throws an `Meritoo\Common\Exception\ValueObject\Template\NotEnoughValuesException` exception if there is not enough +values (iow. more placeholders than values). ### Version @@ -293,6 +306,7 @@ Throws an `Meritoo\Common\Exception\ValueObject\Template\NotEnoughValuesExceptio ##### Info Represents version of software. Contains properties: + 1. `$majorPart` - the "major" part of version 2. `$minorPart` - the "minor" part of version 3. `$patchPart` - the "patch" part of version @@ -303,22 +317,22 @@ New instance can be created using: 1. Constructor: - ```php - new Version(1, 0, 2); - ``` + ```php + new Version(1, 0, 2); + ``` 2. Static methods: - 1. `fromArray(array $version)` - creates new instance using given version as array + 1. `fromArray(array $version)` - creates new instance using given version as array - ```php - Version::fromArray([1, 0, 2]); - ``` + ```php + Version::fromArray([1, 0, 2]); + ``` - 2. `fromString(string $version)` - creates new instance using given version as string: + 2. `fromString(string $version)` - creates new instance using given version as string: - ```php - Version::fromString('1.0.2'); - ``` + ```php + Version::fromString('1.0.2'); + ``` ##### Methods @@ -326,7 +340,8 @@ Has getters for each property: `getMajorPart()`, `getMinorPart()`, `getPatchPart ##### Conversion to string (using `__toString()` method) -Instance of `Version` may be represented as string that contains all properties separated by `.` (`$majorPart`.`$minorPart`.`$patchPart`). +Instance of `Version` may be represented as string that contains all properties separated by `.` (`$majorPart` +.`$minorPart`.`$patchPart`). Example: @@ -342,9 +357,9 @@ $asString = (string)$version; // "1.0.2" 3. [Templates](Collection/Templates.md) 4. [Exceptions](Exceptions.md) 5. [Static methods](Static-methods.md) - 1. [Arrays](Static-methods/Arrays.md) - 2. [Regex](Static-methods/Regex.md) - 3. [Uri](Static-methods/Uri.md) + 1. [Arrays](Static-methods/Arrays.md) + 2. [Regex](Static-methods/Regex.md) + 3. [Uri](Static-methods/Uri.md) 6. [**Value Objects**](Value-Objects.md) [‹ Back to `Readme`](../README.md) diff --git a/phing/app.xml b/phing/app.xml index 7a36756..68c33cf 100644 --- a/phing/app.xml +++ b/phing/app.xml @@ -3,17 +3,17 @@ - + - + - + - + - + - + - + - + @@ -50,41 +50,41 @@ - + - - - + + + - + - + - + - - + + - + - + @@ -93,20 +93,20 @@ - + - - - + + + - + - + @@ -116,24 +116,24 @@ - - + + - + - + - - + + @@ -142,15 +142,15 @@ - - + + - + @@ -158,10 +158,10 @@ - + - + @@ -169,11 +169,11 @@ - + - - - + + + diff --git a/phing/tests.xml b/phing/tests.xml index cfb6b48..4005fde 100644 --- a/phing/tests.xml +++ b/phing/tests.xml @@ -1,30 +1,30 @@ - + - + - + - + - - - - - - + + + + + + - + @@ -37,7 +37,7 @@ - + @@ -57,67 +57,67 @@ - + - - + + - + - + - + - + - + - + - + - - - + + + - + - - - + + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a6964df..3e849fb 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -11,7 +11,7 @@ verbose="true" > - + @@ -30,9 +30,9 @@ - - - - + + + +
diff --git a/psalm.xml b/psalm.xml index aedffd7..c0db670 100644 --- a/psalm.xml +++ b/psalm.xml @@ -1,9 +1,9 @@ diff --git a/src/Collection/BaseCollection.php b/src/Collection/BaseCollection.php index f2539dc..f97c4fc 100644 --- a/src/Collection/BaseCollection.php +++ b/src/Collection/BaseCollection.php @@ -40,16 +40,6 @@ abstract class BaseCollection implements CollectionInterface $this->elements = $this->prepareElements($validated); } - /** - * Returns representation of object as array - * - * @return array - */ - public function toArray(): array - { - return $this->elements; - } - /** * Adds given element (at the end of collection) * @@ -97,45 +87,50 @@ abstract class BaseCollection implements CollectionInterface } } - /** - * Prepends given element (adds given element at the beginning of collection) - * - * @param mixed $element The element to prepend - */ - public function prepend($element): void + public function clear(): void { - array_unshift($this->elements, $element); + $this->elements = []; + } + + public function count(): int + { + return count($this->elements); } /** - * Removes given element + * Returns element with given index * - * @param mixed $element The element to remove - */ - public function remove($element): void - { - if (0 === $this->count()) { - return; - } - - foreach ($this->elements as $index => $existing) { - if ($element === $existing) { - unset($this->elements[$index]); - - break; - } - } - } - - /** - * Returns previous element for given element - * - * @param mixed $element The element to verify + * @param mixed $index Index / key of the element * @return null|mixed */ - public function getPrevious($element) + public function getByIndex($index) { - return Arrays::getPreviousElement($this->elements, $element); + return $this->elements[$index] ?? null; + } + + /** + * Returns the first element in the collection + * + * @return mixed + */ + public function getFirst() + { + return Arrays::getFirstElement($this->elements); + } + + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->elements); + } + + /** + * Returns the last element in the collection + * + * @return mixed + */ + public function getLast() + { + return Arrays::getLastElement($this->elements); } /** @@ -150,34 +145,27 @@ abstract class BaseCollection implements CollectionInterface } /** - * Returns the first element in the collection + * Returns previous element for given element * - * @return mixed - */ - public function getFirst() - { - return Arrays::getFirstElement($this->elements); - } - - /** - * Returns the last element in the collection - * - * @return mixed - */ - public function getLast() - { - return Arrays::getLastElement($this->elements); - } - - /** - * Returns element with given index - * - * @param mixed $index Index / key of the element + * @param mixed $element The element to verify * @return null|mixed */ - public function getByIndex($index) + public function getPrevious($element) { - return $this->elements[$index] ?? null; + return Arrays::getPreviousElement($this->elements, $element); + } + + /** + * Returns information if the collection has given element, iow. if given element exists in the collection + * + * @param mixed $element The element to verify + * @return bool + */ + public function has($element): bool + { + $index = Arrays::getIndexOf($this->elements, $element); + + return null !== $index && false !== $index; } /** @@ -212,24 +200,6 @@ abstract class BaseCollection implements CollectionInterface return end($this->elements) === $element; } - /** - * Returns information if the collection has given element, iow. if given element exists in the collection - * - * @param mixed $element The element to verify - * @return bool - */ - public function has($element): bool - { - $index = Arrays::getIndexOf($this->elements, $element); - - return null !== $index && false !== $index; - } - - public function clear(): void - { - $this->elements = []; - } - public function limit(int $max, int $offset = 0): CollectionInterface { $result = clone $this; @@ -260,11 +230,6 @@ abstract class BaseCollection implements CollectionInterface return $result; } - public function count(): int - { - return count($this->elements); - } - public function offsetExists($offset): bool { return $this->exists($offset); @@ -291,11 +256,54 @@ abstract class BaseCollection implements CollectionInterface } } - public function getIterator(): ArrayIterator + /** + * Prepends given element (adds given element at the beginning of collection) + * + * @param mixed $element The element to prepend + */ + public function prepend($element): void { - return new ArrayIterator($this->elements); + array_unshift($this->elements, $element); } + /** + * Removes given element + * + * @param mixed $element The element to remove + */ + public function remove($element): void + { + if (0 === $this->count()) { + return; + } + + foreach ($this->elements as $index => $existing) { + if ($element === $existing) { + unset($this->elements[$index]); + + break; + } + } + } + + /** + * Returns representation of object as array + * + * @return array + */ + public function toArray(): array + { + return $this->elements; + } + + /** + * Returns information if given element has valid type + * + * @param mixed $element Element of collection + * @return bool + */ + abstract protected function isValidType($element): bool; + /** * Prepares elements to initialize the collection. * Feel free to override and prepare elements in your way. @@ -309,12 +317,15 @@ abstract class BaseCollection implements CollectionInterface } /** - * Returns information if given element has valid type + * Returns information if element with given index/key exists * - * @param mixed $element Element of collection + * @param int|string $index The index/key of element * @return bool */ - abstract protected function isValidType($element): bool; + private function exists($index): bool + { + return isset($this->elements[$index]) || array_key_exists($index, $this->elements); + } /** * Returns elements of collection with valid types @@ -340,15 +351,4 @@ abstract class BaseCollection implements CollectionInterface return $result; } - - /** - * Returns information if element with given index/key exists - * - * @param int|string $index The index/key of element - * @return bool - */ - private function exists($index): bool - { - return isset($this->elements[$index]) || array_key_exists($index, $this->elements); - } } diff --git a/src/Collection/Templates.php b/src/Collection/Templates.php index dbda2d0..6555228 100644 --- a/src/Collection/Templates.php +++ b/src/Collection/Templates.php @@ -25,8 +25,8 @@ class Templates extends BaseCollection * Finds and returns template with given index * * @param string $index Index that contains required template - * @throws TemplateNotFoundException * @return Template + * @throws TemplateNotFoundException */ public function findTemplate(string $index): Template { diff --git a/src/Contract/Collection/CollectionInterface.php b/src/Contract/Collection/CollectionInterface.php index 2c5988d..855a01c 100644 --- a/src/Contract/Collection/CollectionInterface.php +++ b/src/Contract/Collection/CollectionInterface.php @@ -22,25 +22,23 @@ use IteratorAggregate; */ interface CollectionInterface extends Countable, ArrayAccess, IteratorAggregate { - public function toArray(): array; - public function add($element, $index = null): void; public function addMultiple($elements, bool $useIndexes = false): void; - public function prepend($element): void; + public function clear(): void; - public function remove($element): void; - - public function getPrevious($element); - - public function getNext($element); + public function getByIndex($index); public function getFirst(); public function getLast(); - public function getByIndex($index); + public function getNext($element); + + public function getPrevious($element); + + public function has($element): bool; public function isEmpty(): bool; @@ -48,9 +46,11 @@ interface CollectionInterface extends Countable, ArrayAccess, IteratorAggregate public function isLast($element): bool; - public function has($element): bool; - - public function clear(): void; - public function limit(int $max, int $offset = 0): self; + + public function prepend($element): void; + + public function remove($element): void; + + public function toArray(): array; } diff --git a/src/Exception/Base/UnknownTypeException.php b/src/Exception/Base/UnknownTypeException.php index d42571b..7354524 100644 --- a/src/Exception/Base/UnknownTypeException.php +++ b/src/Exception/Base/UnknownTypeException.php @@ -31,7 +31,7 @@ abstract class UnknownTypeException extends Exception public static function create($unknownType, BaseType $typeInstance, string $typeName): UnknownTypeException { $template = 'The \'%s\' type of %s is unknown. Probably doesn\'t exist or there is a typo. You should use one' - . ' of these types: %s.'; + .' of these types: %s.'; $allTypes = $typeInstance->getAll(); $types = Arrays::values2string($allTypes, '', ', ') ?? '[types not found]'; diff --git a/src/Exception/Bundle/IncorrectBundleNameException.php b/src/Exception/Bundle/IncorrectBundleNameException.php index 2c34199..6e7506a 100644 --- a/src/Exception/Bundle/IncorrectBundleNameException.php +++ b/src/Exception/Bundle/IncorrectBundleNameException.php @@ -27,7 +27,7 @@ class IncorrectBundleNameException extends Exception public static function create($bundleName) { $template = 'Name of bundle \'%s\' is incorrect. It should start with big letter and end with "Bundle". Is' - . ' there everything ok?'; + .' there everything ok?'; $message = sprintf($template, $bundleName); diff --git a/src/Exception/File/EmptyFileException.php b/src/Exception/File/EmptyFileException.php index 4ff9441..fea0600 100644 --- a/src/Exception/File/EmptyFileException.php +++ b/src/Exception/File/EmptyFileException.php @@ -8,13 +8,15 @@ namespace Meritoo\Common\Exception\File; +use Exception; + /** * An exception used while file with given path is empty (has no content) * * @author Meritoo * @copyright Meritoo */ -class EmptyFileException extends \Exception +class EmptyFileException extends Exception { /** * Creates exception diff --git a/src/Exception/File/EmptyFilePathException.php b/src/Exception/File/EmptyFilePathException.php index f4386f7..51ca44d 100644 --- a/src/Exception/File/EmptyFilePathException.php +++ b/src/Exception/File/EmptyFilePathException.php @@ -8,13 +8,15 @@ namespace Meritoo\Common\Exception\File; +use Exception; + /** * An exception used while path of given file is empty * * @author Meritoo * @copyright Meritoo */ -class EmptyFilePathException extends \Exception +class EmptyFilePathException extends Exception { /** * Creates exception diff --git a/src/Exception/File/NotExistingFileException.php b/src/Exception/File/NotExistingFileException.php index c64a8f8..6ddc2aa 100644 --- a/src/Exception/File/NotExistingFileException.php +++ b/src/Exception/File/NotExistingFileException.php @@ -8,13 +8,15 @@ namespace Meritoo\Common\Exception\File; +use Exception; + /** * An exception used while file with given path does not exist * * @author Meritoo * @copyright Meritoo */ -class NotExistingFileException extends \Exception +class NotExistingFileException extends Exception { /** * Creates exception diff --git a/src/Exception/Reflection/MissingChildClassesException.php b/src/Exception/Reflection/MissingChildClassesException.php index 8a51e09..9a367b3 100644 --- a/src/Exception/Reflection/MissingChildClassesException.php +++ b/src/Exception/Reflection/MissingChildClassesException.php @@ -29,7 +29,7 @@ class MissingChildClassesException extends Exception public static function create($parentClass): MissingChildClassesException { $template = 'The \'%s\' class requires one child class at least who will extend her (maybe is an abstract' - . ' class), but the child classes are missing. Did you forget to extend this class?'; + .' class), but the child classes are missing. Did you forget to extend this class?'; $parentClassName = Reflection::getClassName($parentClass) ?? '[unknown class]'; $message = sprintf($template, $parentClassName); diff --git a/src/Exception/Reflection/NotExistingPropertyException.php b/src/Exception/Reflection/NotExistingPropertyException.php index 35723a4..c5b10ff 100644 --- a/src/Exception/Reflection/NotExistingPropertyException.php +++ b/src/Exception/Reflection/NotExistingPropertyException.php @@ -8,13 +8,15 @@ namespace Meritoo\Common\Exception\Reflection; +use Exception; + /** * An exception used while property does not exist in instance of class * * @author Meritoo * @copyright Meritoo */ -class NotExistingPropertyException extends \Exception +class NotExistingPropertyException extends Exception { /** * Creates exception diff --git a/src/Exception/Reflection/TooManyChildClassesException.php b/src/Exception/Reflection/TooManyChildClassesException.php index 19967dc..dea2970 100644 --- a/src/Exception/Reflection/TooManyChildClassesException.php +++ b/src/Exception/Reflection/TooManyChildClassesException.php @@ -30,7 +30,7 @@ class TooManyChildClassesException extends Exception public static function create($parentClass, array $childClasses): TooManyChildClassesException { $template = "The '%s' class requires one child class at most who will extend her, but more than one child" - . " class was found:\n- %s\n\nWhy did you create more than one classes that extend '%s' class?"; + ." class was found:\n- %s\n\nWhy did you create more than one classes that extend '%s' class?"; $parentClassName = Reflection::getClassName($parentClass) ?? '[unknown class]'; $message = sprintf($template, $parentClassName, implode("\n- ", $childClasses), $parentClassName); diff --git a/src/Exception/Regex/IncorrectColorHexLengthException.php b/src/Exception/Regex/IncorrectColorHexLengthException.php index 86af0a3..9dcca58 100644 --- a/src/Exception/Regex/IncorrectColorHexLengthException.php +++ b/src/Exception/Regex/IncorrectColorHexLengthException.php @@ -8,13 +8,15 @@ namespace Meritoo\Common\Exception\Regex; +use Exception; + /** * An exception used while length of given hexadecimal value of color is incorrect * * @author Meritoo * @copyright Meritoo */ -class IncorrectColorHexLengthException extends \Exception +class IncorrectColorHexLengthException extends Exception { /** * Creates exception @@ -25,7 +27,7 @@ class IncorrectColorHexLengthException extends \Exception public static function create($color) { $template = 'Length of hexadecimal value of color \'%s\' is incorrect. It\'s %d, but it should be 3 or 6.' - . ' Is there everything ok?'; + .' Is there everything ok?'; $message = sprintf($template, $color, strlen($color)); diff --git a/src/Exception/Regex/InvalidColorHexValueException.php b/src/Exception/Regex/InvalidColorHexValueException.php index 69b1682..1523be0 100644 --- a/src/Exception/Regex/InvalidColorHexValueException.php +++ b/src/Exception/Regex/InvalidColorHexValueException.php @@ -8,13 +8,15 @@ namespace Meritoo\Common\Exception\Regex; +use Exception; + /** * An exception used while given hexadecimal value of color is invalid * * @author Meritoo * @copyright Meritoo */ -class InvalidColorHexValueException extends \Exception +class InvalidColorHexValueException extends Exception { /** * Creates exception diff --git a/src/Exception/Regex/InvalidHtmlAttributesException.php b/src/Exception/Regex/InvalidHtmlAttributesException.php index cac3480..4504fd2 100644 --- a/src/Exception/Regex/InvalidHtmlAttributesException.php +++ b/src/Exception/Regex/InvalidHtmlAttributesException.php @@ -8,13 +8,15 @@ namespace Meritoo\Common\Exception\Regex; +use Exception; + /** * An exception used while html attributes are invalid * * @author Meritoo * @copyright Meritoo */ -class InvalidHtmlAttributesException extends \Exception +class InvalidHtmlAttributesException extends Exception { /** * Creates exception diff --git a/src/Exception/Regex/InvalidUrlException.php b/src/Exception/Regex/InvalidUrlException.php index 080fcf7..4d47d1d 100644 --- a/src/Exception/Regex/InvalidUrlException.php +++ b/src/Exception/Regex/InvalidUrlException.php @@ -8,13 +8,15 @@ namespace Meritoo\Common\Exception\Regex; +use Exception; + /** * An exception used while url is invalid * * @author Meritoo * @copyright Meritoo */ -class InvalidUrlException extends \Exception +class InvalidUrlException extends Exception { /** * Creates exception diff --git a/src/Exception/ValueObject/InvalidSizeDimensionsException.php b/src/Exception/ValueObject/InvalidSizeDimensionsException.php index 8f922e1..15f8838 100644 --- a/src/Exception/ValueObject/InvalidSizeDimensionsException.php +++ b/src/Exception/ValueObject/InvalidSizeDimensionsException.php @@ -8,13 +8,15 @@ namespace Meritoo\Common\Exception\ValueObject; +use Exception; + /** * An exception used while dimensions of size, passed to the instance of Size class, are invalid * * @author Meritoo * @copyright Meritoo */ -class InvalidSizeDimensionsException extends \Exception +class InvalidSizeDimensionsException extends Exception { /** * Creates exception diff --git a/src/Exception/ValueObject/Template/MissingPlaceholdersInValuesException.php b/src/Exception/ValueObject/Template/MissingPlaceholdersInValuesException.php index 3974583..af93d18 100644 --- a/src/Exception/ValueObject/Template/MissingPlaceholdersInValuesException.php +++ b/src/Exception/ValueObject/Template/MissingPlaceholdersInValuesException.php @@ -28,7 +28,7 @@ class MissingPlaceholdersInValuesException extends Exception public static function create(string $content, array $missingPlaceholders): MissingPlaceholdersInValuesException { $template = 'Cannot fill template \'%s\', because of missing values for placeholder(s): %s. Did you provide all' - . ' required values?'; + .' required values?'; $message = sprintf($template, $content, implode(', ', $missingPlaceholders)); return new static($message); diff --git a/src/Traits/CssSelector/FormCssSelector.php b/src/Traits/CssSelector/FormCssSelector.php index 964ce71..9766814 100644 --- a/src/Traits/CssSelector/FormCssSelector.php +++ b/src/Traits/CssSelector/FormCssSelector.php @@ -16,6 +16,24 @@ namespace Meritoo\Common\Traits\CssSelector; */ trait FormCssSelector { + /** + * Returns selector of field-set using index/position of the field-set + * + * @param string $formName Name of form (value of the "name" attribute) + * @param int $fieldSetIndex Index/Position of the field-set + * @return string + */ + public static function getFieldSetByIndexSelector($formName, $fieldSetIndex) + { + $formSelector = static::getFormByNameSelector($formName); + + if (empty($formSelector) || 0 > $fieldSetIndex) { + return ''; + } + + return sprintf('%s fieldset:nth-of-type(%d)', $formSelector, $fieldSetIndex); + } + /** * Returns selector of form based on its name * @@ -33,25 +51,6 @@ trait FormCssSelector return sprintf('form[name="%s"]', $formName); } - /** - * Returns selector of the input field based on its name - * - * @param string $formName Name of form (value of the "name" attribute) - * @param string $fieldName Name of field (value of the "name" attribute) - * @return string - */ - public static function getInputByNameSelector($formName, $fieldName) - { - $formSelector = static::getFormByNameSelector($formName); - $fieldName = trim($fieldName); - - if (empty($formSelector) || empty($fieldName)) { - return ''; - } - - return sprintf('%s input[name="%s"]', $formSelector, $fieldName); - } - /** * Returns selector of the input field based on its ID * @@ -71,6 +70,25 @@ trait FormCssSelector return sprintf('%s input#%s', $formSelector, $fieldId); } + /** + * Returns selector of the input field based on its name + * + * @param string $formName Name of form (value of the "name" attribute) + * @param string $fieldName Name of field (value of the "name" attribute) + * @return string + */ + public static function getInputByNameSelector($formName, $fieldName) + { + $formSelector = static::getFormByNameSelector($formName); + $fieldName = trim($fieldName); + + if (empty($formSelector) || empty($fieldName)) { + return ''; + } + + return sprintf('%s input[name="%s"]', $formSelector, $fieldName); + } + /** * Returns selector of label * @@ -89,22 +107,4 @@ trait FormCssSelector return sprintf('%s label[for="%s"]', $formSelector, $fieldId); } - - /** - * Returns selector of field-set using index/position of the field-set - * - * @param string $formName Name of form (value of the "name" attribute) - * @param int $fieldSetIndex Index/Position of the field-set - * @return string - */ - public static function getFieldSetByIndexSelector($formName, $fieldSetIndex) - { - $formSelector = static::getFormByNameSelector($formName); - - if (empty($formSelector) || 0 > $fieldSetIndex) { - return ''; - } - - return sprintf('%s fieldset:nth-of-type(%d)', $formSelector, $fieldSetIndex); - } } diff --git a/src/Traits/Test/Base/BaseTestCaseTrait.php b/src/Traits/Test/Base/BaseTestCaseTrait.php index bdf852b..6ed450b 100644 --- a/src/Traits/Test/Base/BaseTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTestCaseTrait.php @@ -36,35 +36,6 @@ trait BaseTestCaseTrait */ private static $testsDataDirPath = 'data/tests'; - /** - * Provides an empty value - * - * @return Generator - */ - public function provideEmptyValue(): ?Generator - { - yield['']; - yield[' ']; - yield[null]; - yield[0]; - yield[false]; - yield[[]]; - } - - /** - * Provides an empty scalar value - * - * @return Generator - */ - public function provideEmptyScalarValue(): ?Generator - { - yield['']; - yield[' ']; - yield[null]; - yield[0]; - yield[false]; - } - /** * Provides boolean value * @@ -72,8 +43,8 @@ trait BaseTestCaseTrait */ public function provideBooleanValue(): ?Generator { - yield[false]; - yield[true]; + yield [false]; + yield [true]; } /** @@ -83,10 +54,10 @@ trait BaseTestCaseTrait */ public function provideDateTimeInstance(): ?Generator { - yield[new DateTime()]; - yield[new DateTime('yesterday')]; - yield[new DateTime('now')]; - yield[new DateTime('tomorrow')]; + yield [new DateTime()]; + yield [new DateTime('yesterday')]; + yield [new DateTime('now')]; + yield [new DateTime('tomorrow')]; } /** @@ -96,29 +67,46 @@ trait BaseTestCaseTrait */ public function provideDateTimeRelativeFormat(): ?Generator { - yield['now']; - yield['yesterday']; - yield['tomorrow']; - yield['back of 10']; - yield['front of 10']; - yield['last day of February']; - yield['first day of next month']; - yield['last day of previous month']; - yield['last day of next month']; - yield['Y-m-d']; - yield['Y-m-d 10:00']; + yield ['now']; + yield ['yesterday']; + yield ['tomorrow']; + yield ['back of 10']; + yield ['front of 10']; + yield ['last day of February']; + yield ['first day of next month']; + yield ['last day of previous month']; + yield ['last day of next month']; + yield ['Y-m-d']; + yield ['Y-m-d 10:00']; } /** - * Provides path of not existing file, e.g. "lorem/ipsum.jpg" + * Provides an empty scalar value * * @return Generator */ - public function provideNotExistingFilePath(): ?Generator + public function provideEmptyScalarValue(): ?Generator { - yield['lets-test.doc']; - yield['lorem/ipsum.jpg']; - yield['surprise/me/one/more/time.txt']; + yield ['']; + yield [' ']; + yield [null]; + yield [0]; + yield [false]; + } + + /** + * Provides an empty value + * + * @return Generator + */ + public function provideEmptyValue(): ?Generator + { + yield ['']; + yield [' ']; + yield [null]; + yield [0]; + yield [false]; + yield [[]]; } /** @@ -128,81 +116,21 @@ trait BaseTestCaseTrait */ public function provideNonScalarValue(): ?Generator { - yield[[]]; - yield[null]; - yield[new stdClass()]; + yield [[]]; + yield [null]; + yield [new stdClass()]; } /** - * Returns path of file used by tests. - * It should be placed in /data/tests directory of this project. + * Provides path of not existing file, e.g. "lorem/ipsum.jpg" * - * @param string $fileName Name of file - * @param string $directoryPath (optional) Path of directory containing the file - * @return string + * @return Generator */ - protected function getFilePathForTesting(string $fileName, string $directoryPath = ''): string + public function provideNotExistingFilePath(): ?Generator { - $rootPath = Miscellaneous::getProjectRootPath(); - - $paths = [ - $rootPath, - self::$testsDataDirPath, - $directoryPath, - $fileName, - ]; - - return Miscellaneous::concatenatePaths($paths); - } - - /** - * Verifies visibility of method - * - * @param ReflectionMethod $method Name of method or just the method to verify - * @param string $visibilityType Expected visibility of verified method. One of OopVisibilityType - * class constants. - * @throws UnknownOopVisibilityTypeException - * @throws RuntimeException - */ - protected static function assertMethodVisibility(ReflectionMethod $method, string $visibilityType): void - { - // Type of visibility is not correct? - if (!OopVisibilityType::isCorrectType($visibilityType)) { - throw UnknownOopVisibilityTypeException::createException($visibilityType); - } - - switch ($visibilityType) { - case OopVisibilityType::IS_PUBLIC: - static::assertTrue($method->isPublic()); - - break; - case OopVisibilityType::IS_PROTECTED: - static::assertTrue($method->isProtected()); - - break; - case OopVisibilityType::IS_PRIVATE: - static::assertTrue($method->isPrivate()); - - break; - } - } - - /** - * Verifies count of method's arguments - * - * @param ReflectionMethod $method Name of method or just the method to verify - * @param int $argumentsCount (optional) Expected count/amount of arguments of the verified method - * @param int $requiredCount (optional) Expected count/amount of required arguments of the verified - * method - * @throws RuntimeException - */ - protected static function assertMethodArgumentsCount( - ReflectionMethod $method, - int $argumentsCount = 0, - int $requiredCount = 0 - ): void { - static::assertSame($argumentsCount, $method->getNumberOfParameters()); - static::assertSame($requiredCount, $method->getNumberOfRequiredParameters()); + yield ['lets-test.doc']; + yield ['lorem/ipsum.jpg']; + yield ['surprise/me/one/more/time.txt']; } /** @@ -246,6 +174,78 @@ trait BaseTestCaseTrait static::assertNull($constructor); } + /** + * Verifies count of method's arguments + * + * @param ReflectionMethod $method Name of method or just the method to verify + * @param int $argumentsCount (optional) Expected count/amount of arguments of the verified method + * @param int $requiredCount (optional) Expected count/amount of required arguments of the verified + * method + * @throws RuntimeException + */ + protected static function assertMethodArgumentsCount( + ReflectionMethod $method, + int $argumentsCount = 0, + int $requiredCount = 0 + ): void { + static::assertSame($argumentsCount, $method->getNumberOfParameters()); + static::assertSame($requiredCount, $method->getNumberOfRequiredParameters()); + } + + /** + * Verifies visibility of method + * + * @param ReflectionMethod $method Name of method or just the method to verify + * @param string $visibilityType Expected visibility of verified method. One of OopVisibilityType + * class constants. + * @throws UnknownOopVisibilityTypeException + * @throws RuntimeException + */ + protected static function assertMethodVisibility(ReflectionMethod $method, string $visibilityType): void + { + // Type of visibility is not correct? + if (!OopVisibilityType::isCorrectType($visibilityType)) { + throw UnknownOopVisibilityTypeException::createException($visibilityType); + } + + switch ($visibilityType) { + case OopVisibilityType::IS_PUBLIC: + static::assertTrue($method->isPublic()); + + break; + case OopVisibilityType::IS_PROTECTED: + static::assertTrue($method->isProtected()); + + break; + case OopVisibilityType::IS_PRIVATE: + static::assertTrue($method->isPrivate()); + + break; + } + } + + /** + * Returns path of file used by tests. + * It should be placed in /data/tests directory of this project. + * + * @param string $fileName Name of file + * @param string $directoryPath (optional) Path of directory containing the file + * @return string + */ + protected function getFilePathForTesting(string $fileName, string $directoryPath = ''): string + { + $rootPath = Miscellaneous::getProjectRootPath(); + + $paths = [ + $rootPath, + self::$testsDataDirPath, + $directoryPath, + $fileName, + ]; + + return Miscellaneous::concatenatePaths($paths); + } + /** * Sets path of directory with data used by test cases * diff --git a/src/Traits/Test/Base/BaseTypeTestCaseTrait.php b/src/Traits/Test/Base/BaseTypeTestCaseTrait.php index 9a86368..7c1d85f 100644 --- a/src/Traits/Test/Base/BaseTypeTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTypeTestCaseTrait.php @@ -21,6 +21,13 @@ use Meritoo\Common\Type\Base\BaseType; */ trait BaseTypeTestCaseTrait { + /** + * Provides type to verify and information if it's correct + * + * @return Generator + */ + abstract public function provideTypeToVerify(): Generator; + /** * Verifies availability of all types */ @@ -46,11 +53,11 @@ trait BaseTypeTestCaseTrait } /** - * Provides type to verify and information if it's correct + * Returns all expected types of the tested type * - * @return Generator + * @return array */ - abstract public function provideTypeToVerify(): Generator; + abstract protected function getAllExpectedTypes(): array; /** * Returns instance of the tested type @@ -58,11 +65,4 @@ trait BaseTypeTestCaseTrait * @return BaseType */ abstract protected function getTestedTypeInstance(): BaseType; - - /** - * Returns all expected types of the tested type - * - * @return array - */ - abstract protected function getAllExpectedTypes(): array; } diff --git a/src/Traits/ValueObject/HumanTrait.php b/src/Traits/ValueObject/HumanTrait.php index bfaea59..71d586a 100644 --- a/src/Traits/ValueObject/HumanTrait.php +++ b/src/Traits/ValueObject/HumanTrait.php @@ -83,23 +83,13 @@ trait HumanTrait } /** - * Returns first name + * Returns birth date * - * @return string + * @return null|DateTime */ - public function getFirstName(): string + public function getBirthDate(): ?DateTime { - return $this->firstName; - } - - /** - * Returns last name - * - * @return string - */ - public function getLastName(): string - { - return $this->lastName; + return $this->birthDate; } /** @@ -113,13 +103,13 @@ trait HumanTrait } /** - * Returns birth date + * Returns first name * - * @return null|DateTime + * @return string */ - public function getBirthDate(): ?DateTime + public function getFirstName(): string { - return $this->birthDate; + return $this->firstName; } /** @@ -141,4 +131,14 @@ trait HumanTrait return trim(sprintf('%s %s', $beginning, $finish)); } + + /** + * Returns last name + * + * @return string + */ + public function getLastName(): string + { + return $this->lastName; + } } diff --git a/src/Type/Base/BaseType.php b/src/Type/Base/BaseType.php index d3e49cc..26706d4 100644 --- a/src/Type/Base/BaseType.php +++ b/src/Type/Base/BaseType.php @@ -26,17 +26,6 @@ abstract class BaseType */ private $all; - /** - * Returns information if given type is correct - * - * @param null|string $type The type to check - * @return bool - */ - public static function isCorrectType(?string $type): bool - { - return in_array($type, (new static())->getAll()); - } - /** * Returns all types * @@ -50,4 +39,15 @@ abstract class BaseType return $this->all; } + + /** + * Returns information if given type is correct + * + * @param null|string $type The type to check + * @return bool + */ + public static function isCorrectType(?string $type): bool + { + return in_array($type, (new static())->getAll()); + } } diff --git a/src/Type/DatePeriod.php b/src/Type/DatePeriod.php index 8556031..7fb1fc0 100644 --- a/src/Type/DatePeriod.php +++ b/src/Type/DatePeriod.php @@ -110,6 +110,29 @@ class DatePeriod extends BaseType $this->endDate = $endDate; } + /** + * Returns the end date of period + * + * @return null|DateTime + */ + public function getEndDate(): ?DateTime + { + return $this->endDate; + } + + /** + * Sets the end date of period + * + * @param null|DateTime $endDate (optional) The end date of period. Default: null. + * @return $this + */ + public function setEndDate(?DateTime $endDate = null): self + { + $this->endDate = $endDate; + + return $this; + } + /** * Returns formatted one of the period's date: start date or end date * @@ -136,29 +159,6 @@ class DatePeriod extends BaseType return $date->format($format); } - /** - * Returns the end date of period - * - * @return null|DateTime - */ - public function getEndDate(): ?DateTime - { - return $this->endDate; - } - - /** - * Sets the end date of period - * - * @param null|DateTime $endDate (optional) The end date of period. Default: null. - * @return $this - */ - public function setEndDate(?DateTime $endDate = null): self - { - $this->endDate = $endDate; - - return $this; - } - /** * Returns the start date of period * diff --git a/src/Utilities/Arrays.php b/src/Utilities/Arrays.php index 7e49461..5c82257 100644 --- a/src/Utilities/Arrays.php +++ b/src/Utilities/Arrays.php @@ -24,329 +24,143 @@ class Arrays public const POSITION_KEY_NAME = 'position'; /** - * Converts given array's column to string. - * Recursive call is made for multi-dimensional arrays. + * Returns information if keys / indexes of given array are integers, in other words if the array contains + * zero-based keys / indexes * - * @param array $array Data to be converted - * @param int|string $arrayColumnKey (optional) Column name. Default: "". - * @param string $separator (optional) Separator used between values. Default: ",". - * @return null|string + * @param array $array The array to check + * @param bool $firstLevelOnly (optional) If is set to true, all keys / indexes are checked. Otherwise - from the + * first level only (default behaviour). + * @return bool */ - public static function values2string(array $array, $arrayColumnKey = '', $separator = ',') + public static function areAllKeysIntegers(array $array, $firstLevelOnly = false) { - // No elements? Nothing to do - if (empty($array)) { - return null; - } + $pattern = '\d+'; - $values = []; - - foreach ($array as $key => $value) { - $appendMe = null; - - if (is_array($value)) { - $appendMe = self::values2string($value, $arrayColumnKey, $separator); - } elseif (empty($arrayColumnKey)) { - $appendMe = $value; - } elseif ($key === $arrayColumnKey) { - $appendMe = $array[$arrayColumnKey]; - } - - /* - * Part to append is unknown? - * Let's go to next part - */ - if (null === $appendMe) { - continue; - } - - $values[] = $appendMe; - } - - // No values found? Nothing to do - if (empty($values)) { - return null; - } - - return implode($separator, $values); + return self::areAllKeysMatchedByPattern($array, $pattern, $firstLevelOnly); } /** - * Converts given array to string with keys, e.g. abc=1&def=2 or abc="1" def="2" + * Returns information if keys / indexes of given array are matched by given pattern * - * @param array $array Data to be converted - * @param string $separator (optional) Separator used between name-value pairs. Default: ",". - * @param string $valuesKeysSeparator (optional) Separator used between name and value. Default: "=". - * @param string $valuesWrapper (optional) Wrapper used to wrap values, e.g. double-quote: key="value". - * Default: "". - * @return null|string + * @param array $array The array to check + * @param string $pattern The pattern which keys / indexes should match, e.g. "\d+" + * @param bool $firstLevelOnly (optional) If is set to true, all keys / indexes are checked. Otherwise - from the + * first level only. + * @return bool */ - public static function valuesKeys2string( - array $array, - $separator = ',', - $valuesKeysSeparator = '=', - $valuesWrapper = '' - ) { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $result = ''; - - foreach ($array as $key => $value) { - if (!empty($result)) { - $result .= $separator; - } - - if (!empty($valuesWrapper)) { - $value = sprintf('%s%s%s', $valuesWrapper, $value, $valuesWrapper); - } - - $result .= $key . $valuesKeysSeparator . $value; - } - - return $result; - } - - /** - * Converts given array's rows to csv string - * - * @param array $array Data to be converted. It have to be an array that represents database table. - * @param string $separator (optional) Separator used between values. Default: ",". - * @return null|string - */ - public static function values2csv(array $array, string $separator = ','): ?string + public static function areAllKeysMatchedByPattern(array $array, string $pattern, bool $firstLevelOnly = false): bool { // No elements? Nothing to do if (empty($array)) { - return null; + return false; } - $rows = []; - $lineSeparator = "\n"; + /* + * I suppose that all are keys are matched + * and then I have to look for keys that don't matches + */ + $areMatched = true; - foreach ($array as $row) { + // Building the pattern + $rawPattern = $pattern; + $pattern = sprintf('|%s|', $rawPattern); + + foreach ($array as $key => $value) { /* - * I have to use html_entity_decode() function here, because some string values can contain - * entities with semicolon and this can destroy the CSV column order. + * Not matched? So I have to stop the iteration, because one not matched key + * means that not all keys are matched by given pattern */ + if (!preg_match($pattern, $key)) { + $areMatched = false; - if (is_array($row) && !empty($row)) { - foreach ($row as $key => $value) { - $row[$key] = html_entity_decode($value); + break; + } + + /* + * The not matching key was not found and the value is an array? + * Let's begin recursive looking for result + */ + if ($areMatched && is_array($value) && !$firstLevelOnly) { + $areMatched = self::areAllKeysMatchedByPattern($value, $rawPattern, $firstLevelOnly); + } + } + + return $areMatched; + } + + /** + * Returns information if given array is empty, iow. information if all elements of given array are empty + * + * @param array $array The array to verify + * @param bool $strictNull (optional) If is set to true elements are verified if they are null. Otherwise - only + * if they are empty (e.g. null, '', 0, array()). + * @return bool + */ + public static function areAllValuesEmpty(array $array, $strictNull = false) + { + // No elements? Nothing to do + if (empty($array)) { + return false; + } + + foreach ($array as $element) { + /* + * If elements are verified if they are exactly null and the element is: + * - not an array + * - not null + * or elements are NOT verified if they are exactly null and the element is: + * - not empty (e.g. null, '', 0, array()) + * + * If one of the above is true, not all elements of given array are empty + */ + if ((!is_array($element) && $strictNull && null !== $element) || !empty($element)) { + return false; + } + } + + return true; + } + + /** + * Returns information if given keys exist in given array + * + * @param array $keys The keys to find + * @param array $array The array that maybe contains keys + * @param bool $explicit (optional) If is set to true, all keys should exist in given array. Otherwise - not all. + * @return bool + */ + public static function areKeysInArray(array $keys, array $array, $explicit = true) + { + $result = false; + + if (!empty($array)) { + $firstKey = true; + + foreach ($keys as $key) { + $exists = array_key_exists($key, $array); + + if ($firstKey) { + $result = $exists; + $firstKey = false; + } elseif ($explicit) { + $result = $result && $exists; + + if (!$result) { + break; + } + } else { + $result = $result || $exists; + + if ($result) { + break; + } } - - $rows[] = implode($separator, $row); - } - } - - if (empty($rows)) { - return ''; - } - - return implode($lineSeparator, $rows); - } - - /** - * Returns information if given element is the first one - * - * @param array $array The array to get the first element of - * @param mixed $element The element to check / verify - * @param bool $firstLevelOnly (optional) If is set to true, first element is returned. Otherwise - totally - * first element is returned (first of the First array). - * @return bool - */ - public static function isFirstElement(array $array, $element, bool $firstLevelOnly = true): bool - { - $firstElement = static::getFirstElement($array, $firstLevelOnly); - - return $element === $firstElement; - } - - /** - * Returns the first element of given array - * - * It may be first element of given array or the totally first element from the all elements (first element of the - * first array). - * - * @param array $array The array to get the first element of - * @param bool $firstLevelOnly (optional) If is set to true, first element is returned. Otherwise - totally - * first element is returned (first of the first array). - * @return mixed - */ - public static function getFirstElement(array $array, bool $firstLevelOnly = true) - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $firstKey = static::getFirstKey($array); - $result = $array[$firstKey]; - - if (!$firstLevelOnly && is_array($result)) { - $result = static::getFirstElement($result, $firstLevelOnly); - } - - return $result; - } - - /** - * Returns first key of array - * - * @param array $array The array to get the first key of - * @return mixed - */ - public static function getFirstKey(array $array) - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $keys = array_keys($array); - - return $keys[0]; - } - - /** - * Returns information if given element is the last one - * - * @param array $array The array to get the last element of - * @param mixed $element The element to check / verify - * @param bool $firstLevelOnly (optional) If is set to true, last element is returned. Otherwise - totally - * last element is returned (last of the latest array). - * @return bool - */ - public static function isLastElement(array $array, $element, bool $firstLevelOnly = true): bool - { - $lastElement = static::getLastElement($array, $firstLevelOnly); - - return $element === $lastElement; - } - - /** - * Returns the last element of given array - * - * It may be last element of given array or the totally last element from the all elements (last element of the - * latest array). - * - * @param array $array The array to get the last element of - * @param bool $firstLevelOnly (optional) If is set to true, last element is returned. Otherwise - totally - * last element is returned (last of the latest array). - * @return mixed - */ - public static function getLastElement(array $array, bool $firstLevelOnly = true) - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $last = end($array); - - if (!$firstLevelOnly && is_array($last)) { - $last = static::getLastElement($last, $firstLevelOnly); - } - - return $last; - } - - /** - * Returns breadcrumb (a path) to the last element of array - * - * @param array $array Data to get the breadcrumb - * @param string $separator (optional) Separator used to stick the elements. Default: "/". - * @return null|string - */ - public static function getLastElementBreadCrumb(array $array, $separator = '/') - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $keys = array_keys($array); - $keysCount = count($keys); - - $lastKey = $keys[$keysCount - 1]; - $last = end($array); - - $breadCrumb = $lastKey; - - if (is_array($last)) { - $crumb = self::getLastElementBreadCrumb($last, $separator); - } else { - $crumb = $last; - } - - return $breadCrumb . $separator . $crumb; - } - - /** - * Returns the last row of array - * - * @param array $array The array to get the last row of - * @return mixed - */ - public static function getLastRow(array $array): ?array - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $result = []; - $last = end($array); - - if (is_array($last)) { - // We've got an array, so looking for the last row of array will be done recursively - $result = static::getLastRow($last); - - /* - * The last row is not an array or it's an empty array? - * Let's use the previous candidate - */ - if (!is_array($result) || static::isEmptyArray($result)) { - $result = $last; } } return $result; } - /** - * Replaces array keys that match given pattern with new key name - * - * @param array $array Array which keys should be replaced - * @param string $oldKeyPattern Regular expression of the old key - * @param string $newKey Name of the new key - * @return null|array - */ - public static function replaceKeys(array $array, string $oldKeyPattern, string $newKey): ?array - { - if (empty($array)) { - return null; - } - - $effect = []; - - foreach ($array as $key => $value) { - if (preg_match($oldKeyPattern, $key)) { - $key = $newKey; - } - - if (is_array($value)) { - $value = self::replaceKeys($value, $oldKeyPattern, $newKey); - } - - $effect[$key] = $value; - } - - return $effect; - } - /** * Generates JavaScript code for given PHP array * @@ -405,7 +219,7 @@ class Arrays $variable = $index; if (is_int($index)) { - $variable = 'value_' . $variable; + $variable = 'value_'.$variable; } $value = self::array2JavaScript($value, $variable, $preserveIndexes); @@ -422,7 +236,7 @@ class Arrays $result .= "\n"; } - $result .= $value . "\n"; + $result .= $value."\n"; $result .= sprintf('%s[%s] = %s;', $jsVariableName, Miscellaneous::quoteValue($index), $variable); if ($counter !== $arrayCount) { @@ -453,877 +267,6 @@ class Arrays return $result; } - /** - * Quotes (adds quotes) to elements that are strings and returns new array (with quoted elements) - * - * @param array $array The array to check for string values - * @return null|array - */ - public static function quoteStrings(array $array): ?array - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $result = []; - - foreach ($array as $index => $value) { - if (is_array($value)) { - $value = self::quoteStrings($value); - } elseif (is_string($value) && !Regex::isQuoted($value)) { - $value = '\'' . $value . '\''; - } - - $result[$index] = $value; - } - - return $result; - } - - /** - * Removes marginal element (first or last) from given array - * - * @param array $array The array which should be shortened - * @param bool $last (optional) If is set to true, last element is removed (default behaviour). Otherwise - first. - * @return null|array - */ - public static function removeMarginalElement(array $array, bool $last = true): ?array - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $key = self::getFirstKey($array); - - if ($last) { - $key = self::getLastKey($array); - } - - unset($array[$key]); - - return $array; - } - - /** - * Returns last key of array - * - * @param array $array The array to get the last key of - * @return mixed - */ - public static function getLastKey(array $array) - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $keys = array_keys($array); - - return end($keys); - } - - /** - * Removes element / item of given array - * - * @param array $array The array that contains element / item which should be removed - * @param mixed $item The element / item which should be removed - * @return array|bool - */ - public static function removeElement(array $array, $item) - { - // No elements or the element does not exist? Nothing to do - if (empty($array) || !in_array($item, $array, true)) { - return false; - } - - // Flip the array to make it looks like: value => key - $arrayFlipped = array_flip($array); - - // Take the key of element / item that should be removed - $key = $arrayFlipped[$item]; - - // ...and remove the element / item - unset($array[$key]); - - return $array; - } - - /** - * Removes items from given array starting at given element (before or after the element) - * - * @param array $array The array which contains items to remove - * @param mixed $needle The element which is start point of deletion - * @param bool $before (optional) If is set to true, all elements before given needle are removed. Otherwise - all - * after needle. - */ - public static function removeElements(array &$array, $needle, $before = true): void - { - if (!empty($array)) { - if (!$before) { - $array = array_reverse($array, true); - } - - foreach ($array as $key => &$value) { - $remove = false; - $isArray = is_array($value); - - if ($isArray) { - self::removeElements($value, $needle, $before); - - if (empty($value)) { - $remove = true; - } - } elseif ($value === $needle) { - break; - } else { - $remove = true; - } - - if ($remove) { - unset($array[$key]); - } - } - - if (!$before) { - $array = array_reverse($array, true); - } - } - } - - /** - * Sets keys as values and values as keys in given array. - * Replaces keys with values. - * - * @param array $array The array to change values with keys - * @param bool $ignoreDuplicatedValues (optional) If is set to true, duplicated values are ignored. This means that - * when there is more than 1 value and that values become key, only the last - * value will be used with it's key, because other will be overridden. - * Otherwise - values are preserved and keys assigned to that values are - * returned as an array. - * @return null|array - * - * Example of $ignoreDuplicatedValues = false: - * - provided array - * $array = [ - * 'lorem' => 100, // <-- Duplicated value - * 'ipsum' => 200, - * 'dolor' => 100, // <-- Duplicated value - * ]; - * - * - result - * $replaced = [ - * 100 => [ - * 'lorem', // <-- Key of duplicated value - * 'dolor', // <-- Key of duplicated value - * ], - * 200 => 'ipsum', - * ]; - */ - public static function setKeysAsValues(array $array, $ignoreDuplicatedValues = true) - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $replaced = []; - - foreach ($array as $key => $value) { - /* - * The value it's an array? - * Let's replace keys with values in this array first - */ - if (is_array($value)) { - $replaced[$key] = self::setKeysAsValues($value, $ignoreDuplicatedValues); - - continue; - } - - // Duplicated values shouldn't be ignored and processed value is used as key already? - // Let's use an array and that will contain all values (to avoid ignoring / overriding duplicated values) - if (!$ignoreDuplicatedValues && isset($replaced[$value])) { - $existing = self::makeArray($replaced[$value]); - - $replaced[$value] = array_merge($existing, [ - $key, - ]); - - continue; - } - - // Standard behaviour - $replaced[$value] = $key; - } - - return $replaced; - } - - /** - * Applies ksort() function recursively in the given array - * - * @param array $array The array to sort - * @param int $sortFlags (optional) Options of ksort() function - * @return null|array - */ - public static function ksortRecursive(array &$array, $sortFlags = SORT_REGULAR) - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $effect = &$array; - ksort($effect, $sortFlags); - - foreach ($effect as &$value) { - if (is_array($value)) { - ksort($value, $sortFlags); - } - } - - return $effect; - } - - /** - * Returns count / amount of elements that are not array - * - * @param array $array The array to count - * @return null|int - */ - public static function getNonArrayElementsCount(array $array): ?int - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $count = 0; - - foreach ($array as $value) { - if (is_array($value)) { - $count += (int)self::getNonArrayElementsCount($value); - - continue; - } - - ++$count; - } - - return $count; - } - - /** - * Converts given string with special separators to array - * - * Example: - * ~ string: - * "light:jasny|dark:ciemny" - * - * ~ array as a result: - * [ - * 'light' => 'jasny', - * 'dark' => 'ciemny', - * ] - * - * @param string $string The string to be converted - * @param string $separator (optional) Separator used between name-value pairs in the string. - * Default: "|". - * @param string $valuesKeysSeparator (optional) Separator used between name and value in the string. Default: ":". - * @return null|array - */ - public static function string2array( - string $string, - string $separator = '|', - string $valuesKeysSeparator = ':' - ): ?array { - // Empty string? Nothing to do - if (empty($string)) { - return null; - } - - $array = []; - $exploded = explode($separator, $string); - - foreach ($exploded as $item) { - $exploded2 = explode($valuesKeysSeparator, $item); - - if (2 === count($exploded2)) { - $key = trim($exploded2[0]); - $value = trim($exploded2[1]); - - $array[$key] = $value; - } - } - - return $array; - } - - /** - * Returns information if given keys exist in given array - * - * @param array $keys The keys to find - * @param array $array The array that maybe contains keys - * @param bool $explicit (optional) If is set to true, all keys should exist in given array. Otherwise - not all. - * @return bool - */ - public static function areKeysInArray(array $keys, array $array, $explicit = true) - { - $result = false; - - if (!empty($array)) { - $firstKey = true; - - foreach ($keys as $key) { - $exists = array_key_exists($key, $array); - - if ($firstKey) { - $result = $exists; - $firstKey = false; - } elseif ($explicit) { - $result = $result && $exists; - - if (!$result) { - break; - } - } else { - $result = $result || $exists; - - if ($result) { - break; - } - } - } - } - - return $result; - } - - /** - * Returns paths of the last elements - * - * @param array $array The array with elements - * @param string $separator (optional) Separator used between elements. Default: ".". - * @param string $parentPath (optional) Path of the parent element. Default: "". - * @param array $stopIfMatchedBy (optional) Patterns of keys or paths when matched will stop the process of path - * building and including children of those keys or paths (recursive will not be - * used for keys in lower level of given array). Default: []. - * @return null|array - * - * Examples - $stopIfMatchedBy argument: - * a) "\d+" - * b) [ - * "lorem\-", - * "\d+", - * ]; - */ - public static function getLastElementsPaths( - array $array, - string $separator = '.', - string $parentPath = '', - array $stopIfMatchedBy = [] - ): ?array { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $result = []; - - foreach ($array as $key => $value) { - $path = $key; - $stopRecursion = false; - $valueIsArray = is_array($value); - - /* - * If the path of parent element is delivered, - * I have to use it and build longer path - */ - if (!empty($parentPath)) { - $pathTemplate = '%s%s%s'; - $path = sprintf($pathTemplate, $parentPath, $separator, $key); - } - - /* - * Check if the key or current path matches one of patterns at which the process should be stopped, - * the recursive not used. It means that I have to pass current value and stop processing of the - * array (don't go to the next step). - */ - if (!empty($stopIfMatchedBy)) { - foreach ($stopIfMatchedBy as $rawPattern) { - $pattern = sprintf('|%s|', $rawPattern); - - if (preg_match($pattern, $key) || preg_match($pattern, $path)) { - $stopRecursion = true; - - break; - } - } - } - - /* - * The value is passed to the returned array if: - * - the process is stopped, recursive is not used - * or - * - it's not an array - * or - * - it's an array, but empty - */ - if ($stopRecursion || !$valueIsArray || self::isEmptyArray($value)) { - $result[$path] = $value; - - continue; - } - - // Let's iterate through the next level, using recursive - $recursivePaths = self::getLastElementsPaths($value, $separator, $path, $stopIfMatchedBy); - - if (null !== $recursivePaths) { - $result += $recursivePaths; - } - } - - return $result; - } - - /** - * Makes and returns an array for given variable - * - * @param mixed $variable Variable that should be an array - * @return array - */ - public static function makeArray($variable): array - { - if (is_array($variable)) { - return $variable; - } - - return [$variable]; - } - - /** - * Returns information if keys / indexes of given array are matched by given pattern - * - * @param array $array The array to check - * @param string $pattern The pattern which keys / indexes should match, e.g. "\d+" - * @param bool $firstLevelOnly (optional) If is set to true, all keys / indexes are checked. Otherwise - from the - * first level only. - * @return bool - */ - public static function areAllKeysMatchedByPattern(array $array, string $pattern, bool $firstLevelOnly = false): bool - { - // No elements? Nothing to do - if (empty($array)) { - return false; - } - - /* - * I suppose that all are keys are matched - * and then I have to look for keys that don't matches - */ - $areMatched = true; - - // Building the pattern - $rawPattern = $pattern; - $pattern = sprintf('|%s|', $rawPattern); - - foreach ($array as $key => $value) { - /* - * Not matched? So I have to stop the iteration, because one not matched key - * means that not all keys are matched by given pattern - */ - if (!preg_match($pattern, $key)) { - $areMatched = false; - - break; - } - - /* - * The not matching key was not found and the value is an array? - * Let's begin recursive looking for result - */ - if ($areMatched && is_array($value) && !$firstLevelOnly) { - $areMatched = self::areAllKeysMatchedByPattern($value, $rawPattern, $firstLevelOnly); - } - } - - return $areMatched; - } - - /** - * Returns information if keys / indexes of given array are integers, in other words if the array contains - * zero-based keys / indexes - * - * @param array $array The array to check - * @param bool $firstLevelOnly (optional) If is set to true, all keys / indexes are checked. Otherwise - from the - * first level only (default behaviour). - * @return bool - */ - public static function areAllKeysIntegers(array $array, $firstLevelOnly = false) - { - $pattern = '\d+'; - - return self::areAllKeysMatchedByPattern($array, $pattern, $firstLevelOnly); - } - - /** - * Returns value of given array set under given path of keys, of course if the value exists. - * The keys should be delivered in the same order as used by source array. - * - * @param array $array The array which should contains a value - * @param array $keys Keys, path of keys, to find in given array - * @return mixed - * - * Examples: - * a) $array - * [ - * 'some key' => [ - * 'another some key' => [ - * 'yet another key' => 123, - * ], - * 'some different key' => 456, - * ] - * ] - * - * b) $keys - * [ - * 'some key', - * 'another some key', - * 'yet another key', - * ] - * - * Based on the above examples will return: - * 123 - */ - public static function getValueByKeysPath(array $array, array $keys) - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $value = null; - - if (self::issetRecursive($array, $keys)) { - foreach ($keys as $key) { - $value = $array[$key]; - array_shift($keys); - - if (is_array($value) && !empty($keys)) { - $value = self::getValueByKeysPath($value, $keys); - } - - break; - } - } - - return $value; - } - - /** - * Returns information if given path of keys are set is given array. - * The keys should be delivered in the same order as used by source array. - * - * @param array $array The array to check - * @param array $keys Keys, path of keys, to find in given array - * @return bool - * - * Examples: - * a) $array - * [ - * 'some key' => [ - * 'another some key' => [ - * 'yet another key' => 123, - * ], - * 'some different key' => 456, - * ] - * ] - * - * b) $keys - * [ - * 'some key', - * 'another some key', - * 'yet another key', - * ] - */ - public static function issetRecursive(array $array, array $keys) - { - // No elements? Nothing to do - if (empty($array)) { - return false; - } - - $isset = false; - - foreach ($keys as $key) { - $isset = isset($array[$key]); - - if ($isset) { - $newArray = $array[$key]; - array_shift($keys); - - if (is_array($newArray) && !empty($keys)) { - $isset = self::issetRecursive($newArray, $keys); - } - } - - break; - } - - return $isset; - } - - /** - * Returns all values of given key. - * It may be useful when you want to retrieve all values of one column. - * - * @param array $array The array which should contain values of the key - * @param string $key The key - * @return null|array - */ - public static function getAllValuesOfKey(array $array, $key) - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $values = []; - - foreach ($array as $index => $value) { - if ($index === $key) { - $values[] = $value; - - continue; - } - - if (is_array($value)) { - $recursiveValues = self::getAllValuesOfKey($value, $key); - - if (!empty($recursiveValues)) { - $merged = array_merge($values, $recursiveValues); - $values = $merged; - } - } - } - - return $values; - } - - /** - * Sets positions for each element / child of given array and returns the array - * - * Position for the 1st element / child of a parent is set to 1 and incremented for the next element and - * so on. Each parent is treated as separate array, so its elements are treated as positioned at 1st level. - * - * @param array $array The array which should has values of position for each element - * @param string $keyName (optional) Name of key which will contain the position value - * @param int $startPosition (optional) Default, start value of the position for main / given array, not the - * children - * @return null|array - */ - public static function setPositions(array $array, $keyName = self::POSITION_KEY_NAME, $startPosition = null) - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $childPosition = 1; - - if (null !== $startPosition) { - $array[$keyName] = $startPosition; - } - - foreach ($array as &$value) { - if (is_array($value)) { - $value = self::setPositions($value, $keyName, $childPosition); - ++$childPosition; - } - } - - return $array; - } - - /** - * Trims string values of given array and returns the new array - * - * @param array $array The array which values should be trimmed - * @return array - */ - public static function trimRecursive(array $array) - { - // No elements? Nothing to do - if (empty($array)) { - return []; - } - - $result = []; - - foreach ($array as $key => $value) { - if (is_array($value)) { - $result[$key] = self::trimRecursive($value); - - continue; - } - - if (is_string($value)) { - $value = trim($value); - } - - $result[$key] = $value; - } - - return $result; - } - - /** - * Sorts an array by keys given in second array as values. - * Keys which are not in array with order are pushed after sorted elements. - * - * Example: - * - array to sort: - * - * array( - * 'lorem' => array( - * 'ipsum' - * ), - * 'dolor' => array( - * 'sit', - * 'amet' - * ), - * 'neque' => 'neque' - * ) - * - * - keys order: - * - * array( - * 'dolor', - * 'lorem' - * ) - * - * - the result: - * - * array( - * 'dolor' => array( - * 'sit', - * 'amet' - * ), - * 'lorem' => array( - * 'ipsum' - * ), - * 'neque' => 'neque' // <-- the rest, values of other keys - * ) - * - * - * @param array $array An array to sort - * @param array $keysOrder An array with keys of the 1st argument in proper / required order - * @return null|array - */ - public static function sortByCustomKeysOrder(array $array, array $keysOrder) - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - $ordered = []; - - /* - * 1st iteration: - * Get elements in proper / required order - */ - if (!empty($keysOrder)) { - foreach ($keysOrder as $key) { - if (isset($array[$key])) { - $ordered[$key] = $array[$key]; - unset($array[$key]); - } - } - } - - /* - * 2nd iteration: - * Get the rest of elements - */ - if (!empty($array)) { - foreach ($array as $key => $element) { - $ordered[$key] = $element; - } - } - - return $ordered; - } - - /** - * Returns smartly imploded string - * - * Separators located at the beginning or end of elements are removed. - * It's required to avoid problems with duplicated separator, e.g. "first//second/third", where separator is a - * "/" string. - * - * @param array $array The array with elements to implode - * @param string $separator Separator used to stick together elements of given array - * @return null|string - */ - public static function implodeSmart(array $array, $separator) - { - // No elements? Nothing to do - if (empty($array)) { - return null; - } - - foreach ($array as &$element) { - if (is_array($element)) { - $element = self::implodeSmart($element, $separator); - } - - if (Regex::startsWith($element, $separator)) { - $element = substr($element, 1); - } - - if (Regex::endsWith($element, $separator)) { - $element = substr($element, 0, -1); - } - } - - return implode($separator, $array); - } - - /** - * Returns information if given array is empty, iow. information if all elements of given array are empty - * - * @param array $array The array to verify - * @param bool $strictNull (optional) If is set to true elements are verified if they are null. Otherwise - only - * if they are empty (e.g. null, '', 0, array()). - * @return bool - */ - public static function areAllValuesEmpty(array $array, $strictNull = false) - { - // No elements? Nothing to do - if (empty($array)) { - return false; - } - - foreach ($array as $element) { - /* - * If elements are verified if they are exactly null and the element is: - * - not an array - * - not null - * or elements are NOT verified if they are exactly null and the element is: - * - not empty (e.g. null, '', 0, array()) - * - * If one of the above is true, not all elements of given array are empty - */ - if ((!is_array($element) && $strictNull && null !== $element) || !empty($element)) { - return false; - } - } - - return true; - } - /** * Returns an array containing all the entries from 1st array that are not present in 2nd array. * An item from 1st array is the same as in 2nd array if both, keys and values, are the same. @@ -1412,6 +355,172 @@ class Arrays return $result; } + public static function containsEmptyStringsOnly(array $array): bool + { + if (empty($array)) { + return false; + } + + return '' === trim(implode('', $array)); + } + + /** + * Returns all values of given key. + * It may be useful when you want to retrieve all values of one column. + * + * @param array $array The array which should contain values of the key + * @param string $key The key + * @return null|array + */ + public static function getAllValuesOfKey(array $array, $key) + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $values = []; + + foreach ($array as $index => $value) { + if ($index === $key) { + $values[] = $value; + + continue; + } + + if (is_array($value)) { + $recursiveValues = self::getAllValuesOfKey($value, $key); + + if (!empty($recursiveValues)) { + $merged = array_merge($values, $recursiveValues); + $values = $merged; + } + } + } + + return $values; + } + + /** + * Returns count of dimensions, maximum nesting level actually, in given array + * + * @param array $array The array to verify + * @return int + */ + public static function getDimensionsCount(array $array): int + { + // No elements? Nothing to do + if (empty($array)) { + return 0; + } + + $dimensionsCount = 1; + + foreach ($array as $value) { + if (is_array($value)) { + /* + * I have to increment returned value, because that means we've got 1 level more (if the value is an + * array) + */ + $count = self::getDimensionsCount($value) + 1; + + if ($count > $dimensionsCount) { + $dimensionsCount = $count; + } + } + } + + return $dimensionsCount; + } + + public static function getElementsFromLevel(array $array, int $level, ?string $childrenKey = null): ?array + { + if (empty($array) || $level <= 0) { + return null; + } + + $result = []; + + foreach ($array as $key => $value) { + // This is the expected level (the deepest). Comparing with 1, because level will be decreased by 1 (later), + // and finally we will get the latest/deepest level that equals 1. + if ($level === 1) { + // No key of children (next level) provided or this is the same key as processed? + // We've got the expected value + if ($childrenKey === null || $key === $childrenKey) { + $result[] = $value; + } + + continue; + } + + // There is no deeper level + if (!is_array($value)) { + continue; + } + + // Let's dive one level down/deeper + $elements = self::getElementsFromLevel($value, $level - 1, $childrenKey); + + if ($elements === null) { + continue; + } + + // I have to load each element separately to avoid issue with incorrectly nested values + foreach ($elements as $element) { + $result[] = $element; + } + } + + return $result; + } + + /** + * Returns the first element of given array + * + * It may be first element of given array or the totally first element from the all elements (first element of the + * first array). + * + * @param array $array The array to get the first element of + * @param bool $firstLevelOnly (optional) If is set to true, first element is returned. Otherwise - totally + * first element is returned (first of the first array). + * @return mixed + */ + public static function getFirstElement(array $array, bool $firstLevelOnly = true) + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $firstKey = static::getFirstKey($array); + $result = $array[$firstKey]; + + if (!$firstLevelOnly && is_array($result)) { + $result = static::getFirstElement($result, $firstLevelOnly); + } + + return $result; + } + + /** + * Returns first key of array + * + * @param array $array The array to get the first key of + * @return mixed + */ + public static function getFirstKey(array $array) + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $keys = array_keys($array); + + return $keys[0]; + } + /** * Returns an index / key of given element in given array * @@ -1435,6 +544,387 @@ class Arrays return null; } + /** + * Returns the last element of given array + * + * It may be last element of given array or the totally last element from the all elements (last element of the + * latest array). + * + * @param array $array The array to get the last element of + * @param bool $firstLevelOnly (optional) If is set to true, last element is returned. Otherwise - totally + * last element is returned (last of the latest array). + * @return mixed + */ + public static function getLastElement(array $array, bool $firstLevelOnly = true) + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $last = end($array); + + if (!$firstLevelOnly && is_array($last)) { + $last = static::getLastElement($last, $firstLevelOnly); + } + + return $last; + } + + /** + * Returns breadcrumb (a path) to the last element of array + * + * @param array $array Data to get the breadcrumb + * @param string $separator (optional) Separator used to stick the elements. Default: "/". + * @return null|string + */ + public static function getLastElementBreadCrumb(array $array, $separator = '/') + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $keys = array_keys($array); + $keysCount = count($keys); + + $lastKey = $keys[$keysCount - 1]; + $last = end($array); + + $breadCrumb = $lastKey; + + if (is_array($last)) { + $crumb = self::getLastElementBreadCrumb($last, $separator); + } else { + $crumb = $last; + } + + return $breadCrumb.$separator.$crumb; + } + + /** + * Returns paths of the last elements + * + * @param array $array The array with elements + * @param string $separator (optional) Separator used between elements. Default: ".". + * @param string $parentPath (optional) Path of the parent element. Default: "". + * @param array $stopIfMatchedBy (optional) Patterns of keys or paths when matched will stop the process of path + * building and including children of those keys or paths (recursive will not be + * used for keys in lower level of given array). Default: []. + * @return null|array + * + * Examples - $stopIfMatchedBy argument: + * a) "\d+" + * b) [ + * "lorem\-", + * "\d+", + * ]; + */ + public static function getLastElementsPaths( + array $array, + string $separator = '.', + string $parentPath = '', + array $stopIfMatchedBy = [] + ): ?array { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $result = []; + + foreach ($array as $key => $value) { + $path = $key; + $stopRecursion = false; + $valueIsArray = is_array($value); + + /* + * If the path of parent element is delivered, + * I have to use it and build longer path + */ + if (!empty($parentPath)) { + $pathTemplate = '%s%s%s'; + $path = sprintf($pathTemplate, $parentPath, $separator, $key); + } + + /* + * Check if the key or current path matches one of patterns at which the process should be stopped, + * the recursive not used. It means that I have to pass current value and stop processing of the + * array (don't go to the next step). + */ + if (!empty($stopIfMatchedBy)) { + foreach ($stopIfMatchedBy as $rawPattern) { + $pattern = sprintf('|%s|', $rawPattern); + + if (preg_match($pattern, $key) || preg_match($pattern, $path)) { + $stopRecursion = true; + + break; + } + } + } + + /* + * The value is passed to the returned array if: + * - the process is stopped, recursive is not used + * or + * - it's not an array + * or + * - it's an array, but empty + */ + if ($stopRecursion || !$valueIsArray || self::isEmptyArray($value)) { + $result[$path] = $value; + + continue; + } + + // Let's iterate through the next level, using recursive + $recursivePaths = self::getLastElementsPaths($value, $separator, $path, $stopIfMatchedBy); + + if (null !== $recursivePaths) { + $result += $recursivePaths; + } + } + + return $result; + } + + /** + * Returns last key of array + * + * @param array $array The array to get the last key of + * @return mixed + */ + public static function getLastKey(array $array) + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $keys = array_keys($array); + + return end($keys); + } + + /** + * Returns the last row of array + * + * @param array $array The array to get the last row of + * @return mixed + */ + public static function getLastRow(array $array): ?array + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $result = []; + $last = end($array); + + if (is_array($last)) { + // We've got an array, so looking for the last row of array will be done recursively + $result = static::getLastRow($last); + + /* + * The last row is not an array or it's an empty array? + * Let's use the previous candidate + */ + if (!is_array($result) || static::isEmptyArray($result)) { + $result = $last; + } + } + + return $result; + } + + /** + * Returns next element of given array related to given element + * + * @param array $array The array with elements + * @param mixed $element Element for who next element should be returned + * @return null|mixed + */ + public static function getNextElement(array $array, $element) + { + return self::getNeighbour($array, $element); + } + + /** + * Returns count / amount of elements that are not array + * + * @param array $array The array to count + * @return null|int + */ + public static function getNonArrayElementsCount(array $array): ?int + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $count = 0; + + foreach ($array as $value) { + if (is_array($value)) { + $count += (int) self::getNonArrayElementsCount($value); + + continue; + } + + ++$count; + } + + return $count; + } + + /** + * Returns non-empty values, e.g. without "" (empty string), null or [] + * + * @param array $values The values to filter + * @return null|array + */ + public static function getNonEmptyValues(array $values): ?array + { + // No values? Nothing to do + if (empty($values)) { + return null; + } + + return array_filter($values, static function ($value): bool { + $nonEmptyScalar = is_scalar($value) && '' !== $value; + $nonEmptyArray = self::isNotEmptyArray($value); + + return $nonEmptyScalar || $nonEmptyArray || is_object($value); + }); + } + + /** + * Returns non-empty values concatenated by given separator + * + * @param array $values The values to filter + * @param string $separator (optional) Separator used to implode the values. Default: ", ". + * @return null|string + */ + public static function getNonEmptyValuesAsString(array $values, string $separator = ', '): ?string + { + // No elements? Nothing to do + if (empty($values)) { + return null; + } + + $nonEmpty = self::getNonEmptyValues($values); + + // No values? Nothing to do + if (empty($nonEmpty)) { + return ''; + } + + return implode($separator, $nonEmpty); + } + + /** + * Returns previous element of given array related to given element + * + * @param array $array The array with elements + * @param mixed $element Element for who previous element should be returned + * @return null|mixed + */ + public static function getPreviousElement(array $array, $element) + { + return self::getNeighbour($array, $element, false); + } + + /** + * Returns value of given array set under given path of keys, of course if the value exists. + * The keys should be delivered in the same order as used by source array. + * + * @param array $array The array which should contains a value + * @param array $keys Keys, path of keys, to find in given array + * @return mixed + * + * Examples: + * a) $array + * [ + * 'some key' => [ + * 'another some key' => [ + * 'yet another key' => 123, + * ], + * 'some different key' => 456, + * ] + * ] + * + * b) $keys + * [ + * 'some key', + * 'another some key', + * 'yet another key', + * ] + * + * Based on the above examples will return: + * 123 + */ + public static function getValueByKeysPath(array $array, array $keys) + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $value = null; + + if (self::issetRecursive($array, $keys)) { + foreach ($keys as $key) { + $value = $array[$key]; + array_shift($keys); + + if (is_array($value) && !empty($keys)) { + $value = self::getValueByKeysPath($value, $keys); + } + + break; + } + } + + return $value; + } + + /** + * Returns smartly imploded string + * + * Separators located at the beginning or end of elements are removed. + * It's required to avoid problems with duplicated separator, e.g. "first//second/third", where separator is a + * "/" string. + * + * @param array $array The array with elements to implode + * @param string $separator Separator used to stick together elements of given array + * @return null|string + */ + public static function implodeSmart(array $array, $separator) + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + foreach ($array as &$element) { + if (is_array($element)) { + $element = self::implodeSmart($element, $separator); + } + + if (Regex::startsWith($element, $separator)) { + $element = substr($element, 1); + } + + if (Regex::endsWith($element, $separator)) { + $element = substr($element, 0, -1); + } + } + + return implode($separator, $array); + } + /** * Returns an array with incremented indexes / keys * @@ -1485,7 +975,7 @@ class Arrays */ if (!empty($valuesToIncrement)) { foreach ($valuesToIncrement as $oldIndex => $value) { - $newIndex = (int)$oldIndex + $incrementStep; + $newIndex = (int) $oldIndex + $incrementStep; $array[$newIndex] = $value; } } @@ -1495,27 +985,46 @@ class Arrays } /** - * Returns next element of given array related to given element + * Returns information if given value is an array and is empty * - * @param array $array The array with elements - * @param mixed $element Element for who next element should be returned - * @return null|mixed + * @param mixed $value The value to verify + * @return bool */ - public static function getNextElement(array $array, $element) + public static function isEmptyArray($value): bool { - return self::getNeighbour($array, $element); + return is_array($value) && empty($value); } /** - * Returns previous element of given array related to given element + * Returns information if given element is the first one * - * @param array $array The array with elements - * @param mixed $element Element for who previous element should be returned - * @return null|mixed + * @param array $array The array to get the first element of + * @param mixed $element The element to check / verify + * @param bool $firstLevelOnly (optional) If is set to true, first element is returned. Otherwise - totally + * first element is returned (first of the First array). + * @return bool */ - public static function getPreviousElement(array $array, $element) + public static function isFirstElement(array $array, $element, bool $firstLevelOnly = true): bool { - return self::getNeighbour($array, $element, false); + $firstElement = static::getFirstElement($array, $firstLevelOnly); + + return $element === $firstElement; + } + + /** + * Returns information if given element is the last one + * + * @param array $array The array to get the last element of + * @param mixed $element The element to check / verify + * @param bool $firstLevelOnly (optional) If is set to true, last element is returned. Otherwise - totally + * last element is returned (last of the latest array). + * @return bool + */ + public static function isLastElement(array $array, $element, bool $firstLevelOnly = true): bool + { + $lastElement = static::getLastElement($array, $firstLevelOnly); + + return $element === $lastElement; } /** @@ -1534,94 +1043,6 @@ class Arrays return count($array) !== count($array, COUNT_RECURSIVE); } - /** - * Returns count of dimensions, maximum nesting level actually, in given array - * - * @param array $array The array to verify - * @return int - */ - public static function getDimensionsCount(array $array): int - { - // No elements? Nothing to do - if (empty($array)) { - return 0; - } - - $dimensionsCount = 1; - - foreach ($array as $value) { - if (is_array($value)) { - /* - * I have to increment returned value, because that means we've got 1 level more (if the value is an - * array) - */ - $count = self::getDimensionsCount($value) + 1; - - if ($count > $dimensionsCount) { - $dimensionsCount = $count; - } - } - } - - return $dimensionsCount; - } - - /** - * Returns non-empty values, e.g. without "" (empty string), null or [] - * - * @param array $values The values to filter - * @return null|array - */ - public static function getNonEmptyValues(array $values): ?array - { - // No values? Nothing to do - if (empty($values)) { - return null; - } - - return array_filter($values, static function ($value): bool { - $nonEmptyScalar = is_scalar($value) && '' !== $value; - $nonEmptyArray = self::isNotEmptyArray($value); - - return $nonEmptyScalar || $nonEmptyArray || is_object($value); - }); - } - - /** - * Returns non-empty values concatenated by given separator - * - * @param array $values The values to filter - * @param string $separator (optional) Separator used to implode the values. Default: ", ". - * @return null|string - */ - public static function getNonEmptyValuesAsString(array $values, string $separator = ', '): ?string - { - // No elements? Nothing to do - if (empty($values)) { - return null; - } - - $nonEmpty = self::getNonEmptyValues($values); - - // No values? Nothing to do - if (empty($nonEmpty)) { - return ''; - } - - return implode($separator, $nonEmpty); - } - - /** - * Returns information if given value is an array and is empty - * - * @param mixed $value The value to verify - * @return bool - */ - public static function isEmptyArray($value): bool - { - return is_array($value) && empty($value); - } - /** * Returns information if given value is non-empty array * @@ -1633,52 +1054,631 @@ class Arrays return is_array($value) && !empty($value); } - public static function containsEmptyStringsOnly(array $array): bool + /** + * Returns information if given path of keys are set is given array. + * The keys should be delivered in the same order as used by source array. + * + * @param array $array The array to check + * @param array $keys Keys, path of keys, to find in given array + * @return bool + * + * Examples: + * a) $array + * [ + * 'some key' => [ + * 'another some key' => [ + * 'yet another key' => 123, + * ], + * 'some different key' => 456, + * ] + * ] + * + * b) $keys + * [ + * 'some key', + * 'another some key', + * 'yet another key', + * ] + */ + public static function issetRecursive(array $array, array $keys) { + // No elements? Nothing to do if (empty($array)) { return false; } - return '' === trim(implode('', $array)); + $isset = false; + + foreach ($keys as $key) { + $isset = isset($array[$key]); + + if ($isset) { + $newArray = $array[$key]; + array_shift($keys); + + if (is_array($newArray) && !empty($keys)) { + $isset = self::issetRecursive($newArray, $keys); + } + } + + break; + } + + return $isset; } - public static function getElementsFromLevel(array $array, int $level, ?string $childrenKey = null): ?array + /** + * Applies ksort() function recursively in the given array + * + * @param array $array The array to sort + * @param int $sortFlags (optional) Options of ksort() function + * @return null|array + */ + public static function ksortRecursive(array &$array, $sortFlags = SORT_REGULAR) { - if (empty($array) || $level <= 0) { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $effect = &$array; + ksort($effect, $sortFlags); + + foreach ($effect as &$value) { + if (is_array($value)) { + ksort($value, $sortFlags); + } + } + + return $effect; + } + + /** + * Makes and returns an array for given variable + * + * @param mixed $variable Variable that should be an array + * @return array + */ + public static function makeArray($variable): array + { + if (is_array($variable)) { + return $variable; + } + + return [$variable]; + } + + /** + * Quotes (adds quotes) to elements that are strings and returns new array (with quoted elements) + * + * @param array $array The array to check for string values + * @return null|array + */ + public static function quoteStrings(array $array): ?array + { + // No elements? Nothing to do + if (empty($array)) { return null; } $result = []; - foreach ($array as $key => $value) { - // This is the expected level (the deepest). Comparing with 1, because level will be decreased by 1 (later), - // and finally we will get the latest/deepest level that equals 1. - if ($level === 1) { - // No key of children (next level) provided or this is the same key as processed? - // We've got the expected value - if ($childrenKey === null || $key === $childrenKey) { - $result[] = $value; + foreach ($array as $index => $value) { + if (is_array($value)) { + $value = self::quoteStrings($value); + } elseif (is_string($value) && !Regex::isQuoted($value)) { + $value = '\''.$value.'\''; + } + + $result[$index] = $value; + } + + return $result; + } + + /** + * Removes element / item of given array + * + * @param array $array The array that contains element / item which should be removed + * @param mixed $item The element / item which should be removed + * @return array|bool + */ + public static function removeElement(array $array, $item) + { + // No elements or the element does not exist? Nothing to do + if (empty($array) || !in_array($item, $array, true)) { + return false; + } + + // Flip the array to make it looks like: value => key + $arrayFlipped = array_flip($array); + + // Take the key of element / item that should be removed + $key = $arrayFlipped[$item]; + + // ...and remove the element / item + unset($array[$key]); + + return $array; + } + + /** + * Removes items from given array starting at given element (before or after the element) + * + * @param array $array The array which contains items to remove + * @param mixed $needle The element which is start point of deletion + * @param bool $before (optional) If is set to true, all elements before given needle are removed. Otherwise - all + * after needle. + */ + public static function removeElements(array &$array, $needle, $before = true): void + { + if (!empty($array)) { + if (!$before) { + $array = array_reverse($array, true); + } + + foreach ($array as $key => &$value) { + $remove = false; + $isArray = is_array($value); + + if ($isArray) { + self::removeElements($value, $needle, $before); + + if (empty($value)) { + $remove = true; + } + } elseif ($value === $needle) { + break; + } else { + $remove = true; } + if ($remove) { + unset($array[$key]); + } + } + + if (!$before) { + $array = array_reverse($array, true); + } + } + } + + /** + * Removes marginal element (first or last) from given array + * + * @param array $array The array which should be shortened + * @param bool $last (optional) If is set to true, last element is removed (default behaviour). Otherwise - first. + * @return null|array + */ + public static function removeMarginalElement(array $array, bool $last = true): ?array + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $key = self::getFirstKey($array); + + if ($last) { + $key = self::getLastKey($array); + } + + unset($array[$key]); + + return $array; + } + + /** + * Replaces array keys that match given pattern with new key name + * + * @param array $array Array which keys should be replaced + * @param string $oldKeyPattern Regular expression of the old key + * @param string $newKey Name of the new key + * @return null|array + */ + public static function replaceKeys(array $array, string $oldKeyPattern, string $newKey): ?array + { + if (empty($array)) { + return null; + } + + $effect = []; + + foreach ($array as $key => $value) { + if (preg_match($oldKeyPattern, $key)) { + $key = $newKey; + } + + if (is_array($value)) { + $value = self::replaceKeys($value, $oldKeyPattern, $newKey); + } + + $effect[$key] = $value; + } + + return $effect; + } + + /** + * Sets keys as values and values as keys in given array. + * Replaces keys with values. + * + * @param array $array The array to change values with keys + * @param bool $ignoreDuplicatedValues (optional) If is set to true, duplicated values are ignored. This means that + * when there is more than 1 value and that values become key, only the last + * value will be used with it's key, because other will be overridden. + * Otherwise - values are preserved and keys assigned to that values are + * returned as an array. + * @return null|array + * + * Example of $ignoreDuplicatedValues = false: + * - provided array + * $array = [ + * 'lorem' => 100, // <-- Duplicated value + * 'ipsum' => 200, + * 'dolor' => 100, // <-- Duplicated value + * ]; + * + * - result + * $replaced = [ + * 100 => [ + * 'lorem', // <-- Key of duplicated value + * 'dolor', // <-- Key of duplicated value + * ], + * 200 => 'ipsum', + * ]; + */ + public static function setKeysAsValues(array $array, $ignoreDuplicatedValues = true) + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $replaced = []; + + foreach ($array as $key => $value) { + /* + * The value it's an array? + * Let's replace keys with values in this array first + */ + if (is_array($value)) { + $replaced[$key] = self::setKeysAsValues($value, $ignoreDuplicatedValues); + continue; } - // There is no deeper level - if (!is_array($value)) { + // Duplicated values shouldn't be ignored and processed value is used as key already? + // Let's use an array and that will contain all values (to avoid ignoring / overriding duplicated values) + if (!$ignoreDuplicatedValues && isset($replaced[$value])) { + $existing = self::makeArray($replaced[$value]); + + $replaced[$value] = array_merge($existing, [ + $key, + ]); + continue; } - // Let's dive one level down/deeper - $elements = self::getElementsFromLevel($value, $level - 1, $childrenKey); + // Standard behaviour + $replaced[$value] = $key; + } + + return $replaced; + } + + /** + * Sets positions for each element / child of given array and returns the array + * + * Position for the 1st element / child of a parent is set to 1 and incremented for the next element and + * so on. Each parent is treated as separate array, so its elements are treated as positioned at 1st level. + * + * @param array $array The array which should has values of position for each element + * @param string $keyName (optional) Name of key which will contain the position value + * @param int $startPosition (optional) Default, start value of the position for main / given array, not the + * children + * @return null|array + */ + public static function setPositions(array $array, $keyName = self::POSITION_KEY_NAME, $startPosition = null) + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $childPosition = 1; + + if (null !== $startPosition) { + $array[$keyName] = $startPosition; + } + + foreach ($array as &$value) { + if (is_array($value)) { + $value = self::setPositions($value, $keyName, $childPosition); + ++$childPosition; + } + } + + return $array; + } + + /** + * Sorts an array by keys given in second array as values. + * Keys which are not in array with order are pushed after sorted elements. + * + * Example: + * - array to sort: + * + * array( + * 'lorem' => array( + * 'ipsum' + * ), + * 'dolor' => array( + * 'sit', + * 'amet' + * ), + * 'neque' => 'neque' + * ) + * + * - keys order: + * + * array( + * 'dolor', + * 'lorem' + * ) + * + * - the result: + * + * array( + * 'dolor' => array( + * 'sit', + * 'amet' + * ), + * 'lorem' => array( + * 'ipsum' + * ), + * 'neque' => 'neque' // <-- the rest, values of other keys + * ) + * + * + * @param array $array An array to sort + * @param array $keysOrder An array with keys of the 1st argument in proper / required order + * @return null|array + */ + public static function sortByCustomKeysOrder(array $array, array $keysOrder) + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $ordered = []; + + /* + * 1st iteration: + * Get elements in proper / required order + */ + if (!empty($keysOrder)) { + foreach ($keysOrder as $key) { + if (isset($array[$key])) { + $ordered[$key] = $array[$key]; + unset($array[$key]); + } + } + } + + /* + * 2nd iteration: + * Get the rest of elements + */ + if (!empty($array)) { + foreach ($array as $key => $element) { + $ordered[$key] = $element; + } + } + + return $ordered; + } + + /** + * Converts given string with special separators to array + * + * Example: + * ~ string: + * "light:jasny|dark:ciemny" + * + * ~ array as a result: + * [ + * 'light' => 'jasny', + * 'dark' => 'ciemny', + * ] + * + * @param string $string The string to be converted + * @param string $separator (optional) Separator used between name-value pairs in the string. + * Default: "|". + * @param string $valuesKeysSeparator (optional) Separator used between name and value in the string. Default: ":". + * @return null|array + */ + public static function string2array( + string $string, + string $separator = '|', + string $valuesKeysSeparator = ':' + ): ?array { + // Empty string? Nothing to do + if (empty($string)) { + return null; + } + + $array = []; + $exploded = explode($separator, $string); + + foreach ($exploded as $item) { + $exploded2 = explode($valuesKeysSeparator, $item); + + if (2 === count($exploded2)) { + $key = trim($exploded2[0]); + $value = trim($exploded2[1]); + + $array[$key] = $value; + } + } + + return $array; + } + + /** + * Trims string values of given array and returns the new array + * + * @param array $array The array which values should be trimmed + * @return array + */ + public static function trimRecursive(array $array) + { + // No elements? Nothing to do + if (empty($array)) { + return []; + } + + $result = []; + + foreach ($array as $key => $value) { + if (is_array($value)) { + $result[$key] = self::trimRecursive($value); - if ($elements === null) { continue; } - // I have to load each element separately to avoid issue with incorrectly nested values - foreach ($elements as $element) { - $result[] = $element; + if (is_string($value)) { + $value = trim($value); } + + $result[$key] = $value; + } + + return $result; + } + + /** + * Converts given array's rows to csv string + * + * @param array $array Data to be converted. It have to be an array that represents database table. + * @param string $separator (optional) Separator used between values. Default: ",". + * @return null|string + */ + public static function values2csv(array $array, string $separator = ','): ?string + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $rows = []; + $lineSeparator = "\n"; + + foreach ($array as $row) { + /* + * I have to use html_entity_decode() function here, because some string values can contain + * entities with semicolon and this can destroy the CSV column order. + */ + + if (is_array($row) && !empty($row)) { + foreach ($row as $key => $value) { + $row[$key] = html_entity_decode($value); + } + + $rows[] = implode($separator, $row); + } + } + + if (empty($rows)) { + return ''; + } + + return implode($lineSeparator, $rows); + } + + /** + * Converts given array's column to string. + * Recursive call is made for multi-dimensional arrays. + * + * @param array $array Data to be converted + * @param int|string $arrayColumnKey (optional) Column name. Default: "". + * @param string $separator (optional) Separator used between values. Default: ",". + * @return null|string + */ + public static function values2string(array $array, $arrayColumnKey = '', $separator = ',') + { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $values = []; + + foreach ($array as $key => $value) { + $appendMe = null; + + if (is_array($value)) { + $appendMe = self::values2string($value, $arrayColumnKey, $separator); + } elseif (empty($arrayColumnKey)) { + $appendMe = $value; + } elseif ($key === $arrayColumnKey) { + $appendMe = $array[$arrayColumnKey]; + } + + /* + * Part to append is unknown? + * Let's go to next part + */ + if (null === $appendMe) { + continue; + } + + $values[] = $appendMe; + } + + // No values found? Nothing to do + if (empty($values)) { + return null; + } + + return implode($separator, $values); + } + + /** + * Converts given array to string with keys, e.g. abc=1&def=2 or abc="1" def="2" + * + * @param array $array Data to be converted + * @param string $separator (optional) Separator used between name-value pairs. Default: ",". + * @param string $valuesKeysSeparator (optional) Separator used between name and value. Default: "=". + * @param string $valuesWrapper (optional) Wrapper used to wrap values, e.g. double-quote: key="value". + * Default: "". + * @return null|string + */ + public static function valuesKeys2string( + array $array, + $separator = ',', + $valuesKeysSeparator = '=', + $valuesWrapper = '' + ) { + // No elements? Nothing to do + if (empty($array)) { + return null; + } + + $result = ''; + + foreach ($array as $key => $value) { + if (!empty($result)) { + $result .= $separator; + } + + if (!empty($valuesWrapper)) { + $value = sprintf('%s%s%s', $valuesWrapper, $value, $valuesWrapper); + } + + $result .= $key.$valuesKeysSeparator.$value; } return $result; diff --git a/src/Utilities/Bootstrap4CssSelector.php b/src/Utilities/Bootstrap4CssSelector.php index 6933274..35d12d1 100644 --- a/src/Utilities/Bootstrap4CssSelector.php +++ b/src/Utilities/Bootstrap4CssSelector.php @@ -46,6 +46,23 @@ class Bootstrap4CssSelector return sprintf('%s %s', $labelSelector, $errorContainerSelector); } + /** + * Returns selector of field's group + * + * @param string $formName Name of form (value of the "name" attribute) + * @return string + */ + public static function getFieldGroupSelector($formName) + { + $formSelector = CssSelector::getFormByNameSelector($formName); + + if (empty($formSelector)) { + return ''; + } + + return sprintf('%s .form-group', $formSelector); + } + /** * Returns selector of radio-button's validation error * @@ -65,21 +82,4 @@ class Bootstrap4CssSelector return sprintf('%s legend.col-form-label %s', $fieldSetSelector, $errorContainerSelector); } - - /** - * Returns selector of field's group - * - * @param string $formName Name of form (value of the "name" attribute) - * @return string - */ - public static function getFieldGroupSelector($formName) - { - $formSelector = CssSelector::getFormByNameSelector($formName); - - if (empty($formSelector)) { - return ''; - } - - return sprintf('%s .form-group', $formSelector); - } } diff --git a/src/Utilities/Bundle.php b/src/Utilities/Bundle.php index b1ecb32..691787c 100644 --- a/src/Utilities/Bundle.php +++ b/src/Utilities/Bundle.php @@ -24,8 +24,8 @@ class Bundle * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template". Extension is not required. * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" * @param string $extension (optional) Extension of the view / template (default: "html.twig") - * @throws IncorrectBundleNameException * @return null|string + * @throws IncorrectBundleNameException */ public static function getBundleViewPath( string $viewPath, @@ -58,8 +58,8 @@ class Bundle * Returns short name of bundle (without "Bundle") * * @param string $fullBundleName Full name of the bundle, e.g. "MyExtraBundle" - * @throws IncorrectBundleNameException * @return null|string + * @throws IncorrectBundleNameException */ public static function getShortBundleName(string $fullBundleName): ?string { diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index 8ab59fb..0f501b0 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -63,127 +63,6 @@ class Date */ public const DATE_DIFFERENCE_UNIT_YEARS = 'years'; - /** - * Returns date's period (that contains start and end date) for given period - * - * @param string $period The period, type of period. One of DatePeriod class constants, e.g. DatePeriod::LAST_WEEK. - * @throws Exception - * @return null|DatePeriod - */ - public static function getDatesForPeriod(string $period): ?DatePeriod - { - /* - * Type of period is incorrect? - * Nothing to do - */ - if (!DatePeriod::isCorrectType($period)) { - return null; - } - - $dateStart = null; - $dateEnd = null; - - switch ($period) { - case DatePeriod::LAST_WEEK: - $thisWeekStart = new DateTime('this week'); - - $dateStart = clone $thisWeekStart; - $dateEnd = clone $thisWeekStart; - - $dateStart->sub(new DateInterval('P7D')); - $dateEnd->sub(new DateInterval('P1D')); - - break; - case DatePeriod::THIS_WEEK: - $dateStart = new DateTime('this week'); - - $dateEnd = clone $dateStart; - $dateEnd->add(new DateInterval('P6D')); - - break; - case DatePeriod::NEXT_WEEK: - $dateStart = new DateTime('this week'); - $dateStart->add(new DateInterval('P7D')); - - $dateEnd = clone $dateStart; - $dateEnd->add(new DateInterval('P6D')); - - break; - case DatePeriod::LAST_MONTH: - $dateStart = new DateTime('first day of last month'); - $dateEnd = new DateTime('last day of last month'); - - break; - case DatePeriod::THIS_MONTH: - $lastMonth = self::getDatesForPeriod(DatePeriod::LAST_MONTH); - $nextMonth = self::getDatesForPeriod(DatePeriod::NEXT_MONTH); - - if (null !== $lastMonth) { - $dateStart = $lastMonth->getEndDate(); - - if (null !== $dateStart) { - $dateStart->add(new DateInterval('P1D')); - } - } - - if (null !== $nextMonth) { - $dateEnd = $nextMonth->getStartDate(); - - if (null !== $dateEnd) { - $dateEnd->sub(new DateInterval('P1D')); - } - } - - break; - case DatePeriod::NEXT_MONTH: - $dateStart = new DateTime('first day of next month'); - $dateEnd = new DateTime('last day of next month'); - - break; - case DatePeriod::LAST_YEAR: - case DatePeriod::THIS_YEAR: - case DatePeriod::NEXT_YEAR: - $dateStart = new DateTime(); - $dateEnd = new DateTime(); - - $yearPeriod = [ - DatePeriod::LAST_YEAR, - DatePeriod::NEXT_YEAR, - ]; - - if (in_array($period, $yearPeriod, true)) { - $yearDifference = 1; - - if (DatePeriod::LAST_YEAR === $period) { - $yearDifference *= -1; - } - - $modifyString = sprintf('%s year', $yearDifference); - $dateStart->modify($modifyString); - $dateEnd->modify($modifyString); - } - - $year = (int)$dateStart->format('Y'); - $dateStart->setDate($year, 1, 1); - $dateEnd->setDate($year, 12, 31); - - break; - } - - /* - * Start or end date is unknown? - * Nothing to do - */ - if (null === $dateStart || null === $dateEnd) { - return null; - } - - $dateStart->setTime(0, 0); - $dateEnd->setTime(23, 59, 59); - - return new DatePeriod($dateStart, $dateEnd); - } - /** * Generates and returns random time (the hour, minute and second values) * @@ -227,7 +106,7 @@ class Date return $dateTime ->setTime($hour, $minute, $second) ->format($format) - ; + ; } /** @@ -239,46 +118,13 @@ class Date { $now = new DateTime(); - $year = (int)$now->format('Y'); - $month = (int)$now->format('m'); - $day = (int)$now->format('d'); + $year = (int) $now->format('Y'); + $month = (int) $now->format('m'); + $day = (int) $now->format('d'); return self::getDayOfWeek($year, $month, $day); } - /** - * Returns day of week (number 0 to 6, 0 - sunday, 6 - saturday). - * Based on the Zeller's algorithm (https://en.wikipedia.org/wiki/Perpetual_calendar). - * - * @param int $year The year value - * @param int $month The month value - * @param int $day The day value - * - * @throws UnknownDatePartTypeException - * @return int - */ - public static function getDayOfWeek(int $year, int $month, int $day): int - { - static::validateYear($year); - static::validateMonth($month); - static::validateDay($day); - - if ($month < 3) { - $count = 0; - $yearValue = $year - 1; - } else { - $count = 2; - $yearValue = $year; - } - - $firstPart = floor(23 * $month / 9); - $secondPart = floor($yearValue / 4); - $thirdPart = floor($yearValue / 100); - $fourthPart = floor($yearValue / 400); - - return ($firstPart + $day + 4 + $year + $secondPart - $thirdPart + $fourthPart - $count) % 7; - } - /** * Returns based on locale name of current weekday * @@ -288,39 +134,13 @@ class Date { $now = new DateTime(); - $year = (int)$now->format('Y'); - $month = (int)$now->format('m'); - $day = (int)$now->format('d'); + $year = (int) $now->format('Y'); + $month = (int) $now->format('m'); + $day = (int) $now->format('d'); return self::getDayOfWeekName($year, $month, $day); } - /** - * Returns name of weekday based on locale - * - * @param int $year The year value - * @param int $month The month value - * @param int $day The day value - * @return string - */ - public static function getDayOfWeekName($year, $month, $day): string - { - $hour = 0; - $minute = 0; - $second = 0; - - $time = mktime($hour, $minute, $second, $month, $day, $year); - $name = strftime('%A', $time); - - $encoding = mb_detect_encoding($name); - - if (false === $encoding) { - $name = mb_convert_encoding($name, 'UTF-8', 'ISO-8859-2'); - } - - return $name; - } - /** * Returns difference between given dates. * @@ -408,7 +228,7 @@ class Date } if (null === $differenceUnit || in_array($differenceUnit, $relatedUnits, true)) { - $days = (int)floor($dateDiff / $daySeconds); + $days = (int) floor($dateDiff / $daySeconds); // Difference between dates in days should be returned only? if (self::DATE_DIFFERENCE_UNIT_DAYS === $differenceUnit) { @@ -425,7 +245,7 @@ class Date } if (null === $differenceUnit || in_array($differenceUnit, $relatedUnits, true)) { - $hours = (int)floor(($dateDiff - $daysInSeconds) / $hourSeconds); + $hours = (int) floor(($dateDiff - $daysInSeconds) / $hourSeconds); // Difference between dates in hours should be returned only? if (self::DATE_DIFFERENCE_UNIT_HOURS === $differenceUnit) { @@ -442,7 +262,7 @@ class Date } if (null === $differenceUnit || $differenceMinutes) { - $minutes = (int)floor(($dateDiff - $daysInSeconds - $hoursInSeconds) / 60); + $minutes = (int) floor(($dateDiff - $daysInSeconds - $hoursInSeconds) / 60); // Difference between dates in minutes should be returned only? if ($differenceMinutes) { @@ -455,95 +275,6 @@ class Date return $difference; } - /** - * Returns collection / set of dates for given start date and count of dates. - * Start from given date, add next, iterated value to given date interval and returns requested count of dates. - * - * @param DateTime $startDate The start date. Start of the collection / set. - * @param int $datesCount Count of dates in resulting collection / set - * @param string $intervalTemplate (optional) Template used to build date interval. It should contain "%d" as the - * placeholder which is replaced with a number that represents each iteration. - * Default: interval for days. - * @throws Exception - * @return array - */ - public static function getDatesCollection(DateTime $startDate, $datesCount, $intervalTemplate = 'P%dD'): array - { - $dates = []; - - /* - * The template used to build date interval have to be string. - * Otherwise cannot run preg_match() function and an error occurs. - */ - if (is_string($intervalTemplate)) { - /* - * Let's verify the interval template. It should contains the "%d" placeholder and something before and - * after it. - * - * Examples: - * - P%dD - * - P%dM - * - P1Y%dMT1H - */ - $intervalPattern = '/^(\w*)\%d(\w*)$/'; - $matches = []; - $matchCount = preg_match($intervalPattern, $intervalTemplate, $matches); - - if ($matchCount > 0 && (!empty($matches[1]) || !empty($matches[2]))) { - $datesCount = (int)$datesCount; - - for ($index = 1; $index <= $datesCount; ++$index) { - $date = clone $startDate; - $dates[$index] = $date->add(new DateInterval(sprintf($intervalTemplate, $index))); - } - } - } - - return $dates; - } - - /** - * Returns random date based on given start date - * - * @param DateTime $startDate (optional) Beginning of the random date. If not provided, current date will - * be used (default behaviour). - * @param int $start (optional) Start of random partition. If not provided, 1 will be used - * (default behaviour). - * @param int $end (optional) End of random partition. If not provided, 100 will be used - * (default behaviour). - * @param string $intervalTemplate (optional) Template used to build date interval. The placeholder is replaced - * with next, iterated value. If not provided, "P%sD" will be used (default - * behaviour). - * @throws Exception - * @return DateTime - */ - public static function getRandomDate( - DateTime $startDate = null, - $start = 1, - $end = 100, - $intervalTemplate = 'P%sD' - ): DateTime { - if (null === $startDate) { - $startDate = new DateTime(); - } - - $start = (int)$start; - $end = (int)$end; - - /* - * Incorrect end of random partition? - * Use start as the end of random partition - */ - if ($end < $start) { - $end = $start; - } - - $randomDate = clone $startDate; - $randomInterval = new DateInterval(sprintf($intervalTemplate, random_int($start, $end))); - - return $randomDate->add($randomInterval); - } - /** * Returns the DateTime object for given value. * If the DateTime object cannot be created, false is returned. @@ -646,7 +377,7 @@ class Date */ $dateString = (new DateTime())->format($value); - if ($dateString !== (string)$value) { + if ($dateString !== (string) $value) { return new DateTime($dateString); } } catch (Exception $exception) { @@ -655,6 +386,275 @@ class Date return false; } + /** + * Returns collection / set of dates for given start date and count of dates. + * Start from given date, add next, iterated value to given date interval and returns requested count of dates. + * + * @param DateTime $startDate The start date. Start of the collection / set. + * @param int $datesCount Count of dates in resulting collection / set + * @param string $intervalTemplate (optional) Template used to build date interval. It should contain "%d" as the + * placeholder which is replaced with a number that represents each iteration. + * Default: interval for days. + * @return array + * @throws Exception + */ + public static function getDatesCollection(DateTime $startDate, $datesCount, $intervalTemplate = 'P%dD'): array + { + $dates = []; + + /* + * The template used to build date interval have to be string. + * Otherwise cannot run preg_match() function and an error occurs. + */ + if (is_string($intervalTemplate)) { + /* + * Let's verify the interval template. It should contains the "%d" placeholder and something before and + * after it. + * + * Examples: + * - P%dD + * - P%dM + * - P1Y%dMT1H + */ + $intervalPattern = '/^(\w*)\%d(\w*)$/'; + $matches = []; + $matchCount = preg_match($intervalPattern, $intervalTemplate, $matches); + + if ($matchCount > 0 && (!empty($matches[1]) || !empty($matches[2]))) { + $datesCount = (int) $datesCount; + + for ($index = 1; $index <= $datesCount; ++$index) { + $date = clone $startDate; + $dates[$index] = $date->add(new DateInterval(sprintf($intervalTemplate, $index))); + } + } + } + + return $dates; + } + + /** + * Returns date's period (that contains start and end date) for given period + * + * @param string $period The period, type of period. One of DatePeriod class constants, e.g. DatePeriod::LAST_WEEK. + * @return null|DatePeriod + * @throws Exception + */ + public static function getDatesForPeriod(string $period): ?DatePeriod + { + /* + * Type of period is incorrect? + * Nothing to do + */ + if (!DatePeriod::isCorrectType($period)) { + return null; + } + + $dateStart = null; + $dateEnd = null; + + switch ($period) { + case DatePeriod::LAST_WEEK: + $thisWeekStart = new DateTime('this week'); + + $dateStart = clone $thisWeekStart; + $dateEnd = clone $thisWeekStart; + + $dateStart->sub(new DateInterval('P7D')); + $dateEnd->sub(new DateInterval('P1D')); + + break; + case DatePeriod::THIS_WEEK: + $dateStart = new DateTime('this week'); + + $dateEnd = clone $dateStart; + $dateEnd->add(new DateInterval('P6D')); + + break; + case DatePeriod::NEXT_WEEK: + $dateStart = new DateTime('this week'); + $dateStart->add(new DateInterval('P7D')); + + $dateEnd = clone $dateStart; + $dateEnd->add(new DateInterval('P6D')); + + break; + case DatePeriod::LAST_MONTH: + $dateStart = new DateTime('first day of last month'); + $dateEnd = new DateTime('last day of last month'); + + break; + case DatePeriod::THIS_MONTH: + $lastMonth = self::getDatesForPeriod(DatePeriod::LAST_MONTH); + $nextMonth = self::getDatesForPeriod(DatePeriod::NEXT_MONTH); + + if (null !== $lastMonth) { + $dateStart = $lastMonth->getEndDate(); + + if (null !== $dateStart) { + $dateStart->add(new DateInterval('P1D')); + } + } + + if (null !== $nextMonth) { + $dateEnd = $nextMonth->getStartDate(); + + if (null !== $dateEnd) { + $dateEnd->sub(new DateInterval('P1D')); + } + } + + break; + case DatePeriod::NEXT_MONTH: + $dateStart = new DateTime('first day of next month'); + $dateEnd = new DateTime('last day of next month'); + + break; + case DatePeriod::LAST_YEAR: + case DatePeriod::THIS_YEAR: + case DatePeriod::NEXT_YEAR: + $dateStart = new DateTime(); + $dateEnd = new DateTime(); + + $yearPeriod = [ + DatePeriod::LAST_YEAR, + DatePeriod::NEXT_YEAR, + ]; + + if (in_array($period, $yearPeriod, true)) { + $yearDifference = 1; + + if (DatePeriod::LAST_YEAR === $period) { + $yearDifference *= -1; + } + + $modifyString = sprintf('%s year', $yearDifference); + $dateStart->modify($modifyString); + $dateEnd->modify($modifyString); + } + + $year = (int) $dateStart->format('Y'); + $dateStart->setDate($year, 1, 1); + $dateEnd->setDate($year, 12, 31); + + break; + } + + /* + * Start or end date is unknown? + * Nothing to do + */ + if (null === $dateStart || null === $dateEnd) { + return null; + } + + $dateStart->setTime(0, 0); + $dateEnd->setTime(23, 59, 59); + + return new DatePeriod($dateStart, $dateEnd); + } + + /** + * Returns day of week (number 0 to 6, 0 - sunday, 6 - saturday). + * Based on the Zeller's algorithm (https://en.wikipedia.org/wiki/Perpetual_calendar). + * + * @param int $year The year value + * @param int $month The month value + * @param int $day The day value + * + * @return int + * @throws UnknownDatePartTypeException + */ + public static function getDayOfWeek(int $year, int $month, int $day): int + { + static::validateYear($year); + static::validateMonth($month); + static::validateDay($day); + + if ($month < 3) { + $count = 0; + $yearValue = $year - 1; + } else { + $count = 2; + $yearValue = $year; + } + + $firstPart = floor(23 * $month / 9); + $secondPart = floor($yearValue / 4); + $thirdPart = floor($yearValue / 100); + $fourthPart = floor($yearValue / 400); + + return ($firstPart + $day + 4 + $year + $secondPart - $thirdPart + $fourthPart - $count) % 7; + } + + /** + * Returns name of weekday based on locale + * + * @param int $year The year value + * @param int $month The month value + * @param int $day The day value + * @return string + */ + public static function getDayOfWeekName($year, $month, $day): string + { + $hour = 0; + $minute = 0; + $second = 0; + + $time = mktime($hour, $minute, $second, $month, $day, $year); + $name = strftime('%A', $time); + + $encoding = mb_detect_encoding($name); + + if (false === $encoding) { + $name = mb_convert_encoding($name, 'UTF-8', 'ISO-8859-2'); + } + + return $name; + } + + /** + * Returns random date based on given start date + * + * @param DateTime $startDate (optional) Beginning of the random date. If not provided, current date will + * be used (default behaviour). + * @param int $start (optional) Start of random partition. If not provided, 1 will be used + * (default behaviour). + * @param int $end (optional) End of random partition. If not provided, 100 will be used + * (default behaviour). + * @param string $intervalTemplate (optional) Template used to build date interval. The placeholder is replaced + * with next, iterated value. If not provided, "P%sD" will be used (default + * behaviour). + * @return DateTime + * @throws Exception + */ + public static function getRandomDate( + DateTime $startDate = null, + $start = 1, + $end = 100, + $intervalTemplate = 'P%sD' + ): DateTime { + if (null === $startDate) { + $startDate = new DateTime(); + } + + $start = (int) $start; + $end = (int) $end; + + /* + * Incorrect end of random partition? + * Use start as the end of random partition + */ + if ($end < $start) { + $end = $start; + } + + $randomDate = clone $startDate; + $randomInterval = new DateInterval(sprintf($intervalTemplate, random_int($start, $end))); + + return $randomDate->add($randomInterval); + } + /** * Returns information if given value is valid date * @@ -702,19 +702,19 @@ class Date } /** - * Verifies/validates given year + * Verifies/validates given day * - * @param int $year Year to verify/validate + * @param int $day Day to verify/validate * @throws UnknownDatePartTypeException */ - private static function validateYear(int $year): void + private static function validateDay(int $day): void { - // Oops, given year is incorrect - if ($year >= 0) { + // Oops, given day is incorrect + if ($day >= 1 && $day <= 31) { return; } - throw UnknownDatePartTypeException::createException(DatePartType::YEAR, $year); + throw UnknownDatePartTypeException::createException(DatePartType::DAY, $day); } /** @@ -734,18 +734,18 @@ class Date } /** - * Verifies/validates given day + * Verifies/validates given year * - * @param int $day Day to verify/validate + * @param int $year Year to verify/validate * @throws UnknownDatePartTypeException */ - private static function validateDay(int $day): void + private static function validateYear(int $year): void { - // Oops, given day is incorrect - if ($day >= 1 && $day <= 31) { + // Oops, given year is incorrect + if ($year >= 0) { return; } - throw UnknownDatePartTypeException::createException(DatePartType::DAY, $day); + throw UnknownDatePartTypeException::createException(DatePartType::YEAR, $year); } } diff --git a/src/Utilities/Locale.php b/src/Utilities/Locale.php index 770c01b..b7f7787 100644 --- a/src/Utilities/Locale.php +++ b/src/Utilities/Locale.php @@ -16,51 +16,6 @@ namespace Meritoo\Common\Utilities; */ class Locale { - /** - * Sets locale for given category using given language and country code - * - * @param int $category Named constant specifying the category of the functions affected by the locale - * setting. It's the same constant as required by setlocale() function. - * @param string $languageCode Language code, in ISO 639-1 format. Short form of the locale, e.g. "fr". - * @param string $countryCode (optional) Country code, in ISO 3166-1 alpha-2 format, e.g. "FR" - * @return false|string - * - * Available categories (values of $category argument): - * - LC_ALL for all of the below - * - LC_COLLATE for string comparison, see strcoll() - * - LC_CTYPE for character classification and conversion, for example strtoupper() - * - LC_MONETARY for localeconv() - * - LC_NUMERIC for decimal separator (See also localeconv()) - * - LC_TIME for date and time formatting with strftime() - * - LC_MESSAGES for system responses (available if PHP was compiled with libintl) - */ - public static function setLocale($category, $languageCode, $countryCode = '') - { - $category = (int)$category; - - if (is_string($languageCode)) { - $languageCode = trim($languageCode); - } - - $availableCategories = [ - LC_ALL, - LC_COLLATE, - LC_CTYPE, - LC_MONETARY, - LC_NUMERIC, - LC_TIME, - LC_MESSAGES, - ]; - - if (empty($languageCode) || !in_array($category, $availableCategories, true)) { - return false; - } - - $localeLongForm = self::getLongForm($languageCode, $countryCode); - - return setlocale($category, $localeLongForm); - } - /** * Returns locale for given category * @@ -123,4 +78,49 @@ class Locale return sprintf('%s_%s%s', $languageCode, strtoupper($countryCode), $encoding); } + + /** + * Sets locale for given category using given language and country code + * + * @param int $category Named constant specifying the category of the functions affected by the locale + * setting. It's the same constant as required by setlocale() function. + * @param string $languageCode Language code, in ISO 639-1 format. Short form of the locale, e.g. "fr". + * @param string $countryCode (optional) Country code, in ISO 3166-1 alpha-2 format, e.g. "FR" + * @return false|string + * + * Available categories (values of $category argument): + * - LC_ALL for all of the below + * - LC_COLLATE for string comparison, see strcoll() + * - LC_CTYPE for character classification and conversion, for example strtoupper() + * - LC_MONETARY for localeconv() + * - LC_NUMERIC for decimal separator (See also localeconv()) + * - LC_TIME for date and time formatting with strftime() + * - LC_MESSAGES for system responses (available if PHP was compiled with libintl) + */ + public static function setLocale($category, $languageCode, $countryCode = '') + { + $category = (int) $category; + + if (is_string($languageCode)) { + $languageCode = trim($languageCode); + } + + $availableCategories = [ + LC_ALL, + LC_COLLATE, + LC_CTYPE, + LC_MONETARY, + LC_NUMERIC, + LC_TIME, + LC_MESSAGES, + ]; + + if (empty($languageCode) || !in_array($category, $availableCategories, true)) { + return false; + } + + $localeLongForm = self::getLongForm($languageCode, $countryCode); + + return setlocale($category, $localeLongForm); + } } diff --git a/src/Utilities/MimeTypes.php b/src/Utilities/MimeTypes.php index 9b61023..f300738 100644 --- a/src/Utilities/MimeTypes.php +++ b/src/Utilities/MimeTypes.php @@ -8,6 +8,9 @@ namespace Meritoo\Common\Utilities; +use finfo; +use RuntimeException; + /** * Useful methods for mime types of files * @@ -22,663 +25,680 @@ class MimeTypes * @var array */ private static $mimeTypes = [ - '7z' => 'application/x-7z-compressed', - 'ez' => 'application/andrew-inset', - 'atom' => 'application/atom+xml', - 'atomcat' => 'application/atomcat+xml', - 'atomsvc' => 'application/atomsvc+xml', - 'ccxml' => 'application/ccxml+xml', - 'davmount' => 'application/davmount+xml', - 'ecma' => 'application/ecmascript', - 'pfr' => 'application/font-tdpfr', - 'stk' => 'application/hyperstudio', - 'js' => 'application/javascript', - 'json' => 'application/json', - 'hqx' => 'application/mac-binhex40', - 'cpt' => 'application/mac-compactpro', - 'mrc' => 'application/marc', - 'ma' => 'application/mathematica', - 'nb' => 'application/mathematica', - 'mb' => 'application/mathematica', - 'mathml' => 'application/mathml+xml', - 'mbox' => 'application/mbox', - 'mscml' => 'application/mediaservercontrol+xml', - 'mp4s' => 'application/mp4', - 'dot' => 'application/msword', - 'doc' => 'application/msword', + '7z' => 'application/x-7z-compressed', + 'ez' => 'application/andrew-inset', + 'atom' => 'application/atom+xml', + 'atomcat' => 'application/atomcat+xml', + 'atomsvc' => 'application/atomsvc+xml', + 'ccxml' => 'application/ccxml+xml', + 'davmount' => 'application/davmount+xml', + 'ecma' => 'application/ecmascript', + 'pfr' => 'application/font-tdpfr', + 'stk' => 'application/hyperstudio', + 'js' => 'application/javascript', + 'json' => 'application/json', + 'hqx' => 'application/mac-binhex40', + 'cpt' => 'application/mac-compactpro', + 'mrc' => 'application/marc', + 'ma' => 'application/mathematica', + 'nb' => 'application/mathematica', + 'mb' => 'application/mathematica', + 'mathml' => 'application/mathml+xml', + 'mbox' => 'application/mbox', + 'mscml' => 'application/mediaservercontrol+xml', + 'mp4s' => 'application/mp4', + 'dot' => 'application/msword', + 'doc' => 'application/msword', /* * MS Office system file format MIME types * http://technet.microsoft.com/en-us/library/ee309278%28office.12%29.aspx */ - 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'mxf' => 'application/mxf', - 'bin' => 'application/octet-stream', - 'dms' => 'application/octet-stream', - 'lha' => 'application/octet-stream', - 'lzh' => 'application/octet-stream', - 'class' => 'application/octet-stream', - 'so' => 'application/octet-stream', - 'iso' => 'application/octet-stream', - 'dmg' => 'application/octet-stream', - 'dist' => 'application/octet-stream', - 'distz' => 'application/octet-stream', - 'pkg' => 'application/octet-stream', - 'bpk' => 'application/octet-stream', - 'dump' => 'application/octet-stream', - 'elc' => 'application/octet-stream', - 'scpt' => 'application/octet-stream', - 'oda' => 'application/oda', - 'ogg' => 'application/ogg', - 'pdf' => 'application/pdf', - 'pgp' => 'application/pgp-encrypted', - 'asc' => 'application/pgp-signature', - 'sig' => 'application/pgp-signature', - 'prf' => 'application/pics-rules', - 'p10' => 'application/pkcs10', - 'p7m' => 'application/pkcs7-mime', - 'p7c' => 'application/pkcs7-mime', - 'p7s' => 'application/pkcs7-signature', - 'cer' => 'application/pkix-cert', - 'crl' => 'application/pkix-crl', - 'pkipath' => 'application/pkix-pkipath', - 'pki' => 'application/pkixcmp', - 'pls' => 'application/pls+xml', - 'ai' => 'application/postscript', - 'eps' => 'application/postscript', - 'ps' => 'application/postscript', - 'cww' => 'application/prs.cww', - 'rdf' => 'application/rdf+xml', - 'rif' => 'application/reginfo+xml', - 'rnc' => 'application/relax-ng-compact-syntax', - 'rl' => 'application/resource-lists+xml', - 'rs' => 'application/rls-services+xml', - 'rsd' => 'application/rsd+xml', - 'rss' => 'application/rss+xml', - 'rtf' => 'application/rtf', - 'sbml' => 'application/sbml+xml', - 'sdp' => 'application/sdp', - 'setpay' => 'application/set-payment-initiation', - 'setreg' => 'application/set-registration-initiation', - 'shf' => 'application/shf+xml', - 'smi' => 'application/smil+xml', - 'smil' => 'application/smil+xml', - 'gram' => 'application/srgs', - 'grxml' => 'application/srgs+xml', - 'ssml' => 'application/ssml+xml', - 'plb' => 'application/vnd.3gpp.pic-bw-large', - 'psb' => 'application/vnd.3gpp.pic-bw-small', - 'pvb' => 'application/vnd.3gpp.pic-bw-var', - 'pwn' => 'application/vnd.3m.post-it-notes', - 'aso' => 'application/vnd.accpac.simply.aso', - 'imp' => 'application/vnd.accpac.simply.imp', - 'acu' => 'application/vnd.acucobol', - 'atc' => 'application/vnd.acucorp', - 'acutc' => 'application/vnd.acucorp', - 'xdp' => 'application/vnd.adobe.xdp+xml', - 'xfdf' => 'application/vnd.adobe.xfdf', - 'ami' => 'application/vnd.amiga.ami', - 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', - 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', - 'atx' => 'application/vnd.antix.game-component', - 'mpkg' => 'application/vnd.apple.installer+xml', - 'aep' => 'application/vnd.audiograph', - 'mpm' => 'application/vnd.blueice.multipass', - 'bmi' => 'application/vnd.bmi', - 'rep' => 'application/vnd.businessobjects', - 'cdxml' => 'application/vnd.chemdraw+xml', - 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', - 'cdy' => 'application/vnd.cinderella', - 'cla' => 'application/vnd.claymore', - 'c4g' => 'application/vnd.clonk.c4group', - 'c4d' => 'application/vnd.clonk.c4group', - 'c4f' => 'application/vnd.clonk.c4group', - 'c4p' => 'application/vnd.clonk.c4group', - 'c4u' => 'application/vnd.clonk.c4group', - 'csp' => 'application/vnd.commonspace', - 'cst' => 'application/vnd.commonspace', - 'cdbcmsg' => 'application/vnd.contact.cmsg', - 'cmc' => 'application/vnd.cosmocaller', - 'clkx' => 'application/vnd.crick.clicker', - 'clkk' => 'application/vnd.crick.clicker.keyboard', - 'clkp' => 'application/vnd.crick.clicker.palette', - 'clkt' => 'application/vnd.crick.clicker.template', - 'clkw' => 'application/vnd.crick.clicker.wordbank', - 'wbs' => 'application/vnd.criticaltools.wbs+xml', - 'pml' => 'application/vnd.ctc-posml', - 'ppd' => 'application/vnd.cups-ppd', - 'curl' => 'application/vnd.curl', - 'rdz' => 'application/vnd.data-vision.rdz', - 'dna' => 'application/vnd.dna', - 'mlp' => 'application/vnd.dolby.mlp', - 'dpg' => 'application/vnd.dpgraph', - 'dfac' => 'application/vnd.dreamfactory', - 'mag' => 'application/vnd.ecowin.chart', - 'nml' => 'application/vnd.enliven', - 'esf' => 'application/vnd.epson.esf', - 'msf' => 'application/vnd.epson.msf', - 'qam' => 'application/vnd.epson.quickanime', - 'slt' => 'application/vnd.epson.salt', - 'ssf' => 'application/vnd.epson.ssf', - 'es3' => 'application/vnd.eszigno3+xml', - 'et3' => 'application/vnd.eszigno3+xml', - 'ez2' => 'application/vnd.ezpix-album', - 'ez3' => 'application/vnd.ezpix-package', - 'fdf' => 'application/vnd.fdf', - 'gph' => 'application/vnd.flographit', - 'ftc' => 'application/vnd.fluxtime.clip', - 'fm' => 'application/vnd.framemaker', - 'frame' => 'application/vnd.framemaker', - 'maker' => 'application/vnd.framemaker', - 'fnc' => 'application/vnd.frogans.fnc', - 'ltf' => 'application/vnd.frogans.ltf', - 'fsc' => 'application/vnd.fsc.weblaunch', - 'oas' => 'application/vnd.fujitsu.oasys', - 'oa2' => 'application/vnd.fujitsu.oasys2', - 'oa3' => 'application/vnd.fujitsu.oasys3', - 'fg5' => 'application/vnd.fujitsu.oasysgp', - 'bh2' => 'application/vnd.fujitsu.oasysprs', - 'ddd' => 'application/vnd.fujixerox.ddd', - 'xdw' => 'application/vnd.fujixerox.docuworks', - 'xbd' => 'application/vnd.fujixerox.docuworks.binder', - 'fzs' => 'application/vnd.fuzzysheet', - 'txd' => 'application/vnd.genomatix.tuxedo', - 'kml' => 'application/vnd.google-earth.kml+xml', - 'kmz' => 'application/vnd.google-earth.kmz', - 'gqf' => 'application/vnd.grafeq', - 'gqs' => 'application/vnd.grafeq', - 'gac' => 'application/vnd.groove-account', - 'ghf' => 'application/vnd.groove-help', - 'gim' => 'application/vnd.groove-identity-message', - 'grv' => 'application/vnd.groove-injector', - 'gtm' => 'application/vnd.groove-tool-message', - 'tpl' => 'application/vnd.groove-tool-template', - 'vcg' => 'application/vnd.groove-vcard', - 'zmm' => 'application/vnd.handheld-entertainment+xml', - 'hbci' => 'application/vnd.hbci', - 'les' => 'application/vnd.hhe.lesson-player', - 'hpgl' => 'application/vnd.hp-hpgl', - 'hpid' => 'application/vnd.hp-hpid', - 'hps' => 'application/vnd.hp-hps', - 'jlt' => 'application/vnd.hp-jlyt', - 'pcl' => 'application/vnd.hp-pcl', - 'pclxl' => 'application/vnd.hp-pclxl', - 'x3d' => 'application/vnd.hzn-3d-crossword', - 'mpy' => 'application/vnd.ibm.minipay', - 'afp' => 'application/vnd.ibm.modcap', - 'listafp' => 'application/vnd.ibm.modcap', - 'list3820' => 'application/vnd.ibm.modcap', - 'irm' => 'application/vnd.ibm.rights-management', - 'sc' => 'application/vnd.ibm.secure-container', - 'igl' => 'application/vnd.igloader', - 'ivp' => 'application/vnd.immervision-ivp', - 'ivu' => 'application/vnd.immervision-ivu', - 'xpw' => 'application/vnd.intercon.formnet', - 'xpx' => 'application/vnd.intercon.formnet', - 'qbo' => 'application/vnd.intu.qbo', - 'qfx' => 'application/vnd.intu.qfx', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'mxf' => 'application/mxf', + 'bin' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'class' => 'application/octet-stream', + 'so' => 'application/octet-stream', + 'iso' => 'application/octet-stream', + 'dmg' => 'application/octet-stream', + 'dist' => 'application/octet-stream', + 'distz' => 'application/octet-stream', + 'pkg' => 'application/octet-stream', + 'bpk' => 'application/octet-stream', + 'dump' => 'application/octet-stream', + 'elc' => 'application/octet-stream', + 'scpt' => 'application/octet-stream', + 'oda' => 'application/oda', + 'ogg' => 'application/ogg', + 'pdf' => 'application/pdf', + 'pgp' => 'application/pgp-encrypted', + 'asc' => 'application/pgp-signature', + 'sig' => 'application/pgp-signature', + 'prf' => 'application/pics-rules', + 'p10' => 'application/pkcs10', + 'p7m' => 'application/pkcs7-mime', + 'p7c' => 'application/pkcs7-mime', + 'p7s' => 'application/pkcs7-signature', + 'cer' => 'application/pkix-cert', + 'crl' => 'application/pkix-crl', + 'pkipath' => 'application/pkix-pkipath', + 'pki' => 'application/pkixcmp', + 'pls' => 'application/pls+xml', + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'cww' => 'application/prs.cww', + 'rdf' => 'application/rdf+xml', + 'rif' => 'application/reginfo+xml', + 'rnc' => 'application/relax-ng-compact-syntax', + 'rl' => 'application/resource-lists+xml', + 'rs' => 'application/rls-services+xml', + 'rsd' => 'application/rsd+xml', + 'rss' => 'application/rss+xml', + 'rtf' => 'application/rtf', + 'sbml' => 'application/sbml+xml', + 'sdp' => 'application/sdp', + 'setpay' => 'application/set-payment-initiation', + 'setreg' => 'application/set-registration-initiation', + 'shf' => 'application/shf+xml', + 'smi' => 'application/smil+xml', + 'smil' => 'application/smil+xml', + 'gram' => 'application/srgs', + 'grxml' => 'application/srgs+xml', + 'ssml' => 'application/ssml+xml', + 'plb' => 'application/vnd.3gpp.pic-bw-large', + 'psb' => 'application/vnd.3gpp.pic-bw-small', + 'pvb' => 'application/vnd.3gpp.pic-bw-var', + 'pwn' => 'application/vnd.3m.post-it-notes', + 'aso' => 'application/vnd.accpac.simply.aso', + 'imp' => 'application/vnd.accpac.simply.imp', + 'acu' => 'application/vnd.acucobol', + 'atc' => 'application/vnd.acucorp', + 'acutc' => 'application/vnd.acucorp', + 'xdp' => 'application/vnd.adobe.xdp+xml', + 'xfdf' => 'application/vnd.adobe.xfdf', + 'ami' => 'application/vnd.amiga.ami', + 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', + 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', + 'atx' => 'application/vnd.antix.game-component', + 'mpkg' => 'application/vnd.apple.installer+xml', + 'aep' => 'application/vnd.audiograph', + 'mpm' => 'application/vnd.blueice.multipass', + 'bmi' => 'application/vnd.bmi', + 'rep' => 'application/vnd.businessobjects', + 'cdxml' => 'application/vnd.chemdraw+xml', + 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', + 'cdy' => 'application/vnd.cinderella', + 'cla' => 'application/vnd.claymore', + 'c4g' => 'application/vnd.clonk.c4group', + 'c4d' => 'application/vnd.clonk.c4group', + 'c4f' => 'application/vnd.clonk.c4group', + 'c4p' => 'application/vnd.clonk.c4group', + 'c4u' => 'application/vnd.clonk.c4group', + 'csp' => 'application/vnd.commonspace', + 'cst' => 'application/vnd.commonspace', + 'cdbcmsg' => 'application/vnd.contact.cmsg', + 'cmc' => 'application/vnd.cosmocaller', + 'clkx' => 'application/vnd.crick.clicker', + 'clkk' => 'application/vnd.crick.clicker.keyboard', + 'clkp' => 'application/vnd.crick.clicker.palette', + 'clkt' => 'application/vnd.crick.clicker.template', + 'clkw' => 'application/vnd.crick.clicker.wordbank', + 'wbs' => 'application/vnd.criticaltools.wbs+xml', + 'pml' => 'application/vnd.ctc-posml', + 'ppd' => 'application/vnd.cups-ppd', + 'curl' => 'application/vnd.curl', + 'rdz' => 'application/vnd.data-vision.rdz', + 'dna' => 'application/vnd.dna', + 'mlp' => 'application/vnd.dolby.mlp', + 'dpg' => 'application/vnd.dpgraph', + 'dfac' => 'application/vnd.dreamfactory', + 'mag' => 'application/vnd.ecowin.chart', + 'nml' => 'application/vnd.enliven', + 'esf' => 'application/vnd.epson.esf', + 'msf' => 'application/vnd.epson.msf', + 'qam' => 'application/vnd.epson.quickanime', + 'slt' => 'application/vnd.epson.salt', + 'ssf' => 'application/vnd.epson.ssf', + 'es3' => 'application/vnd.eszigno3+xml', + 'et3' => 'application/vnd.eszigno3+xml', + 'ez2' => 'application/vnd.ezpix-album', + 'ez3' => 'application/vnd.ezpix-package', + 'fdf' => 'application/vnd.fdf', + 'gph' => 'application/vnd.flographit', + 'ftc' => 'application/vnd.fluxtime.clip', + 'fm' => 'application/vnd.framemaker', + 'frame' => 'application/vnd.framemaker', + 'maker' => 'application/vnd.framemaker', + 'fnc' => 'application/vnd.frogans.fnc', + 'ltf' => 'application/vnd.frogans.ltf', + 'fsc' => 'application/vnd.fsc.weblaunch', + 'oas' => 'application/vnd.fujitsu.oasys', + 'oa2' => 'application/vnd.fujitsu.oasys2', + 'oa3' => 'application/vnd.fujitsu.oasys3', + 'fg5' => 'application/vnd.fujitsu.oasysgp', + 'bh2' => 'application/vnd.fujitsu.oasysprs', + 'ddd' => 'application/vnd.fujixerox.ddd', + 'xdw' => 'application/vnd.fujixerox.docuworks', + 'xbd' => 'application/vnd.fujixerox.docuworks.binder', + 'fzs' => 'application/vnd.fuzzysheet', + 'txd' => 'application/vnd.genomatix.tuxedo', + 'kml' => 'application/vnd.google-earth.kml+xml', + 'kmz' => 'application/vnd.google-earth.kmz', + 'gqf' => 'application/vnd.grafeq', + 'gqs' => 'application/vnd.grafeq', + 'gac' => 'application/vnd.groove-account', + 'ghf' => 'application/vnd.groove-help', + 'gim' => 'application/vnd.groove-identity-message', + 'grv' => 'application/vnd.groove-injector', + 'gtm' => 'application/vnd.groove-tool-message', + 'tpl' => 'application/vnd.groove-tool-template', + 'vcg' => 'application/vnd.groove-vcard', + 'zmm' => 'application/vnd.handheld-entertainment+xml', + 'hbci' => 'application/vnd.hbci', + 'les' => 'application/vnd.hhe.lesson-player', + 'hpgl' => 'application/vnd.hp-hpgl', + 'hpid' => 'application/vnd.hp-hpid', + 'hps' => 'application/vnd.hp-hps', + 'jlt' => 'application/vnd.hp-jlyt', + 'pcl' => 'application/vnd.hp-pcl', + 'pclxl' => 'application/vnd.hp-pclxl', + 'x3d' => 'application/vnd.hzn-3d-crossword', + 'mpy' => 'application/vnd.ibm.minipay', + 'afp' => 'application/vnd.ibm.modcap', + 'listafp' => 'application/vnd.ibm.modcap', + 'list3820' => 'application/vnd.ibm.modcap', + 'irm' => 'application/vnd.ibm.rights-management', + 'sc' => 'application/vnd.ibm.secure-container', + 'igl' => 'application/vnd.igloader', + 'ivp' => 'application/vnd.immervision-ivp', + 'ivu' => 'application/vnd.immervision-ivu', + 'xpw' => 'application/vnd.intercon.formnet', + 'xpx' => 'application/vnd.intercon.formnet', + 'qbo' => 'application/vnd.intu.qbo', + 'qfx' => 'application/vnd.intu.qfx', 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', - 'irp' => 'application/vnd.irepository.package+xml', - 'xpr' => 'application/vnd.is-xpr', - 'jam' => 'application/vnd.jam', - 'rms' => 'application/vnd.jcp.javame.midlet-rms', - 'jisp' => 'application/vnd.jisp', - 'ktz' => 'application/vnd.kahootz', - 'ktr' => 'application/vnd.kahootz', - 'karbon' => 'application/vnd.kde.karbon', - 'chrt' => 'application/vnd.kde.kchart', - 'kfo' => 'application/vnd.kde.kformula', - 'flw' => 'application/vnd.kde.kivio', - 'kon' => 'application/vnd.kde.kontour', - 'kpr' => 'application/vnd.kde.kpresenter', - 'kpt' => 'application/vnd.kde.kpresenter', - 'ksp' => 'application/vnd.kde.kspread', - 'kwd' => 'application/vnd.kde.kword', - 'kwt' => 'application/vnd.kde.kword', - 'htke' => 'application/vnd.kenameaapp', - 'kia' => 'application/vnd.kidspiration', - 'kne' => 'application/vnd.kinar', - 'knp' => 'application/vnd.kinar', - 'skp' => 'application/vnd.koan', - 'skd' => 'application/vnd.koan', - 'skt' => 'application/vnd.koan', - 'skm' => 'application/vnd.koan', - 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', - 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', - '123' => 'application/vnd.lotus-1-2-3', - 'apr' => 'application/vnd.lotus-approach', - 'pre' => 'application/vnd.lotus-freelance', - 'nsf' => 'application/vnd.lotus-notes', - 'org' => 'application/vnd.lotus-organizer', - 'scm' => 'application/vnd.lotus-screencam', - 'lwp' => 'application/vnd.lotus-wordpro', - 'portpkg' => 'application/vnd.macports.portpkg', - 'mcd' => 'application/vnd.mcd', - 'mc1' => 'application/vnd.medcalcdata', - 'cdkey' => 'application/vnd.mediastation.cdkey', - 'mwf' => 'application/vnd.mfer', - 'mfm' => 'application/vnd.mfmp', - 'flo' => 'application/vnd.micrografx.flo', - 'igx' => 'application/vnd.micrografx.igx', - 'mif' => 'application/vnd.mif', - 'daf' => 'application/vnd.mobius.daf', - 'dis' => 'application/vnd.mobius.dis', - 'mbk' => 'application/vnd.mobius.mbk', - 'mqy' => 'application/vnd.mobius.mqy', - 'msl' => 'application/vnd.mobius.msl', - 'plc' => 'application/vnd.mobius.plc', - 'txf' => 'application/vnd.mobius.txf', - 'mpn' => 'application/vnd.mophun.application', - 'mpc' => 'application/vnd.mophun.certificate', - 'xul' => 'application/vnd.mozilla.xul+xml', - 'cil' => 'application/vnd.ms-artgalry', - 'asf' => 'application/vnd.ms-asf', - 'cab' => 'application/vnd.ms-cab-compressed', - 'xls' => 'application/vnd.ms-excel', - 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'xlm' => 'application/vnd.ms-excel', - 'xla' => 'application/vnd.ms-excel', - 'xlc' => 'application/vnd.ms-excel', - 'xlt' => 'application/vnd.ms-excel', - 'xlw' => 'application/vnd.ms-excel', - 'eot' => 'application/vnd.ms-fontobject', - 'chm' => 'application/vnd.ms-htmlhelp', - 'ims' => 'application/vnd.ms-ims', - 'lrm' => 'application/vnd.ms-lrm', - 'ppt' => 'application/vnd.ms-powerpoint', - 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'pps' => 'application/vnd.ms-powerpoint', - 'pot' => 'application/vnd.ms-powerpoint', - 'mpp' => 'application/vnd.ms-project', - 'mpt' => 'application/vnd.ms-project', - 'wps' => 'application/vnd.ms-works', - 'wks' => 'application/vnd.ms-works', - 'wcm' => 'application/vnd.ms-works', - 'wdb' => 'application/vnd.ms-works', - 'wpl' => 'application/vnd.ms-wpl', - 'xps' => 'application/vnd.ms-xpsdocument', - 'mseq' => 'application/vnd.mseq', - 'mus' => 'application/vnd.musician', - 'nlu' => 'application/vnd.neurolanguage.nlu', - 'nnd' => 'application/vnd.noblenet-directory', - 'nns' => 'application/vnd.noblenet-sealer', - 'nnw' => 'application/vnd.noblenet-web', - 'ngdat' => 'application/vnd.nokia.n-gage.data', - 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', - 'rpst' => 'application/vnd.nokia.radio-preset', - 'rpss' => 'application/vnd.nokia.radio-presets', - 'edm' => 'application/vnd.novadigm.edm', - 'edx' => 'application/vnd.novadigm.edx', - 'ext' => 'application/vnd.novadigm.ext', - 'odc' => 'application/vnd.oasis.opendocument.chart', - 'otc' => 'application/vnd.oasis.opendocument.chart-template', - 'odf' => 'application/vnd.oasis.opendocument.formula', - 'otf' => 'application/vnd.oasis.opendocument.formula-template', - 'odg' => 'application/vnd.oasis.opendocument.graphics', - 'otg' => 'application/vnd.oasis.opendocument.graphics-template', - 'odi' => 'application/vnd.oasis.opendocument.image', - 'oti' => 'application/vnd.oasis.opendocument.image-template', - 'odp' => 'application/vnd.oasis.opendocument.presentation', - 'otp' => 'application/vnd.oasis.opendocument.presentation-template', - 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', - 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', - 'odt' => 'application/vnd.oasis.opendocument.text', - 'otm' => 'application/vnd.oasis.opendocument.text-master', - 'ott' => 'application/vnd.oasis.opendocument.text-template', - 'oth' => 'application/vnd.oasis.opendocument.text-web', - 'xo' => 'application/vnd.olpc-sugar', - 'dd2' => 'application/vnd.oma.dd2+xml', - 'oxt' => 'application/vnd.openofficeorg.extension', - 'dp' => 'application/vnd.osgi.dp', - 'prc' => 'application/vnd.palm', - 'pdb' => 'application/vnd.palm', - 'pqa' => 'application/vnd.palm', - 'oprc' => 'application/vnd.palm', - 'str' => 'application/vnd.pg.format', - 'ei6' => 'application/vnd.pg.osasli', - 'efif' => 'application/vnd.picsel', - 'plf' => 'application/vnd.pocketlearn', - 'pbd' => 'application/vnd.powerbuilder6', - 'box' => 'application/vnd.previewsystems.box', - 'mgz' => 'application/vnd.proteus.magazine', - 'qps' => 'application/vnd.publishare-delta-tree', - 'ptid' => 'application/vnd.pvi.ptid1', - 'qxd' => 'application/vnd.quark.quarkxpress', - 'qxt' => 'application/vnd.quark.quarkxpress', - 'qwd' => 'application/vnd.quark.quarkxpress', - 'qwt' => 'application/vnd.quark.quarkxpress', - 'qxl' => 'application/vnd.quark.quarkxpress', - 'qxb' => 'application/vnd.quark.quarkxpress', - 'mxl' => 'application/vnd.recordare.musicxml', - 'rm' => 'application/vnd.rn-realmedia', - 'see' => 'application/vnd.seemail', - 'sema' => 'application/vnd.sema', - 'semd' => 'application/vnd.semd', - 'semf' => 'application/vnd.semf', - 'ifm' => 'application/vnd.shana.informed.formdata', - 'itp' => 'application/vnd.shana.informed.formtemplate', - 'iif' => 'application/vnd.shana.informed.interchange', - 'ipk' => 'application/vnd.shana.informed.package', - 'twd' => 'application/vnd.simtech-mindmapper', - 'twds' => 'application/vnd.simtech-mindmapper', - 'mmf' => 'application/vnd.smaf', - 'sdkm' => 'application/vnd.solent.sdkm+xml', - 'sdkd' => 'application/vnd.solent.sdkm+xml', - 'dxp' => 'application/vnd.spotfire.dxp', - 'sfs' => 'application/vnd.spotfire.sfs', - 'sus' => 'application/vnd.sus-calendar', - 'susp' => 'application/vnd.sus-calendar', - 'svd' => 'application/vnd.svd', - 'xsm' => 'application/vnd.syncml+xml', - 'bdm' => 'application/vnd.syncml.dm+wbxml', - 'xdm' => 'application/vnd.syncml.dm+xml', - 'tao' => 'application/vnd.tao.intent-module-archive', - 'tmo' => 'application/vnd.tmobile-livetv', - 'tpt' => 'application/vnd.trid.tpt', - 'mxs' => 'application/vnd.triscape.mxs', - 'tra' => 'application/vnd.trueapp', - 'ufd' => 'application/vnd.ufdl', - 'ufdl' => 'application/vnd.ufdl', - 'utz' => 'application/vnd.uiq.theme', - 'umj' => 'application/vnd.umajin', - 'unityweb' => 'application/vnd.unity', - 'uoml' => 'application/vnd.uoml+xml', - 'vcx' => 'application/vnd.vcx', - 'vsd' => 'application/vnd.visio', - 'vst' => 'application/vnd.visio', - 'vss' => 'application/vnd.visio', - 'vsw' => 'application/vnd.visio', - 'vis' => 'application/vnd.visionary', - 'vsf' => 'application/vnd.vsf', - 'wbxml' => 'application/vnd.wap.wbxml', - 'wmlc' => 'application/vnd.wap.wmlc', - 'wmlsc' => 'application/vnd.wap.wmlscriptc', - 'wtb' => 'application/vnd.webturbo', - 'wpd' => 'application/vnd.wordperfect', - 'wqd' => 'application/vnd.wqd', - 'stf' => 'application/vnd.wt.stf', - 'xar' => 'application/vnd.xara', - 'xfdl' => 'application/vnd.xfdl', - 'hvd' => 'application/vnd.yamaha.hv-dic', - 'hvs' => 'application/vnd.yamaha.hv-script', - 'hvp' => 'application/vnd.yamaha.hv-voice', - 'saf' => 'application/vnd.yamaha.smaf-audio', - 'spf' => 'application/vnd.yamaha.smaf-phrase', - 'cmp' => 'application/vnd.yellowriver-custom-menu', - 'zaz' => 'application/vnd.zzazz.deck+xml', - 'vxml' => 'application/voicexml+xml', - 'hlp' => 'application/winhlp', - 'wsdl' => 'application/wsdl+xml', - 'wspolicy' => 'application/wspolicy+xml', - 'ace' => 'application/x-ace-compressed', - 'bcpio' => 'application/x-bcpio', - 'torrent' => 'application/x-bittorrent', - 'bz' => 'application/x-bzip', - 'bz2' => 'application/x-bzip2', - 'boz' => 'application/x-bzip2', - 'vcd' => 'application/x-cdlink', - 'chat' => 'application/x-chat', - 'pgn' => 'application/x-chess-pgn', - 'cpio' => 'application/x-cpio', - 'csh' => 'application/x-csh', - 'dcr' => 'application/x-director', - 'dir' => 'application/x-director', - 'dxr' => 'application/x-director', - 'fgd' => 'application/x-director', - 'dvi' => 'application/x-dvi', - 'spl' => 'application/x-futuresplash', - 'gtar' => 'application/x-gtar', - 'hdf' => 'application/x-hdf', - 'jnlp' => 'application/x-java-jnlp-file', - 'latex' => 'application/x-latex', - 'wmd' => 'application/x-ms-wmd', - 'wmz' => 'application/x-ms-wmz', - 'mdb' => 'application/x-msaccess', - 'obd' => 'application/x-msbinder', - 'crd' => 'application/x-mscardfile', - 'clp' => 'application/x-msclip', - 'exe' => 'application/x-msdownload', - 'dll' => 'application/x-msdownload', - 'com' => 'application/x-msdownload', - 'bat' => 'application/x-msdownload', - 'msi' => 'application/x-msdownload', - 'mvb' => 'application/x-msmediaview', - 'm13' => 'application/x-msmediaview', - 'm14' => 'application/x-msmediaview', - 'wmf' => 'application/x-msmetafile', - 'mny' => 'application/x-msmoney', - 'pub' => 'application/x-mspublisher', - 'scd' => 'application/x-msschedule', - 'trm' => 'application/x-msterminal', - 'wri' => 'application/x-mswrite', - 'nc' => 'application/x-netcdf', - 'cdf' => 'application/x-netcdf', - 'p12' => 'application/x-pkcs12', - 'pfx' => 'application/x-pkcs12', - 'p7b' => 'application/x-pkcs7-certificates', - 'spc' => 'application/x-pkcs7-certificates', - 'p7r' => 'application/x-pkcs7-certreqresp', - 'rar' => 'application/x-rar-compressed', - 'sh' => 'application/x-sh', - 'shar' => 'application/x-shar', - 'swf' => 'application/x-shockwave-flash', - 'sit' => 'application/x-stuffit', - 'sitx' => 'application/x-stuffitx', - 'sv4cpio' => 'application/x-sv4cpio', - 'sv4crc' => 'application/x-sv4crc', - 'tar' => 'application/x-tar', - 'tcl' => 'application/x-tcl', - 'tex' => 'application/x-tex', - 'texinfo' => 'application/x-texinfo', - 'texi' => 'application/x-texinfo', - 'ustar' => 'application/x-ustar', - 'src' => 'application/x-wais-source', - 'der' => 'application/x-x509-ca-cert', - 'crt' => 'application/x-x509-ca-cert', - 'xenc' => 'application/xenc+xml', - 'xhtml' => 'application/xhtml+xml', - 'xht' => 'application/xhtml+xml', - 'xml' => 'application/xml', - 'xsl' => 'application/xml', - 'dtd' => 'application/xml-dtd', - 'xop' => 'application/xop+xml', - 'xslt' => 'application/xslt+xml', - 'xspf' => 'application/xspf+xml', - 'mxml' => 'application/xv+xml', - 'xhvml' => 'application/xv+xml', - 'xvml' => 'application/xv+xml', - 'xvm' => 'application/xv+xml', - 'zip' => 'application/zip', - 'au' => 'audio/basic', - 'snd' => 'audio/basic', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'kar' => 'audio/midi', - 'rmi' => 'audio/midi', - 'mp4a' => 'audio/mp4', - 'm4a' => 'audio/mp4a-latm', - 'm4p' => 'audio/mp4a-latm', - 'mpga' => 'audio/mpeg', - 'mp2' => 'audio/mpeg', - 'mp2a' => 'audio/mpeg', - 'mp3' => 'audio/mpeg', - 'm2a' => 'audio/mpeg', - 'm3a' => 'audio/mpeg', - 'eol' => 'audio/vnd.digital-winds', - 'lvp' => 'audio/vnd.lucent.voice', + 'irp' => 'application/vnd.irepository.package+xml', + 'xpr' => 'application/vnd.is-xpr', + 'jam' => 'application/vnd.jam', + 'rms' => 'application/vnd.jcp.javame.midlet-rms', + 'jisp' => 'application/vnd.jisp', + 'ktz' => 'application/vnd.kahootz', + 'ktr' => 'application/vnd.kahootz', + 'karbon' => 'application/vnd.kde.karbon', + 'chrt' => 'application/vnd.kde.kchart', + 'kfo' => 'application/vnd.kde.kformula', + 'flw' => 'application/vnd.kde.kivio', + 'kon' => 'application/vnd.kde.kontour', + 'kpr' => 'application/vnd.kde.kpresenter', + 'kpt' => 'application/vnd.kde.kpresenter', + 'ksp' => 'application/vnd.kde.kspread', + 'kwd' => 'application/vnd.kde.kword', + 'kwt' => 'application/vnd.kde.kword', + 'htke' => 'application/vnd.kenameaapp', + 'kia' => 'application/vnd.kidspiration', + 'kne' => 'application/vnd.kinar', + 'knp' => 'application/vnd.kinar', + 'skp' => 'application/vnd.koan', + 'skd' => 'application/vnd.koan', + 'skt' => 'application/vnd.koan', + 'skm' => 'application/vnd.koan', + 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', + 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', + '123' => 'application/vnd.lotus-1-2-3', + 'apr' => 'application/vnd.lotus-approach', + 'pre' => 'application/vnd.lotus-freelance', + 'nsf' => 'application/vnd.lotus-notes', + 'org' => 'application/vnd.lotus-organizer', + 'scm' => 'application/vnd.lotus-screencam', + 'lwp' => 'application/vnd.lotus-wordpro', + 'portpkg' => 'application/vnd.macports.portpkg', + 'mcd' => 'application/vnd.mcd', + 'mc1' => 'application/vnd.medcalcdata', + 'cdkey' => 'application/vnd.mediastation.cdkey', + 'mwf' => 'application/vnd.mfer', + 'mfm' => 'application/vnd.mfmp', + 'flo' => 'application/vnd.micrografx.flo', + 'igx' => 'application/vnd.micrografx.igx', + 'mif' => 'application/vnd.mif', + 'daf' => 'application/vnd.mobius.daf', + 'dis' => 'application/vnd.mobius.dis', + 'mbk' => 'application/vnd.mobius.mbk', + 'mqy' => 'application/vnd.mobius.mqy', + 'msl' => 'application/vnd.mobius.msl', + 'plc' => 'application/vnd.mobius.plc', + 'txf' => 'application/vnd.mobius.txf', + 'mpn' => 'application/vnd.mophun.application', + 'mpc' => 'application/vnd.mophun.certificate', + 'xul' => 'application/vnd.mozilla.xul+xml', + 'cil' => 'application/vnd.ms-artgalry', + 'asf' => 'application/vnd.ms-asf', + 'cab' => 'application/vnd.ms-cab-compressed', + 'xls' => 'application/vnd.ms-excel', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xlm' => 'application/vnd.ms-excel', + 'xla' => 'application/vnd.ms-excel', + 'xlc' => 'application/vnd.ms-excel', + 'xlt' => 'application/vnd.ms-excel', + 'xlw' => 'application/vnd.ms-excel', + 'eot' => 'application/vnd.ms-fontobject', + 'chm' => 'application/vnd.ms-htmlhelp', + 'ims' => 'application/vnd.ms-ims', + 'lrm' => 'application/vnd.ms-lrm', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'pps' => 'application/vnd.ms-powerpoint', + 'pot' => 'application/vnd.ms-powerpoint', + 'mpp' => 'application/vnd.ms-project', + 'mpt' => 'application/vnd.ms-project', + 'wps' => 'application/vnd.ms-works', + 'wks' => 'application/vnd.ms-works', + 'wcm' => 'application/vnd.ms-works', + 'wdb' => 'application/vnd.ms-works', + 'wpl' => 'application/vnd.ms-wpl', + 'xps' => 'application/vnd.ms-xpsdocument', + 'mseq' => 'application/vnd.mseq', + 'mus' => 'application/vnd.musician', + 'nlu' => 'application/vnd.neurolanguage.nlu', + 'nnd' => 'application/vnd.noblenet-directory', + 'nns' => 'application/vnd.noblenet-sealer', + 'nnw' => 'application/vnd.noblenet-web', + 'ngdat' => 'application/vnd.nokia.n-gage.data', + 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', + 'rpst' => 'application/vnd.nokia.radio-preset', + 'rpss' => 'application/vnd.nokia.radio-presets', + 'edm' => 'application/vnd.novadigm.edm', + 'edx' => 'application/vnd.novadigm.edx', + 'ext' => 'application/vnd.novadigm.ext', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'otc' => 'application/vnd.oasis.opendocument.chart-template', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'otf' => 'application/vnd.oasis.opendocument.formula-template', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'oti' => 'application/vnd.oasis.opendocument.image-template', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'otm' => 'application/vnd.oasis.opendocument.text-master', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web', + 'xo' => 'application/vnd.olpc-sugar', + 'dd2' => 'application/vnd.oma.dd2+xml', + 'oxt' => 'application/vnd.openofficeorg.extension', + 'dp' => 'application/vnd.osgi.dp', + 'prc' => 'application/vnd.palm', + 'pdb' => 'application/vnd.palm', + 'pqa' => 'application/vnd.palm', + 'oprc' => 'application/vnd.palm', + 'str' => 'application/vnd.pg.format', + 'ei6' => 'application/vnd.pg.osasli', + 'efif' => 'application/vnd.picsel', + 'plf' => 'application/vnd.pocketlearn', + 'pbd' => 'application/vnd.powerbuilder6', + 'box' => 'application/vnd.previewsystems.box', + 'mgz' => 'application/vnd.proteus.magazine', + 'qps' => 'application/vnd.publishare-delta-tree', + 'ptid' => 'application/vnd.pvi.ptid1', + 'qxd' => 'application/vnd.quark.quarkxpress', + 'qxt' => 'application/vnd.quark.quarkxpress', + 'qwd' => 'application/vnd.quark.quarkxpress', + 'qwt' => 'application/vnd.quark.quarkxpress', + 'qxl' => 'application/vnd.quark.quarkxpress', + 'qxb' => 'application/vnd.quark.quarkxpress', + 'mxl' => 'application/vnd.recordare.musicxml', + 'rm' => 'application/vnd.rn-realmedia', + 'see' => 'application/vnd.seemail', + 'sema' => 'application/vnd.sema', + 'semd' => 'application/vnd.semd', + 'semf' => 'application/vnd.semf', + 'ifm' => 'application/vnd.shana.informed.formdata', + 'itp' => 'application/vnd.shana.informed.formtemplate', + 'iif' => 'application/vnd.shana.informed.interchange', + 'ipk' => 'application/vnd.shana.informed.package', + 'twd' => 'application/vnd.simtech-mindmapper', + 'twds' => 'application/vnd.simtech-mindmapper', + 'mmf' => 'application/vnd.smaf', + 'sdkm' => 'application/vnd.solent.sdkm+xml', + 'sdkd' => 'application/vnd.solent.sdkm+xml', + 'dxp' => 'application/vnd.spotfire.dxp', + 'sfs' => 'application/vnd.spotfire.sfs', + 'sus' => 'application/vnd.sus-calendar', + 'susp' => 'application/vnd.sus-calendar', + 'svd' => 'application/vnd.svd', + 'xsm' => 'application/vnd.syncml+xml', + 'bdm' => 'application/vnd.syncml.dm+wbxml', + 'xdm' => 'application/vnd.syncml.dm+xml', + 'tao' => 'application/vnd.tao.intent-module-archive', + 'tmo' => 'application/vnd.tmobile-livetv', + 'tpt' => 'application/vnd.trid.tpt', + 'mxs' => 'application/vnd.triscape.mxs', + 'tra' => 'application/vnd.trueapp', + 'ufd' => 'application/vnd.ufdl', + 'ufdl' => 'application/vnd.ufdl', + 'utz' => 'application/vnd.uiq.theme', + 'umj' => 'application/vnd.umajin', + 'unityweb' => 'application/vnd.unity', + 'uoml' => 'application/vnd.uoml+xml', + 'vcx' => 'application/vnd.vcx', + 'vsd' => 'application/vnd.visio', + 'vst' => 'application/vnd.visio', + 'vss' => 'application/vnd.visio', + 'vsw' => 'application/vnd.visio', + 'vis' => 'application/vnd.visionary', + 'vsf' => 'application/vnd.vsf', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'wtb' => 'application/vnd.webturbo', + 'wpd' => 'application/vnd.wordperfect', + 'wqd' => 'application/vnd.wqd', + 'stf' => 'application/vnd.wt.stf', + 'xar' => 'application/vnd.xara', + 'xfdl' => 'application/vnd.xfdl', + 'hvd' => 'application/vnd.yamaha.hv-dic', + 'hvs' => 'application/vnd.yamaha.hv-script', + 'hvp' => 'application/vnd.yamaha.hv-voice', + 'saf' => 'application/vnd.yamaha.smaf-audio', + 'spf' => 'application/vnd.yamaha.smaf-phrase', + 'cmp' => 'application/vnd.yellowriver-custom-menu', + 'zaz' => 'application/vnd.zzazz.deck+xml', + 'vxml' => 'application/voicexml+xml', + 'hlp' => 'application/winhlp', + 'wsdl' => 'application/wsdl+xml', + 'wspolicy' => 'application/wspolicy+xml', + 'ace' => 'application/x-ace-compressed', + 'bcpio' => 'application/x-bcpio', + 'torrent' => 'application/x-bittorrent', + 'bz' => 'application/x-bzip', + 'bz2' => 'application/x-bzip2', + 'boz' => 'application/x-bzip2', + 'vcd' => 'application/x-cdlink', + 'chat' => 'application/x-chat', + 'pgn' => 'application/x-chess-pgn', + 'cpio' => 'application/x-cpio', + 'csh' => 'application/x-csh', + 'dcr' => 'application/x-director', + 'dir' => 'application/x-director', + 'dxr' => 'application/x-director', + 'fgd' => 'application/x-director', + 'dvi' => 'application/x-dvi', + 'spl' => 'application/x-futuresplash', + 'gtar' => 'application/x-gtar', + 'hdf' => 'application/x-hdf', + 'jnlp' => 'application/x-java-jnlp-file', + 'latex' => 'application/x-latex', + 'wmd' => 'application/x-ms-wmd', + 'wmz' => 'application/x-ms-wmz', + 'mdb' => 'application/x-msaccess', + 'obd' => 'application/x-msbinder', + 'crd' => 'application/x-mscardfile', + 'clp' => 'application/x-msclip', + 'exe' => 'application/x-msdownload', + 'dll' => 'application/x-msdownload', + 'com' => 'application/x-msdownload', + 'bat' => 'application/x-msdownload', + 'msi' => 'application/x-msdownload', + 'mvb' => 'application/x-msmediaview', + 'm13' => 'application/x-msmediaview', + 'm14' => 'application/x-msmediaview', + 'wmf' => 'application/x-msmetafile', + 'mny' => 'application/x-msmoney', + 'pub' => 'application/x-mspublisher', + 'scd' => 'application/x-msschedule', + 'trm' => 'application/x-msterminal', + 'wri' => 'application/x-mswrite', + 'nc' => 'application/x-netcdf', + 'cdf' => 'application/x-netcdf', + 'p12' => 'application/x-pkcs12', + 'pfx' => 'application/x-pkcs12', + 'p7b' => 'application/x-pkcs7-certificates', + 'spc' => 'application/x-pkcs7-certificates', + 'p7r' => 'application/x-pkcs7-certreqresp', + 'rar' => 'application/x-rar-compressed', + 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'sitx' => 'application/x-stuffitx', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'tar' => 'application/x-tar', + 'tcl' => 'application/x-tcl', + 'tex' => 'application/x-tex', + 'texinfo' => 'application/x-texinfo', + 'texi' => 'application/x-texinfo', + 'ustar' => 'application/x-ustar', + 'src' => 'application/x-wais-source', + 'der' => 'application/x-x509-ca-cert', + 'crt' => 'application/x-x509-ca-cert', + 'xenc' => 'application/xenc+xml', + 'xhtml' => 'application/xhtml+xml', + 'xht' => 'application/xhtml+xml', + 'xml' => 'application/xml', + 'xsl' => 'application/xml', + 'dtd' => 'application/xml-dtd', + 'xop' => 'application/xop+xml', + 'xslt' => 'application/xslt+xml', + 'xspf' => 'application/xspf+xml', + 'mxml' => 'application/xv+xml', + 'xhvml' => 'application/xv+xml', + 'xvml' => 'application/xv+xml', + 'xvm' => 'application/xv+xml', + 'zip' => 'application/zip', + 'au' => 'audio/basic', + 'snd' => 'audio/basic', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'kar' => 'audio/midi', + 'rmi' => 'audio/midi', + 'mp4a' => 'audio/mp4', + 'm4a' => 'audio/mp4a-latm', + 'm4p' => 'audio/mp4a-latm', + 'mpga' => 'audio/mpeg', + 'mp2' => 'audio/mpeg', + 'mp2a' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'm2a' => 'audio/mpeg', + 'm3a' => 'audio/mpeg', + 'eol' => 'audio/vnd.digital-winds', + 'lvp' => 'audio/vnd.lucent.voice', 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', - 'wav' => 'audio/wav', - 'aif' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'aifc' => 'audio/x-aiff', - 'm3u' => 'audio/x-mpegurl', - 'wax' => 'audio/x-ms-wax', - 'wma' => 'audio/x-ms-wma', - 'ram' => 'audio/x-pn-realaudio', - 'ra' => 'audio/x-pn-realaudio', - 'rmp' => 'audio/x-pn-realaudio-plugin', - 'cdx' => 'chemical/x-cdx', - 'cif' => 'chemical/x-cif', - 'cmdf' => 'chemical/x-cmdf', - 'cml' => 'chemical/x-cml', - 'csml' => 'chemical/x-csml', - 'xyz' => 'chemical/x-xyz', - 'bmp' => 'image/bmp', - 'cgm' => 'image/cgm', - 'g3' => 'image/g3fax', - 'gif' => 'image/gif', - 'ief' => 'image/ief', - 'jp2' => 'image/jp2', - 'jpeg' => 'image/jpeg', - 'jpe' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'pict' => 'image/pict', - 'pic' => 'image/pict', - 'pct' => 'image/pict', - 'png' => 'image/png', - 'btif' => 'image/prs.btif', - 'svg' => 'image/svg+xml', - 'svgz' => 'image/svg+xml', - 'tiff' => 'image/tiff', - 'tif' => 'image/tiff', - 'psd' => 'image/vnd.adobe.photoshop', - 'djvu' => 'image/vnd.djvu', - 'djv' => 'image/vnd.djvu', - 'dwg' => 'image/vnd.dwg', - 'dxf' => 'image/vnd.dxf', - 'fbs' => 'image/vnd.fastbidsheet', - 'fpx' => 'image/vnd.fpx', - 'fst' => 'image/vnd.fst', - 'mmr' => 'image/vnd.fujixerox.edmics-mmr', - 'rlc' => 'image/vnd.fujixerox.edmics-rlc', - 'ico' => 'image/vnd.microsoft.icon', - 'mdi' => 'image/vnd.ms-modi', - 'npx' => 'image/vnd.net-fpx', - 'wbmp' => 'image/vnd.wap.wbmp', - 'xif' => 'image/vnd.xiff', - 'ras' => 'image/x-cmu-raster', - 'cmx' => 'image/x-cmx', - 'pntg' => 'image/x-macpaint', - 'pnt' => 'image/x-macpaint', - 'mac' => 'image/x-macpaint', - 'pcx' => 'image/x-pcx', - 'pnm' => 'image/x-portable-anymap', - 'pbm' => 'image/x-portable-bitmap', - 'pgm' => 'image/x-portable-graymap', - 'ppm' => 'image/x-portable-pixmap', - 'qtif' => 'image/x-quicktime', - 'qti' => 'image/x-quicktime', - 'rgb' => 'image/x-rgb', - 'xbm' => 'image/x-xbitmap', - 'xpm' => 'image/x-xpixmap', - 'xwd' => 'image/x-xwindowdump', - 'eml' => 'message/rfc822', - 'mime' => 'message/rfc822', - 'igs' => 'model/iges', - 'iges' => 'model/iges', - 'msh' => 'model/mesh', - 'mesh' => 'model/mesh', - 'silo' => 'model/mesh', - 'dwf' => 'model/vnd.dwf', - 'gdl' => 'model/vnd.gdl', - 'gtw' => 'model/vnd.gtw', - 'mts' => 'model/vnd.mts', - 'vtu' => 'model/vnd.vtu', - 'wrl' => 'model/vrml', - 'vrml' => 'model/vrml', - 'ics' => 'text/calendar', - 'ifb' => 'text/calendar', - 'css' => 'text/css', - 'csv' => 'text/csv', - 'html' => 'text/html', - 'htm' => 'text/html', - 'txt' => 'text/plain', - 'text' => 'text/plain', - 'conf' => 'text/plain', - 'def' => 'text/plain', - 'list' => 'text/plain', - 'log' => 'text/plain', - 'in' => 'text/plain', - 'dsc' => 'text/prs.lines.tag', - 'rtx' => 'text/richtext', - 'sgml' => 'text/sgml', - 'sgm' => 'text/sgml', - 'tsv' => 'text/tab-separated-values', - 't' => 'text/troff', - 'tr' => 'text/troff', - 'roff' => 'text/troff', - 'man' => 'text/troff', - 'me' => 'text/troff', - 'ms' => 'text/troff', - 'uri' => 'text/uri-list', - 'uris' => 'text/uri-list', - 'urls' => 'text/uri-list', - 'fly' => 'text/vnd.fly', - 'flx' => 'text/vnd.fmi.flexstor', - '3dml' => 'text/vnd.in3d.3dml', - 'spot' => 'text/vnd.in3d.spot', - 'jad' => 'text/vnd.sun.j2me.app-descriptor', - 'wml' => 'text/vnd.wap.wml', - 'wmls' => 'text/vnd.wap.wmlscript', - 's' => 'text/x-asm', - 'asm' => 'text/x-asm', - 'c' => 'text/x-c', - 'cc' => 'text/x-c', - 'cxx' => 'text/x-c', - 'cpp' => 'text/x-c', - 'h' => 'text/x-c', - 'hh' => 'text/x-c', - 'dic' => 'text/x-c', - 'f' => 'text/x-fortran', - 'for' => 'text/x-fortran', - 'f77' => 'text/x-fortran', - 'f90' => 'text/x-fortran', - 'p' => 'text/x-pascal', - 'pas' => 'text/x-pascal', - 'java' => 'text/x-java-source', - 'etx' => 'text/x-setext', - 'uu' => 'text/x-uuencode', - 'vcs' => 'text/x-vcalendar', - 'vcf' => 'text/x-vcard', - '3gp' => 'video/3gpp', - '3g2' => 'video/3gpp2', - 'h261' => 'video/h261', - 'h263' => 'video/h263', - 'h264' => 'video/h264', - 'jpgv' => 'video/jpeg', - 'jpm' => 'video/jpm', - 'jpgm' => 'video/jpm', - 'mj2' => 'video/mj2', - 'mjp2' => 'video/mj2', - 'mp4' => 'video/mp4', - 'mp4v' => 'video/mp4', - 'mpg4' => 'video/mp4', - 'm4v' => 'video/mp4', - 'mpeg' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'mpe' => 'video/mpeg', - 'm1v' => 'video/mpeg', - 'm2v' => 'video/mpeg', - 'qt' => 'video/quicktime', - 'mov' => 'video/quicktime', - 'fvt' => 'video/vnd.fvt', - 'mxu' => 'video/vnd.mpegurl', - 'm4u' => 'video/vnd.mpegurl', - 'viv' => 'video/vnd.vivo', - 'dv' => 'video/x-dv', - 'dif' => 'video/x-dv', - 'fli' => 'video/x-fli', - 'asx' => 'video/x-ms-asf', - 'wm' => 'video/x-ms-wm', - 'wmv' => 'video/x-ms-wmv', - 'wmx' => 'video/x-ms-wmx', - 'wvx' => 'video/x-ms-wvx', - 'avi' => 'video/x-msvideo', - 'movie' => 'video/x-sgi-movie', - 'ice' => 'x-conference/x-cooltalk', + 'wav' => 'audio/wav', + 'aif' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'm3u' => 'audio/x-mpegurl', + 'wax' => 'audio/x-ms-wax', + 'wma' => 'audio/x-ms-wma', + 'ram' => 'audio/x-pn-realaudio', + 'ra' => 'audio/x-pn-realaudio', + 'rmp' => 'audio/x-pn-realaudio-plugin', + 'cdx' => 'chemical/x-cdx', + 'cif' => 'chemical/x-cif', + 'cmdf' => 'chemical/x-cmdf', + 'cml' => 'chemical/x-cml', + 'csml' => 'chemical/x-csml', + 'xyz' => 'chemical/x-xyz', + 'bmp' => 'image/bmp', + 'cgm' => 'image/cgm', + 'g3' => 'image/g3fax', + 'gif' => 'image/gif', + 'ief' => 'image/ief', + 'jp2' => 'image/jp2', + 'jpeg' => 'image/jpeg', + 'jpe' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'pict' => 'image/pict', + 'pic' => 'image/pict', + 'pct' => 'image/pict', + 'png' => 'image/png', + 'btif' => 'image/prs.btif', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'psd' => 'image/vnd.adobe.photoshop', + 'djvu' => 'image/vnd.djvu', + 'djv' => 'image/vnd.djvu', + 'dwg' => 'image/vnd.dwg', + 'dxf' => 'image/vnd.dxf', + 'fbs' => 'image/vnd.fastbidsheet', + 'fpx' => 'image/vnd.fpx', + 'fst' => 'image/vnd.fst', + 'mmr' => 'image/vnd.fujixerox.edmics-mmr', + 'rlc' => 'image/vnd.fujixerox.edmics-rlc', + 'ico' => 'image/vnd.microsoft.icon', + 'mdi' => 'image/vnd.ms-modi', + 'npx' => 'image/vnd.net-fpx', + 'wbmp' => 'image/vnd.wap.wbmp', + 'xif' => 'image/vnd.xiff', + 'ras' => 'image/x-cmu-raster', + 'cmx' => 'image/x-cmx', + 'pntg' => 'image/x-macpaint', + 'pnt' => 'image/x-macpaint', + 'mac' => 'image/x-macpaint', + 'pcx' => 'image/x-pcx', + 'pnm' => 'image/x-portable-anymap', + 'pbm' => 'image/x-portable-bitmap', + 'pgm' => 'image/x-portable-graymap', + 'ppm' => 'image/x-portable-pixmap', + 'qtif' => 'image/x-quicktime', + 'qti' => 'image/x-quicktime', + 'rgb' => 'image/x-rgb', + 'xbm' => 'image/x-xbitmap', + 'xpm' => 'image/x-xpixmap', + 'xwd' => 'image/x-xwindowdump', + 'eml' => 'message/rfc822', + 'mime' => 'message/rfc822', + 'igs' => 'model/iges', + 'iges' => 'model/iges', + 'msh' => 'model/mesh', + 'mesh' => 'model/mesh', + 'silo' => 'model/mesh', + 'dwf' => 'model/vnd.dwf', + 'gdl' => 'model/vnd.gdl', + 'gtw' => 'model/vnd.gtw', + 'mts' => 'model/vnd.mts', + 'vtu' => 'model/vnd.vtu', + 'wrl' => 'model/vrml', + 'vrml' => 'model/vrml', + 'ics' => 'text/calendar', + 'ifb' => 'text/calendar', + 'css' => 'text/css', + 'csv' => 'text/csv', + 'html' => 'text/html', + 'htm' => 'text/html', + 'txt' => 'text/plain', + 'text' => 'text/plain', + 'conf' => 'text/plain', + 'def' => 'text/plain', + 'list' => 'text/plain', + 'log' => 'text/plain', + 'in' => 'text/plain', + 'dsc' => 'text/prs.lines.tag', + 'rtx' => 'text/richtext', + 'sgml' => 'text/sgml', + 'sgm' => 'text/sgml', + 'tsv' => 'text/tab-separated-values', + 't' => 'text/troff', + 'tr' => 'text/troff', + 'roff' => 'text/troff', + 'man' => 'text/troff', + 'me' => 'text/troff', + 'ms' => 'text/troff', + 'uri' => 'text/uri-list', + 'uris' => 'text/uri-list', + 'urls' => 'text/uri-list', + 'fly' => 'text/vnd.fly', + 'flx' => 'text/vnd.fmi.flexstor', + '3dml' => 'text/vnd.in3d.3dml', + 'spot' => 'text/vnd.in3d.spot', + 'jad' => 'text/vnd.sun.j2me.app-descriptor', + 'wml' => 'text/vnd.wap.wml', + 'wmls' => 'text/vnd.wap.wmlscript', + 's' => 'text/x-asm', + 'asm' => 'text/x-asm', + 'c' => 'text/x-c', + 'cc' => 'text/x-c', + 'cxx' => 'text/x-c', + 'cpp' => 'text/x-c', + 'h' => 'text/x-c', + 'hh' => 'text/x-c', + 'dic' => 'text/x-c', + 'f' => 'text/x-fortran', + 'for' => 'text/x-fortran', + 'f77' => 'text/x-fortran', + 'f90' => 'text/x-fortran', + 'p' => 'text/x-pascal', + 'pas' => 'text/x-pascal', + 'java' => 'text/x-java-source', + 'etx' => 'text/x-setext', + 'uu' => 'text/x-uuencode', + 'vcs' => 'text/x-vcalendar', + 'vcf' => 'text/x-vcard', + '3gp' => 'video/3gpp', + '3g2' => 'video/3gpp2', + 'h261' => 'video/h261', + 'h263' => 'video/h263', + 'h264' => 'video/h264', + 'jpgv' => 'video/jpeg', + 'jpm' => 'video/jpm', + 'jpgm' => 'video/jpm', + 'mj2' => 'video/mj2', + 'mjp2' => 'video/mj2', + 'mp4' => 'video/mp4', + 'mp4v' => 'video/mp4', + 'mpg4' => 'video/mp4', + 'm4v' => 'video/mp4', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'm1v' => 'video/mpeg', + 'm2v' => 'video/mpeg', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + 'fvt' => 'video/vnd.fvt', + 'mxu' => 'video/vnd.mpegurl', + 'm4u' => 'video/vnd.mpegurl', + 'viv' => 'video/vnd.vivo', + 'dv' => 'video/x-dv', + 'dif' => 'video/x-dv', + 'fli' => 'video/x-fli', + 'asx' => 'video/x-ms-asf', + 'wm' => 'video/x-ms-wm', + 'wmv' => 'video/x-ms-wmv', + 'wmx' => 'video/x-ms-wmx', + 'wvx' => 'video/x-ms-wvx', + 'avi' => 'video/x-msvideo', + 'movie' => 'video/x-sgi-movie', + 'ice' => 'x-conference/x-cooltalk', ]; + /** + * Returns extension for given mime type + * + * @param string $mimeType The mime type, e.g. "video/mpeg" + * @return array|string + */ + public static function getExtension($mimeType) + { + if (is_string($mimeType) && in_array($mimeType, self::$mimeTypes, true)) { + $data = Arrays::setKeysAsValues(self::$mimeTypes, false); + + return $data[$mimeType]; + } + + return ''; + } + /** * Returns extensions for given mimes types * @@ -723,20 +743,56 @@ class MimeTypes } /** - * Returns extension for given mime type + * Returns mime type of given file * - * @param string $mimeType The mime type, e.g. "video/mpeg" - * @return array|string + * @param string $filePath Path of the file to check + * @return string + * @throws RuntimeException */ - public static function getExtension($mimeType) + public static function getMimeType($filePath) { - if (is_string($mimeType) && in_array($mimeType, self::$mimeTypes, true)) { - $data = Arrays::setKeysAsValues(self::$mimeTypes, false); - - return $data[$mimeType]; + /* + * The file does not exist? + * Nothing to do + */ + if (!is_string($filePath) || !is_readable($filePath)) { + return ''; } - return ''; + // 1st possibility: the finfo class + if (class_exists('finfo')) { + $finfo = new finfo(); + + return $finfo->file($filePath, FILEINFO_MIME_TYPE); + } + + // 2nd possibility: the mime_content_type function + if (function_exists('mime_content_type')) { + return mime_content_type($filePath); + } + + // Oops, there is no possibility to read the mime type + $template = 'Neither \'finfo\' class nor \'mime_content_type\' function exists. There is no way to read the' + .' mime type of file \'%s\'.'; + + $message = sprintf($template, $filePath); + + throw new RuntimeException($message); + } + + /** + * Returns information whether the given file type is an image + * + * @param string $mimeType The mime type of file + * @return bool + */ + public static function isImage($mimeType) + { + if (in_array($mimeType, self::$mimeTypes, true)) { + return (bool) preg_match('|^image/.+$|', $mimeType); + } + + return false; } /** @@ -751,57 +807,4 @@ class MimeTypes return self::isImage($mimeType); } - - /** - * Returns mime type of given file - * - * @param string $filePath Path of the file to check - * @throws \RuntimeException - * @return string - */ - public static function getMimeType($filePath) - { - /* - * The file does not exist? - * Nothing to do - */ - if (!is_string($filePath) || !is_readable($filePath)) { - return ''; - } - - // 1st possibility: the finfo class - if (class_exists('finfo')) { - $finfo = new \finfo(); - - return $finfo->file($filePath, FILEINFO_MIME_TYPE); - } - - // 2nd possibility: the mime_content_type function - if (function_exists('mime_content_type')) { - return mime_content_type($filePath); - } - - // Oops, there is no possibility to read the mime type - $template = 'Neither \'finfo\' class nor \'mime_content_type\' function exists. There is no way to read the' - . ' mime type of file \'%s\'.'; - - $message = sprintf($template, $filePath); - - throw new \RuntimeException($message); - } - - /** - * Returns information whether the given file type is an image - * - * @param string $mimeType The mime type of file - * @return bool - */ - public static function isImage($mimeType) - { - if (in_array($mimeType, self::$mimeTypes, true)) { - return (bool)preg_match('|^image/.+$|', $mimeType); - } - - return false; - } } diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index f760215..f04e3af 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -19,574 +19,6 @@ use Transliterator; */ class Miscellaneous { - /** - * Returns directory's content (names of directories and files) - * - * @param string $directoryPath Path of directory who content should be returned - * @param bool $recursive (optional) If is set to true, sub-directories are also searched for content. - * Otherwise - only content of given directory is returned. - * @param int $maxFilesCount (optional) Maximum files that will be returned. If it's null, all files are - * returned. - * @return null|array - */ - public static function getDirectoryContent($directoryPath, $recursive = false, $maxFilesCount = null) - { - /* - * Path of directory is unknown or does not exist and is not readable? - * Nothing to do - */ - if (empty($directoryPath) || !is_readable($directoryPath)) { - return null; - } - - $files = []; - $startFileName = ''; - - if (self::isFilePath($directoryPath)) { - $startDirectoryPath = dirname($directoryPath); - $startFileName = str_replace($startDirectoryPath, '', $directoryPath); - - $directoryPath = $startDirectoryPath; - } - - $count = 0; - $startFileFound = false; - - if (!Regex::endsWith($directoryPath, '/')) { - $directoryPath .= '/'; - } - - if (Regex::startsWith($startFileName, '/')) { - $startFileName = mb_substr($startFileName, 1); - } - - $directoryContent = scandir($directoryPath, SCANDIR_SORT_ASCENDING); - - if (!empty($directoryContent)) { - foreach ($directoryContent as $fileName) { - if ('.' !== $fileName && '..' !== $fileName) { - $content = null; - - if (!empty($startFileName) && !$startFileFound) { - if ($fileName === $startFileName) { - $startFileFound = true; - } - - continue; - } - - if ($recursive && is_dir($directoryPath . $fileName)) { - $content = self::getDirectoryContent($directoryPath . $fileName, true, $maxFilesCount - $count); - } - - if (null !== $content) { - $files[$fileName] = $content; - - if (null !== $maxFilesCount) { - $count += Arrays::getNonArrayElementsCount($content); - } - } else { - $files[] = $fileName; - - if (null !== $maxFilesCount) { - ++$count; - } - } - - if (null !== $maxFilesCount && $count >= $maxFilesCount) { - break; - } - } - } - } - - return $files; - } - - /** - * Returns information if given path it's a file's path, if the path contains file name - * - * @param string $path The path to check - * @return bool - */ - public static function isFilePath($path) - { - $info = pathinfo($path); - - return isset($info['extension']) && !empty($info['extension']); - } - - /** - * Converts checkbox value to boolean - * - * @param string $checkboxValue Checkbox value - * @return bool - */ - public static function checkboxValue2Boolean($checkboxValue) - { - $mapping = [ - 'on' => true, - 'off' => false, - ]; - - $clearValue = strtolower(trim($checkboxValue)); - - if (isset($mapping[$clearValue])) { - return $mapping[$clearValue]; - } - - return false; - } - - /** - * Converts checkbox value to integer - * - * @param string $checkboxValue Checkbox value - * @return int - */ - public static function checkboxValue2Integer($checkboxValue) - { - return (int)self::checkboxValue2Boolean($checkboxValue); - } - - /** - * Returns name of file with given extension after verification if it contains the extension - * - * @param string $fileName The file name to verify - * @param string $extension The extension to verify and include - * @return string - */ - public static function includeFileExtension($fileName, $extension) - { - $fileExtension = self::getFileExtension($fileName, true); - - /* - * File has given extension? - * Nothing to do - */ - if ($fileExtension === strtolower($extension)) { - return $fileName; - } - - return sprintf('%s.%s', $fileName, $extension); - } - - /** - * Returns file extension - * - * @param string $fileName File name - * @param bool $asLowerCase (optional) if true extension is returned as lowercase string - * @return string - */ - public static function getFileExtension($fileName, $asLowerCase = false) - { - $extension = ''; - $matches = []; - - if (preg_match('|(.+)\.(.+)|', $fileName, $matches)) { - $extension = end($matches); - } - - if ($asLowerCase) { - return strtolower($extension); - } - - return $extension; - } - - /** - * Returns file name from given path - * - * @param string $path A path that contains file name - * @return string - */ - public static function getFileNameFromPath(string $path): string - { - $matches = []; - $pattern = Regex::getFileNamePattern(); - - if ((bool)preg_match($pattern, $path, $matches)) { - return $matches[0]; - } - - return ''; - } - - /** - * Returns unique name for file based on given original name - * - * @param string $originalFileName Original name of the file - * @param int $objectId (optional) Object ID, the ID of database's row. May be included into the - * generated / unique name. - * @return string - */ - public static function getUniqueFileName($originalFileName, $objectId = 0) - { - $withoutExtension = self::getFileNameWithoutExtension($originalFileName); - $extension = self::getFileExtension($originalFileName, true); - - /* - * Let's clear name of file - * - * Attention. - * The name without extension should be cleared to avoid incorrect name by replacing "." with "-". - */ - $withoutExtension = Urlizer::urlize($withoutExtension); - - // Now I have to complete the template used to build / generate unique name - $template = '%s-%s.%s'; // [file's name]-[unique key].[file's extension] - - // Add some uniqueness - $unique = self::getUniqueString(mt_rand()); - - // Finally build and return the unique name - if ($objectId > 0) { - $template = '%s-%s-%s.%s'; // [file's name]-[unique key]-[object ID].[file's extension] - - return sprintf($template, $withoutExtension, $unique, $objectId, $extension); - } - - return sprintf($template, $withoutExtension, $unique, $extension); - } - - /** - * Returns file name without extension - * - * @param string $fileName The file name - * @return string - */ - public static function getFileNameWithoutExtension($fileName) - { - $matches = []; - - if (is_string($fileName) && (bool)preg_match('|(.+)\.(.+)|', $fileName, $matches)) { - return $matches[1]; - } - - return ''; - } - - /** - * Converts value to non-negative integer (element of the set {0, 1, 2, 3, ...}) - * - * @param mixed $value Value to convert - * @param int $negativeReplacement (optional) Replacement for negative value - * @return int - */ - public static function value2NonNegativeInteger($value, $negativeReplacement = 0) - { - $effect = (int)$value; - - if ($effect < 0) { - return $negativeReplacement; - } - - return $effect; - } - - /** - * Returns information if given PHP module is compiled and loaded - * - * @param string $phpModuleName PHP module name - * @return bool - */ - public static function isPhpModuleLoaded($phpModuleName) - { - $phpModulesArray = get_loaded_extensions(); - - return in_array($phpModuleName, $phpModulesArray, false); - } - - /** - * Converts given string characters to latin characters - * - * @param string $string String to convert - * @param bool $lowerCaseHuman (optional) If is set to true, converted string is returned as lowercase and - * human-readable. Otherwise - as original. - * @param string $replacementChar (optional) Replacement character for all non-latin characters and uppercase - * letters, if 2nd argument is set to true - * @return string - */ - public static function toLatin($string, $lowerCaseHuman = true, $replacementChar = '-') - { - if (is_string($string)) { - $string = trim($string); - } - - /* - * Empty value? - * Nothing to do - */ - if (empty($string)) { - return ''; - } - - $converter = Transliterator::create('Latin-ASCII;'); - - /* - * Oops, cannot instantiate converter - * Nothing to do - */ - if (null === $converter) { - return ''; - } - - $converted = $converter->transliterate($string); - - // Make the string lowercase and human-readable - if ($lowerCaseHuman) { - $matches = []; - $matchCount = preg_match_all('|[A-Z]{1}[^A-Z]*|', $converted, $matches); - - if ($matchCount > 0) { - $parts = $matches[0]; - $converted = mb_strtolower(implode($replacementChar, $parts)); - } - } - - /* - * Let's replace special characters to spaces - * ...and finally spaces to $replacementChar - */ - $replaced = preg_replace('|[^a-zA-Z0-9]|', ' ', $converted); - - return preg_replace('| +|', $replacementChar, trim($replaced)); - } - - /** - * Returns unique string - * - * @param string $prefix (optional) Prefix of the unique string. May be used while generating the unique - * string simultaneously on several hosts at the same microsecond. - * @param bool $hashed (optional) If is set to true, the unique string is hashed additionally. Otherwise - not. - * @return string - */ - public static function getUniqueString($prefix = '', $hashed = false) - { - $unique = uniqid($prefix, true); - - if ($hashed) { - return sha1($unique); - } - - return $unique; - } - - /** - * Replaces part of string with other string or strings. - * There is a few combination of what should be searched and with what it should be replaced. - * - * @param array|string $subject The string or an array of strings to search and replace - * @param array|string $search String or pattern or array of patterns to find. It may be: string, an array - * of strings or an array of patterns. - * @param array|string $replacement The string or an array of strings to replace. It may be: string or an array - * of strings. - * @param bool $quoteStrings (optional) If is set to true, strings are surrounded with single quote sign - * @return string - * - * Example: - * a) an array of strings to search - * $subject = [ - * 'Lorem ipsum dolor sit amet.', - * 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis.', - * ]; - * - * b) an array of patterns - * $search = [ - * '|ipsum|', - * '|pellentesque|', - * ]; - * - * c) an array of strings to replace - * $replacement = [ - * 'commodo', - * 'interdum', - * ]; - * - * The result: - * [ - * 'Lorem commodo dolor sit amet.', - * 'Etiam ullamcorper. Suspendisse a interdum dui, non felis.', - * ]; - */ - public static function replace($subject, $search, $replacement, $quoteStrings = false) - { - /* - * Unknown source or item to find or replacement is an empty array? - * Nothing to do - */ - if (empty($subject) || empty($search) || [] === $replacement) { - return $subject; - } - - $effect = $subject; - - $searchIsString = is_string($search); - $searchIsArray = is_array($search); - - /* - * Value to find is neither a string nor an array OR it's an empty string? - * Nothing to do - */ - if ((!$searchIsString && !$searchIsArray) || ($searchIsString && '' === $search)) { - return $effect; - } - - $replacementIsString = is_string($replacement); - $replacementIsArray = is_array($replacement); - - $bothAreStrings = $searchIsString && $replacementIsString; - $bothAreArrays = $searchIsArray && $replacementIsArray; - - if ($quoteStrings) { - if ($replacementIsString) { - $replacement = '\'' . $replacement . '\''; - } elseif ($replacementIsArray) { - foreach ($replacement as &$item) { - if (is_string($item)) { - $item = '\'' . $item . '\''; - } - } - - unset($item); - } - } - - // 1st step: replace strings, simple operation with strings - if ($bothAreStrings) { - $effect = str_replace($search, $replacement, $subject); - } - - /* - * 2nd step: replace with regular expressions. - * Attention. Searched and replacement value should be the same type: strings or arrays. - */ - if ($effect === $subject && ($bothAreStrings || $bothAreArrays)) { - /* - * I have to avoid string that contains spaces only, e.g. " ". - * It's required to avoid bug: preg_replace(): Empty regular expression. - */ - if ($searchIsArray || ($searchIsString && !empty(trim($search)))) { - $replaced = @preg_replace($search, $replacement, $subject); - - if (null !== $replaced && [] !== $replaced) { - $effect = $replaced; - } - } - } - - /* - * 3rd step: complex replace of the replacement defined as an array. - * It may be useful when you want to search for a one string and replace the string with multiple values. - */ - if ($effect === $subject && $searchIsString && $replacementIsArray) { - $subjectIsArray = is_array($subject); - $effect = ''; - - if ($subjectIsArray) { - $effect = []; - } - - $subject = Arrays::makeArray($subject); - - // I have to iterate through the subjects, because explode() function expects strings as both arguments - // (1st and 2nd) - foreach ($subject as $subSubject) { - $subEffect = ''; - - $exploded = explode($search, $subSubject); - $explodedCount = count($exploded); - - foreach ($exploded as $key => $item) { - $subEffect .= $item; - - // The replacement shouldn't be included when the searched string was not found - if ($explodedCount > 1 && $key < $explodedCount - 1 && isset($replacement[$key])) { - $subEffect .= $replacement[$key]; - } - } - - if ($subjectIsArray) { - $effect[] = $subEffect; - - continue; - } - - $effect .= $subEffect; - } - } - - return $effect; - } - - /** - * Returns new file name after adding prefix or suffix (or both of them) to the name - * - * @param string $fileName The file name - * @param string $prefix File name prefix - * @param string $suffix File name suffix - * @return string - */ - public static function getNewFileName($fileName, $prefix, $suffix) - { - $effect = $fileName; - - if (!empty($fileName) && (!empty($prefix) || !empty($suffix))) { - $name = self::getFileNameWithoutExtension($fileName); - $extension = self::getFileExtension($fileName); - - $effect = sprintf('%s%s%s.%s', $prefix, $name, $suffix, $extension); - } - - return $effect; - } - - /** - * Returns operating system name PHP is running on - * - * @return string - */ - public static function getOperatingSystemNameServer() - { - return PHP_OS; - /* - * Previous version: - * return php_uname('s'); - */ - } - - /** - * Returns part of string preserving words - * - * @param string $text The string / text - * @param int $maxLength Maximum length of given string - * @param string $suffix (optional) The suffix to add at the end of string - * @return string - */ - public static function substringToWord(string $text, int $maxLength, string $suffix = '...'): string - { - $effect = $text; - $encoding = 'utf-8'; - - $textLength = mb_strlen($text, $encoding); - $suffixLength = mb_strlen($suffix, $encoding); - - $maxLength -= $suffixLength; - - if ($textLength > $maxLength) { - $effect = mb_substr($text, 0, $maxLength, $encoding); - $lastSpacePosition = mb_strrpos($effect, ' ', 0, $encoding); - - if (false !== $lastSpacePosition) { - $effect = mb_substr($effect, 0, $lastSpacePosition, $encoding); - } - - $effect .= $suffix; - } - - return $effect; - } - /** * Breaks long text * @@ -676,271 +108,46 @@ class Miscellaneous return $effect; } - /** - * Removes the directory. - * If not empty, removes also contents. - * - * @param string $directoryPath Directory path - * @param bool $contentOnly (optional) If is set to true, only content of the directory is removed, not - * directory itself. Otherwise - directory is removed too (default behaviour). - * @return null|bool - */ - public static function removeDirectory($directoryPath, $contentOnly = false) + public static function calculateGreatestCommonDivisor(int $first, int $second): int { - /* - * Directory does not exist? - * Nothing to do - */ - if (!file_exists($directoryPath)) { - return null; + if (0 === $second) { + return $first; } - /* - * It's not a directory? - * Let's treat it like file - */ - if (!is_dir($directoryPath)) { - return unlink($directoryPath); - } - - foreach (scandir($directoryPath, SCANDIR_SORT_ASCENDING) as $item) { - if ('.' === $item || '..' === $item) { - continue; - } - - if (!self::removeDirectory($directoryPath . DIRECTORY_SEPARATOR . $item)) { - return false; - } - } - - // Directory should be removed too? - if (!$contentOnly) { - return rmdir($directoryPath); - } - - return true; + return static::calculateGreatestCommonDivisor($second, $first % $second); } /** - * Returns information if value is decimal + * Converts checkbox value to boolean * - * @param mixed $value The value to check + * @param string $checkboxValue Checkbox value * @return bool */ - public static function isDecimal($value) + public static function checkboxValue2Boolean($checkboxValue) { - return is_scalar($value) && is_numeric($value) && floor($value) !== (float) $value; - } - - /** - * Returns the string in camel case - * - * @param string $string The string to convert e.g. this-is-eXamplE (return: thisIsExample) - * @param string $separator (optional) Separator used to find parts of the string, e.g. '-' or ',' - * @return string - */ - public static function getCamelCase($string, $separator = ' ') - { - if (empty($string)) { - return ''; - } - - $effect = ''; - $members = explode($separator, $string); - - foreach ($members as $key => $value) { - $value = mb_strtolower($value); - - if (0 === $key) { - $effect .= self::lowercaseFirst($value); - } else { - $effect .= self::uppercaseFirst($value); - } - } - - return $effect; - } - - /** - * Make a string's first character lowercase - * - * @param string $text The text to get first character lowercase - * @param null|bool $restLowercase (optional) Information that to do with rest of given string - * @return string - * - * Values of the $restLowercase argument: - * - null (default): nothing is done with the string - * - true: the rest of string is lowercased - * - false: the rest of string is uppercased - */ - public static function lowercaseFirst($text, $restLowercase = null) - { - if (empty($text)) { - return ''; - } - - $effect = $text; - - if ($restLowercase) { - $effect = mb_strtolower($effect); - } elseif (false === $restLowercase) { - $effect = mb_strtoupper($effect); - } - - return lcfirst($effect); - } - - /** - * Make a string's first character uppercase - * - * @param string $text The text to get uppercase - * @param null|bool $restLowercase (optional) Information that to do with rest of given string - * @return string - * - * Values of the $restLowercase argument: - * - null (default): nothing is done with the string - * - true: the rest of string is lowercased - * - false: the rest of string is uppercased - */ - public static function uppercaseFirst($text, $restLowercase = null) - { - if (empty($text)) { - return ''; - } - - $effect = $text; - - if ($restLowercase) { - $effect = mb_strtolower($effect); - } elseif (false === $restLowercase) { - $effect = mb_strtoupper($effect); - } - - return ucfirst($effect); - } - - /** - * Quotes given value with apostrophes or quotation marks - * - * @param mixed $value The value to quote - * @param bool $useApostrophe (optional) If is set to true, apostrophes are used. Otherwise - quotation marks. - * @return string - */ - public static function quoteValue($value, $useApostrophe = true) - { - if (is_string($value)) { - $quotes = '"'; - - if ($useApostrophe) { - $quotes = '\''; - } - - $value = sprintf('%s%s%s', $quotes, $value, $quotes); - } - - return $value; - } - - /** - * Returns size (of file or directory) in human readable format - * - * @param int $sizeInBytes The size in bytes - * @return string - */ - public static function getHumanReadableSize($sizeInBytes) - { - $units = [ - 'B', - 'KB', - 'MB', - 'GB', - 'TB', - 'PB', + $mapping = [ + 'on' => true, + 'off' => false, ]; - $index = floor(log($sizeInBytes, 1024)); - $size = round($sizeInBytes / (1024 ** $index), 2); - $unit = $units[(int)$index]; + $clearValue = strtolower(trim($checkboxValue)); - return sprintf('%s %s', $size, $unit); + if (isset($mapping[$clearValue])) { + return $mapping[$clearValue]; + } + + return false; } /** - * Returns string without the last element. - * The string should contain given separator. + * Converts checkbox value to integer * - * @param string $string The string to check - * @param string $separator The separator which divides elements of string - * @return string + * @param string $checkboxValue Checkbox value + * @return int */ - public static function getStringWithoutLastElement($string, $separator) + public static function checkboxValue2Integer($checkboxValue) { - $elements = self::getStringElements($string, $separator); - $lastKey = Arrays::getLastKey($elements); - - unset($elements[$lastKey]); - - return implode($separator, $elements); - } - - /** - * Returns elements of given string divided by given separator - * - * @param string $string The string to check - * @param string $separator The separator which divides elements of string - * @return array - */ - public static function getStringElements(string $string, string $separator): array - { - if (empty($string) || empty($separator)) { - return []; - } - - $matches = []; - $pattern = sprintf('|[^\%s]+|', $separator); - $matchCount = preg_match_all($pattern, $string, $matches); - - if ($matchCount > 1) { - return $matches[0]; - } - - return []; - } - - /** - * Returns the last element of given string divided by given separator - * - * @param string $string The string to check - * @param string $separator The separator which divides elements of string - * @return null|string - */ - public static function getLastElementOfString($string, $separator): ?string - { - $elements = self::getStringElements($string, $separator); - - if (empty($elements)) { - return null; - } - - return Arrays::getLastElement($elements); - } - - /** - * Returns smartly trimmed string. - * If the string is empty, contains only spaces, e.g. " ", nothing is done and the original string is returned. - * - * @param string $string The string to trim - * @return string - */ - public static function trimSmart($string) - { - $trimmed = trim($string); - - if (empty($trimmed)) { - return $string; - } - - return $trimmed; + return (int) self::checkboxValue2Boolean($checkboxValue); } /** @@ -1017,67 +224,369 @@ class Miscellaneous } /** - * Removes the starting / beginning directory's separator + * Adds missing the "0" characters to given number until given length is reached * - * @param string $text Text that may contain a directory's separator at the start / beginning - * @param string $separator (optional) The directory's separator, e.g. "/". If is empty (not provided), separator - * provided by operating system will be used. + * Example: + * - number: 201 + * - length: 6 + * - will be returned: 000201 + * + * If "before" parameter is false, zeros will be inserted after given number. If given number is longer than + * given length the number will be returned as it was given to the method. + * + * @param mixed $number Number for who the "0" characters should be inserted + * @param int $length Wanted length of final number + * @param bool $before (optional) If false, 0 characters will be inserted after given number * @return string */ - public static function removeStartingDirectorySeparator($text, $separator = '') + public static function fillMissingZeros($number, $length, $before = true) { /* - * Not a string? + * It's not a number? Empty string is not a number too. * Nothing to do */ - if (!is_string($text)) { + if (!is_numeric($number)) { return ''; } - if (empty($separator)) { - $separator = DIRECTORY_SEPARATOR; + $text = trim($number); + $textLength = mb_strlen($text); + + if ($length <= $textLength) { + return $text; } - $effect = trim($text); + for ($i = ($length - $textLength); 0 < $i; --$i) { + if ($before) { + $text = '0'.$text; - if (Regex::startsWithDirectorySeparator($effect, $separator)) { - $effect = mb_substr($effect, mb_strlen($separator)); + continue; + } + + $text .= '0'; + } + + return $text; + } + + /** + * Returns the string in camel case + * + * @param string $string The string to convert e.g. this-is-eXamplE (return: thisIsExample) + * @param string $separator (optional) Separator used to find parts of the string, e.g. '-' or ',' + * @return string + */ + public static function getCamelCase($string, $separator = ' ') + { + if (empty($string)) { + return ''; + } + + $effect = ''; + $members = explode($separator, $string); + + foreach ($members as $key => $value) { + $value = mb_strtolower($value); + + if (0 === $key) { + $effect .= self::lowercaseFirst($value); + } else { + $effect .= self::uppercaseFirst($value); + } } return $effect; } /** - * Removes the ending directory's separator + * Returns directory's content (names of directories and files) * - * @param string $text Text that may contain a directory's separator at the end - * @param string $separator (optional) The directory's separator, e.g. "/". If is empty (not provided), system's - * separator is used. - * @return string + * @param string $directoryPath Path of directory who content should be returned + * @param bool $recursive (optional) If is set to true, sub-directories are also searched for content. + * Otherwise - only content of given directory is returned. + * @param int $maxFilesCount (optional) Maximum files that will be returned. If it's null, all files are + * returned. + * @return null|array */ - public static function removeEndingDirectorySeparator($text, $separator = '') + public static function getDirectoryContent($directoryPath, $recursive = false, $maxFilesCount = null) { /* - * Not a string? + * Path of directory is unknown or does not exist and is not readable? * Nothing to do */ - if (!is_string($text)) { - return ''; + if (empty($directoryPath) || !is_readable($directoryPath)) { + return null; } - if (empty($separator)) { - $separator = DIRECTORY_SEPARATOR; + $files = []; + $startFileName = ''; + + if (self::isFilePath($directoryPath)) { + $startDirectoryPath = dirname($directoryPath); + $startFileName = str_replace($startDirectoryPath, '', $directoryPath); + + $directoryPath = $startDirectoryPath; } - $effect = trim($text); + $count = 0; + $startFileFound = false; - if (Regex::endsWithDirectorySeparator($effect, $separator)) { - $effect = mb_substr($effect, 0, mb_strlen($effect) - mb_strlen($separator)); + if (!Regex::endsWith($directoryPath, '/')) { + $directoryPath .= '/'; + } + + if (Regex::startsWith($startFileName, '/')) { + $startFileName = mb_substr($startFileName, 1); + } + + $directoryContent = scandir($directoryPath, SCANDIR_SORT_ASCENDING); + + if (!empty($directoryContent)) { + foreach ($directoryContent as $fileName) { + if ('.' !== $fileName && '..' !== $fileName) { + $content = null; + + if (!empty($startFileName) && !$startFileFound) { + if ($fileName === $startFileName) { + $startFileFound = true; + } + + continue; + } + + if ($recursive && is_dir($directoryPath.$fileName)) { + $content = self::getDirectoryContent($directoryPath.$fileName, true, $maxFilesCount - $count); + } + + if (null !== $content) { + $files[$fileName] = $content; + + if (null !== $maxFilesCount) { + $count += Arrays::getNonArrayElementsCount($content); + } + } else { + $files[] = $fileName; + + if (null !== $maxFilesCount) { + ++$count; + } + } + + if (null !== $maxFilesCount && $count >= $maxFilesCount) { + break; + } + } + } + } + + return $files; + } + + /** + * Returns file extension + * + * @param string $fileName File name + * @param bool $asLowerCase (optional) if true extension is returned as lowercase string + * @return string + */ + public static function getFileExtension($fileName, $asLowerCase = false) + { + $extension = ''; + $matches = []; + + if (preg_match('|(.+)\.(.+)|', $fileName, $matches)) { + $extension = end($matches); + } + + if ($asLowerCase) { + return strtolower($extension); + } + + return $extension; + } + + /** + * Returns file name from given path + * + * @param string $path A path that contains file name + * @return string + */ + public static function getFileNameFromPath(string $path): string + { + $matches = []; + $pattern = Regex::getFileNamePattern(); + + if ((bool) preg_match($pattern, $path, $matches)) { + return $matches[0]; + } + + return ''; + } + + /** + * Returns file name without extension + * + * @param string $fileName The file name + * @return string + */ + public static function getFileNameWithoutExtension($fileName) + { + $matches = []; + + if (is_string($fileName) && (bool) preg_match('|(.+)\.(.+)|', $fileName, $matches)) { + return $matches[1]; + } + + return ''; + } + + /** + * Returns size (of file or directory) in human readable format + * + * @param int $sizeInBytes The size in bytes + * @return string + */ + public static function getHumanReadableSize($sizeInBytes) + { + $units = [ + 'B', + 'KB', + 'MB', + 'GB', + 'TB', + 'PB', + ]; + + $index = floor(log($sizeInBytes, 1024)); + $size = round($sizeInBytes / (1024 ** $index), 2); + $unit = $units[(int) $index]; + + return sprintf('%s %s', $size, $unit); + } + + /** + * Returns inverted value of color for given color + * + * @param string $color Hexadecimal value of color to invert (with or without hash), e.g. "dd244c" or "#22a5fe" + * @return string + */ + public static function getInvertedColor($color) + { + // Prepare the color for later usage + $color = trim($color); + $withHash = Regex::startsWith($color, '#'); + + /* + * Verify and get valid value of color. + * An exception will be thrown if the value is not a color. + */ + $validColor = Regex::getValidColorHexValue($color); + + // Grab color's components + $red = hexdec(substr($validColor, 0, 2)); + $green = hexdec(substr($validColor, 2, 2)); + $blue = hexdec(substr($validColor, 4, 2)); + + // Calculate inverted color's components + $redInverted = self::getValidColorComponent(255 - $red); + $greenInverted = self::getValidColorComponent(255 - $green); + $blueInverted = self::getValidColorComponent(255 - $blue); + + // Voila, here is the inverted color + $invertedColor = sprintf('%s%s%s', $redInverted, $greenInverted, $blueInverted); + + if ($withHash) { + return sprintf('#%s', $invertedColor); + } + + return $invertedColor; + } + + /** + * Returns the last element of given string divided by given separator + * + * @param string $string The string to check + * @param string $separator The separator which divides elements of string + * @return null|string + */ + public static function getLastElementOfString($string, $separator): ?string + { + $elements = self::getStringElements($string, $separator); + + if (empty($elements)) { + return null; + } + + return Arrays::getLastElement($elements); + } + + /** + * Returns new file name after adding prefix or suffix (or both of them) to the name + * + * @param string $fileName The file name + * @param string $prefix File name prefix + * @param string $suffix File name suffix + * @return string + */ + public static function getNewFileName($fileName, $prefix, $suffix) + { + $effect = $fileName; + + if (!empty($fileName) && (!empty($prefix) || !empty($suffix))) { + $name = self::getFileNameWithoutExtension($fileName); + $extension = self::getFileExtension($fileName); + + $effect = sprintf('%s%s%s.%s', $prefix, $name, $suffix, $extension); } return $effect; } + /** + * Returns operating system name PHP is running on + * + * @return string + */ + public static function getOperatingSystemNameServer() + { + return PHP_OS; + /* + * Previous version: + * return php_uname('s'); + */ + } + + /** + * Returns project's root path. + * Looks for directory that contains composer.json. + * + * @return string + */ + public static function getProjectRootPath(): string + { + $projectRootPath = ''; + + $fileName = 'composer.json'; + $directoryPath = __DIR__; + + // Path of directory it's not the path of last directory? + while (DIRECTORY_SEPARATOR !== $directoryPath) { + $filePath = static::concatenatePaths($directoryPath, $fileName); + + /* + * Is here file we are looking for? + * Maybe it's a project's root path + */ + if (file_exists($filePath)) { + $projectRootPath = $directoryPath; + } + + $directoryPath = dirname($directoryPath); + } + + return $projectRootPath; + } + /** * Returns safely value of global variable, found in one of the global arrays / variables, e.g. $_GET * @@ -1125,62 +634,45 @@ class Miscellaneous } /** - * Adds missing the "0" characters to given number until given length is reached + * Returns elements of given string divided by given separator * - * Example: - * - number: 201 - * - length: 6 - * - will be returned: 000201 - * - * If "before" parameter is false, zeros will be inserted after given number. If given number is longer than - * given length the number will be returned as it was given to the method. - * - * @param mixed $number Number for who the "0" characters should be inserted - * @param int $length Wanted length of final number - * @param bool $before (optional) If false, 0 characters will be inserted after given number - * @return string + * @param string $string The string to check + * @param string $separator The separator which divides elements of string + * @return array */ - public static function fillMissingZeros($number, $length, $before = true) + public static function getStringElements(string $string, string $separator): array { - /* - * It's not a number? Empty string is not a number too. - * Nothing to do - */ - if (!is_numeric($number)) { - return ''; + if (empty($string) || empty($separator)) { + return []; } - $text = trim($number); - $textLength = mb_strlen($text); + $matches = []; + $pattern = sprintf('|[^\%s]+|', $separator); + $matchCount = preg_match_all($pattern, $string, $matches); - if ($length <= $textLength) { - return $text; + if ($matchCount > 1) { + return $matches[0]; } - for ($i = ($length - $textLength); 0 < $i; --$i) { - if ($before) { - $text = '0' . $text; - - continue; - } - - $text .= '0'; - } - - return $text; + return []; } /** - * Returns information if given value is located in interval between given utmost left and right values + * Returns string without the last element. + * The string should contain given separator. * - * @param float|int $value Value to verify - * @param float|int $left Left utmost value of interval - * @param float|int $right Right utmost value of interval - * @return bool + * @param string $string The string to check + * @param string $separator The separator which divides elements of string + * @return string */ - public static function isBetween($value, $left, $right) + public static function getStringWithoutLastElement($string, $separator) { - return $value > $left && $value < $right; + $elements = self::getStringElements($string, $separator); + $lastKey = Arrays::getLastKey($elements); + + unset($elements[$lastKey]); + + return implode($separator, $elements); } /** @@ -1199,6 +691,62 @@ class Miscellaneous return gettype($variable); } + /** + * Returns unique name for file based on given original name + * + * @param string $originalFileName Original name of the file + * @param int $objectId (optional) Object ID, the ID of database's row. May be included into the + * generated / unique name. + * @return string + */ + public static function getUniqueFileName($originalFileName, $objectId = 0) + { + $withoutExtension = self::getFileNameWithoutExtension($originalFileName); + $extension = self::getFileExtension($originalFileName, true); + + /* + * Let's clear name of file + * + * Attention. + * The name without extension should be cleared to avoid incorrect name by replacing "." with "-". + */ + $withoutExtension = Urlizer::urlize($withoutExtension); + + // Now I have to complete the template used to build / generate unique name + $template = '%s-%s.%s'; // [file's name]-[unique key].[file's extension] + + // Add some uniqueness + $unique = self::getUniqueString(mt_rand()); + + // Finally build and return the unique name + if ($objectId > 0) { + $template = '%s-%s-%s.%s'; // [file's name]-[unique key]-[object ID].[file's extension] + + return sprintf($template, $withoutExtension, $unique, $objectId, $extension); + } + + return sprintf($template, $withoutExtension, $unique, $extension); + } + + /** + * Returns unique string + * + * @param string $prefix (optional) Prefix of the unique string. May be used while generating the unique + * string simultaneously on several hosts at the same microsecond. + * @param bool $hashed (optional) If is set to true, the unique string is hashed additionally. Otherwise - not. + * @return string + */ + public static function getUniqueString($prefix = '', $hashed = false) + { + $unique = uniqid($prefix, true); + + if ($hashed) { + return sha1($unique); + } + + return $unique; + } + /** * Returns valid value of color's component (e.g. red). * If given value is greater than 0, returns the value. Otherwise - 0. @@ -1210,7 +758,7 @@ class Miscellaneous */ public static function getValidColorComponent($colorComponent, $asHexadecimal = true) { - $colorComponent = (int)$colorComponent; + $colorComponent = (int) $colorComponent; if ($colorComponent < 0 || $colorComponent > 255) { $colorComponent = 0; @@ -1230,72 +778,202 @@ class Miscellaneous } /** - * Returns inverted value of color for given color + * Returns name of file with given extension after verification if it contains the extension * - * @param string $color Hexadecimal value of color to invert (with or without hash), e.g. "dd244c" or "#22a5fe" + * @param string $fileName The file name to verify + * @param string $extension The extension to verify and include * @return string */ - public static function getInvertedColor($color) + public static function includeFileExtension($fileName, $extension) { - // Prepare the color for later usage - $color = trim($color); - $withHash = Regex::startsWith($color, '#'); + $fileExtension = self::getFileExtension($fileName, true); /* - * Verify and get valid value of color. - * An exception will be thrown if the value is not a color. + * File has given extension? + * Nothing to do */ - $validColor = Regex::getValidColorHexValue($color); - - // Grab color's components - $red = hexdec(substr($validColor, 0, 2)); - $green = hexdec(substr($validColor, 2, 2)); - $blue = hexdec(substr($validColor, 4, 2)); - - // Calculate inverted color's components - $redInverted = self::getValidColorComponent(255 - $red); - $greenInverted = self::getValidColorComponent(255 - $green); - $blueInverted = self::getValidColorComponent(255 - $blue); - - // Voila, here is the inverted color - $invertedColor = sprintf('%s%s%s', $redInverted, $greenInverted, $blueInverted); - - if ($withHash) { - return sprintf('#%s', $invertedColor); + if ($fileExtension === strtolower($extension)) { + return $fileName; } - return $invertedColor; + return sprintf('%s.%s', $fileName, $extension); } /** - * Returns project's root path. - * Looks for directory that contains composer.json. + * Returns information if given value is located in interval between given utmost left and right values * - * @return string + * @param float|int $value Value to verify + * @param float|int $left Left utmost value of interval + * @param float|int $right Right utmost value of interval + * @return bool */ - public static function getProjectRootPath(): string + public static function isBetween($value, $left, $right) { - $projectRootPath = ''; + return $value > $left && $value < $right; + } - $fileName = 'composer.json'; - $directoryPath = __DIR__; + /** + * Returns information if value is decimal + * + * @param mixed $value The value to check + * @return bool + */ + public static function isDecimal($value) + { + return is_scalar($value) && is_numeric($value) && floor($value) !== (float) $value; + } - // Path of directory it's not the path of last directory? - while (DIRECTORY_SEPARATOR !== $directoryPath) { - $filePath = static::concatenatePaths($directoryPath, $fileName); + /** + * Returns information if given path it's a file's path, if the path contains file name + * + * @param string $path The path to check + * @return bool + */ + public static function isFilePath($path) + { + $info = pathinfo($path); - /* - * Is here file we are looking for? - * Maybe it's a project's root path - */ - if (file_exists($filePath)) { - $projectRootPath = $directoryPath; - } + return isset($info['extension']) && !empty($info['extension']); + } - $directoryPath = dirname($directoryPath); + /** + * Returns information if given PHP module is compiled and loaded + * + * @param string $phpModuleName PHP module name + * @return bool + */ + public static function isPhpModuleLoaded($phpModuleName) + { + $phpModulesArray = get_loaded_extensions(); + + return in_array($phpModuleName, $phpModulesArray, false); + } + + /** + * Make a string's first character lowercase + * + * @param string $text The text to get first character lowercase + * @param null|bool $restLowercase (optional) Information that to do with rest of given string + * @return string + * + * Values of the $restLowercase argument: + * - null (default): nothing is done with the string + * - true: the rest of string is lowercased + * - false: the rest of string is uppercased + */ + public static function lowercaseFirst($text, $restLowercase = null) + { + if (empty($text)) { + return ''; } - return $projectRootPath; + $effect = $text; + + if ($restLowercase) { + $effect = mb_strtolower($effect); + } elseif (false === $restLowercase) { + $effect = mb_strtoupper($effect); + } + + return lcfirst($effect); + } + + /** + * Quotes given value with apostrophes or quotation marks + * + * @param mixed $value The value to quote + * @param bool $useApostrophe (optional) If is set to true, apostrophes are used. Otherwise - quotation marks. + * @return string + */ + public static function quoteValue($value, $useApostrophe = true) + { + if (is_string($value)) { + $quotes = '"'; + + if ($useApostrophe) { + $quotes = '\''; + } + + $value = sprintf('%s%s%s', $quotes, $value, $quotes); + } + + return $value; + } + + /** + * Removes the directory. + * If not empty, removes also contents. + * + * @param string $directoryPath Directory path + * @param bool $contentOnly (optional) If is set to true, only content of the directory is removed, not + * directory itself. Otherwise - directory is removed too (default behaviour). + * @return null|bool + */ + public static function removeDirectory($directoryPath, $contentOnly = false) + { + /* + * Directory does not exist? + * Nothing to do + */ + if (!file_exists($directoryPath)) { + return null; + } + + /* + * It's not a directory? + * Let's treat it like file + */ + if (!is_dir($directoryPath)) { + return unlink($directoryPath); + } + + foreach (scandir($directoryPath, SCANDIR_SORT_ASCENDING) as $item) { + if ('.' === $item || '..' === $item) { + continue; + } + + if (!self::removeDirectory($directoryPath.DIRECTORY_SEPARATOR.$item)) { + return false; + } + } + + // Directory should be removed too? + if (!$contentOnly) { + return rmdir($directoryPath); + } + + return true; + } + + /** + * Removes the ending directory's separator + * + * @param string $text Text that may contain a directory's separator at the end + * @param string $separator (optional) The directory's separator, e.g. "/". If is empty (not provided), system's + * separator is used. + * @return string + */ + public static function removeEndingDirectorySeparator($text, $separator = '') + { + /* + * Not a string? + * Nothing to do + */ + if (!is_string($text)) { + return ''; + } + + if (empty($separator)) { + $separator = DIRECTORY_SEPARATOR; + } + + $effect = trim($text); + + if (Regex::endsWithDirectorySeparator($effect, $separator)) { + $effect = mb_substr($effect, 0, mb_strlen($effect) - mb_strlen($separator)); + } + + return $effect; } /** @@ -1319,12 +997,334 @@ class Miscellaneous return substr($string, 1); } - public static function calculateGreatestCommonDivisor(int $first, int $second): int + /** + * Removes the starting / beginning directory's separator + * + * @param string $text Text that may contain a directory's separator at the start / beginning + * @param string $separator (optional) The directory's separator, e.g. "/". If is empty (not provided), separator + * provided by operating system will be used. + * @return string + */ + public static function removeStartingDirectorySeparator($text, $separator = '') { - if (0 === $second) { - return $first; + /* + * Not a string? + * Nothing to do + */ + if (!is_string($text)) { + return ''; } - return static::calculateGreatestCommonDivisor($second, $first % $second); + if (empty($separator)) { + $separator = DIRECTORY_SEPARATOR; + } + + $effect = trim($text); + + if (Regex::startsWithDirectorySeparator($effect, $separator)) { + $effect = mb_substr($effect, mb_strlen($separator)); + } + + return $effect; + } + + /** + * Replaces part of string with other string or strings. + * There is a few combination of what should be searched and with what it should be replaced. + * + * @param array|string $subject The string or an array of strings to search and replace + * @param array|string $search String or pattern or array of patterns to find. It may be: string, an array + * of strings or an array of patterns. + * @param array|string $replacement The string or an array of strings to replace. It may be: string or an array + * of strings. + * @param bool $quoteStrings (optional) If is set to true, strings are surrounded with single quote sign + * @return string + * + * Example: + * a) an array of strings to search + * $subject = [ + * 'Lorem ipsum dolor sit amet.', + * 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis.', + * ]; + * + * b) an array of patterns + * $search = [ + * '|ipsum|', + * '|pellentesque|', + * ]; + * + * c) an array of strings to replace + * $replacement = [ + * 'commodo', + * 'interdum', + * ]; + * + * The result: + * [ + * 'Lorem commodo dolor sit amet.', + * 'Etiam ullamcorper. Suspendisse a interdum dui, non felis.', + * ]; + */ + public static function replace($subject, $search, $replacement, $quoteStrings = false) + { + /* + * Unknown source or item to find or replacement is an empty array? + * Nothing to do + */ + if (empty($subject) || empty($search) || [] === $replacement) { + return $subject; + } + + $effect = $subject; + + $searchIsString = is_string($search); + $searchIsArray = is_array($search); + + /* + * Value to find is neither a string nor an array OR it's an empty string? + * Nothing to do + */ + if ((!$searchIsString && !$searchIsArray) || ($searchIsString && '' === $search)) { + return $effect; + } + + $replacementIsString = is_string($replacement); + $replacementIsArray = is_array($replacement); + + $bothAreStrings = $searchIsString && $replacementIsString; + $bothAreArrays = $searchIsArray && $replacementIsArray; + + if ($quoteStrings) { + if ($replacementIsString) { + $replacement = '\''.$replacement.'\''; + } elseif ($replacementIsArray) { + foreach ($replacement as &$item) { + if (is_string($item)) { + $item = '\''.$item.'\''; + } + } + + unset($item); + } + } + + // 1st step: replace strings, simple operation with strings + if ($bothAreStrings) { + $effect = str_replace($search, $replacement, $subject); + } + + /* + * 2nd step: replace with regular expressions. + * Attention. Searched and replacement value should be the same type: strings or arrays. + */ + if ($effect === $subject && ($bothAreStrings || $bothAreArrays)) { + /* + * I have to avoid string that contains spaces only, e.g. " ". + * It's required to avoid bug: preg_replace(): Empty regular expression. + */ + if ($searchIsArray || ($searchIsString && !empty(trim($search)))) { + $replaced = @preg_replace($search, $replacement, $subject); + + if (null !== $replaced && [] !== $replaced) { + $effect = $replaced; + } + } + } + + /* + * 3rd step: complex replace of the replacement defined as an array. + * It may be useful when you want to search for a one string and replace the string with multiple values. + */ + if ($effect === $subject && $searchIsString && $replacementIsArray) { + $subjectIsArray = is_array($subject); + $effect = ''; + + if ($subjectIsArray) { + $effect = []; + } + + $subject = Arrays::makeArray($subject); + + // I have to iterate through the subjects, because explode() function expects strings as both arguments + // (1st and 2nd) + foreach ($subject as $subSubject) { + $subEffect = ''; + + $exploded = explode($search, $subSubject); + $explodedCount = count($exploded); + + foreach ($exploded as $key => $item) { + $subEffect .= $item; + + // The replacement shouldn't be included when the searched string was not found + if ($explodedCount > 1 && $key < $explodedCount - 1 && isset($replacement[$key])) { + $subEffect .= $replacement[$key]; + } + } + + if ($subjectIsArray) { + $effect[] = $subEffect; + + continue; + } + + $effect .= $subEffect; + } + } + + return $effect; + } + + /** + * Returns part of string preserving words + * + * @param string $text The string / text + * @param int $maxLength Maximum length of given string + * @param string $suffix (optional) The suffix to add at the end of string + * @return string + */ + public static function substringToWord(string $text, int $maxLength, string $suffix = '...'): string + { + $effect = $text; + $encoding = 'utf-8'; + + $textLength = mb_strlen($text, $encoding); + $suffixLength = mb_strlen($suffix, $encoding); + + $maxLength -= $suffixLength; + + if ($textLength > $maxLength) { + $effect = mb_substr($text, 0, $maxLength, $encoding); + $lastSpacePosition = mb_strrpos($effect, ' ', 0, $encoding); + + if (false !== $lastSpacePosition) { + $effect = mb_substr($effect, 0, $lastSpacePosition, $encoding); + } + + $effect .= $suffix; + } + + return $effect; + } + + /** + * Converts given string characters to latin characters + * + * @param string $string String to convert + * @param bool $lowerCaseHuman (optional) If is set to true, converted string is returned as lowercase and + * human-readable. Otherwise - as original. + * @param string $replacementChar (optional) Replacement character for all non-latin characters and uppercase + * letters, if 2nd argument is set to true + * @return string + */ + public static function toLatin($string, $lowerCaseHuman = true, $replacementChar = '-') + { + if (is_string($string)) { + $string = trim($string); + } + + /* + * Empty value? + * Nothing to do + */ + if (empty($string)) { + return ''; + } + + $converter = Transliterator::create('Latin-ASCII;'); + + /* + * Oops, cannot instantiate converter + * Nothing to do + */ + if (null === $converter) { + return ''; + } + + $converted = $converter->transliterate($string); + + // Make the string lowercase and human-readable + if ($lowerCaseHuman) { + $matches = []; + $matchCount = preg_match_all('|[A-Z]{1}[^A-Z]*|', $converted, $matches); + + if ($matchCount > 0) { + $parts = $matches[0]; + $converted = mb_strtolower(implode($replacementChar, $parts)); + } + } + + /* + * Let's replace special characters to spaces + * ...and finally spaces to $replacementChar + */ + $replaced = preg_replace('|[^a-zA-Z0-9]|', ' ', $converted); + + return preg_replace('| +|', $replacementChar, trim($replaced)); + } + + /** + * Returns smartly trimmed string. + * If the string is empty, contains only spaces, e.g. " ", nothing is done and the original string is returned. + * + * @param string $string The string to trim + * @return string + */ + public static function trimSmart($string) + { + $trimmed = trim($string); + + if (empty($trimmed)) { + return $string; + } + + return $trimmed; + } + + /** + * Make a string's first character uppercase + * + * @param string $text The text to get uppercase + * @param null|bool $restLowercase (optional) Information that to do with rest of given string + * @return string + * + * Values of the $restLowercase argument: + * - null (default): nothing is done with the string + * - true: the rest of string is lowercased + * - false: the rest of string is uppercased + */ + public static function uppercaseFirst($text, $restLowercase = null) + { + if (empty($text)) { + return ''; + } + + $effect = $text; + + if ($restLowercase) { + $effect = mb_strtolower($effect); + } elseif (false === $restLowercase) { + $effect = mb_strtoupper($effect); + } + + return ucfirst($effect); + } + + /** + * Converts value to non-negative integer (element of the set {0, 1, 2, 3, ...}) + * + * @param mixed $value Value to convert + * @param int $negativeReplacement (optional) Replacement for negative value + * @return int + */ + public static function value2NonNegativeInteger($value, $negativeReplacement = 0) + { + $effect = (int) $value; + + if ($effect < 0) { + return $negativeReplacement; + } + + return $effect; } } diff --git a/src/Utilities/QueryBuilderUtility.php b/src/Utilities/QueryBuilderUtility.php index 8d466b0..392525b 100644 --- a/src/Utilities/QueryBuilderUtility.php +++ b/src/Utilities/QueryBuilderUtility.php @@ -23,25 +23,68 @@ use Doctrine\ORM\QueryBuilder; class QueryBuilderUtility { /** - * Returns root alias of given query builder. - * If null is returned, alias was not found. + * Adds given parameters to given query builder. + * Attention. Existing parameters will be overridden. * - * @param QueryBuilder $queryBuilder The query builder to retrieve root alias - * @return null|string + * @param QueryBuilder $queryBuilder The query builder + * @param array|ArrayCollection $parameters Parameters to add. Collection of Doctrine\ORM\Query\Parameter + * instances or an array with key-value pairs. + * @return QueryBuilder */ - public static function getRootAlias(QueryBuilder $queryBuilder) + public static function addParameters(QueryBuilder $queryBuilder, $parameters) { - $aliases = $queryBuilder->getRootAliases(); - /* - * No aliases? + * No parameters? * Nothing to do */ - if (empty($aliases)) { - return null; + if (empty($parameters)) { + return $queryBuilder; } - return Arrays::getFirstElement($aliases); + foreach ($parameters as $key => $parameter) { + $name = $key; + $value = $parameter; + + if ($parameter instanceof Parameter) { + $name = $parameter->getName(); + $value = $parameter->getValue(); + } + + $queryBuilder->setParameter($name, $value); + } + + return $queryBuilder; + } + + /** + * Deletes given entities + * + * @param EntityManager $entityManager The entity manager + * @param array|ArrayCollection $entities The entities to delete + * @param bool $flushDeleted (optional) If is set to true, flushes the deleted objects (default + * behaviour). Otherwise - not. + * @return bool + */ + public static function deleteEntities(EntityManager $entityManager, $entities, $flushDeleted = true) + { + /* + * No entities provided? + * Nothing to do + */ + if (empty($entities)) { + return false; + } + + foreach ($entities as $entity) { + $entityManager->remove($entity); + } + + // The deleted objects should be flushed? + if ($flushDeleted) { + $entityManager->flush(); + } + + return true; } /** @@ -83,6 +126,28 @@ class QueryBuilderUtility return null; } + /** + * Returns root alias of given query builder. + * If null is returned, alias was not found. + * + * @param QueryBuilder $queryBuilder The query builder to retrieve root alias + * @return null|string + */ + public static function getRootAlias(QueryBuilder $queryBuilder) + { + $aliases = $queryBuilder->getRootAliases(); + + /* + * No aliases? + * Nothing to do + */ + if (empty($aliases)) { + return null; + } + + return Arrays::getFirstElement($aliases); + } + /** * Sets the WHERE criteria in given query builder * @@ -149,69 +214,4 @@ class QueryBuilderUtility return $queryBuilder; } - - /** - * Deletes given entities - * - * @param EntityManager $entityManager The entity manager - * @param array|ArrayCollection $entities The entities to delete - * @param bool $flushDeleted (optional) If is set to true, flushes the deleted objects (default - * behaviour). Otherwise - not. - * @return bool - */ - public static function deleteEntities(EntityManager $entityManager, $entities, $flushDeleted = true) - { - /* - * No entities provided? - * Nothing to do - */ - if (empty($entities)) { - return false; - } - - foreach ($entities as $entity) { - $entityManager->remove($entity); - } - - // The deleted objects should be flushed? - if ($flushDeleted) { - $entityManager->flush(); - } - - return true; - } - - /** - * Adds given parameters to given query builder. - * Attention. Existing parameters will be overridden. - * - * @param QueryBuilder $queryBuilder The query builder - * @param array|ArrayCollection $parameters Parameters to add. Collection of Doctrine\ORM\Query\Parameter - * instances or an array with key-value pairs. - * @return QueryBuilder - */ - public static function addParameters(QueryBuilder $queryBuilder, $parameters) - { - /* - * No parameters? - * Nothing to do - */ - if (empty($parameters)) { - return $queryBuilder; - } - - foreach ($parameters as $key => $parameter) { - $name = $key; - $value = $parameter; - - if ($parameter instanceof Parameter) { - $name = $parameter->getName(); - $value = $parameter->getValue(); - } - - $queryBuilder->setParameter($name, $value); - } - - return $queryBuilder; - } } diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index d6f7ebc..be86a2a 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -30,35 +30,157 @@ use ReflectionProperty; class Reflection { /** - * Returns names of methods for given class / object + * Returns child classes of given class. + * It's an array of namespaces of the child classes or null (if given class has not child classes). * - * @param object|string $class The object or name of object's class - * @param bool $withoutInheritance (optional) If is set to true, only methods for given class are returned. - * Otherwise - all methods, with inherited methods too. - * @return array + * @param array|object|string $class Class who child classes should be returned. An array of objects, strings, + * object or string. + * @return null|array + * @throws CannotResolveClassNameException */ - public static function getMethods($class, bool $withoutInheritance = false): array + public static function getChildClasses($class): ?array { - $effect = []; + $allClasses = get_declared_classes(); - $reflection = new ReflectionClass($class); - $methods = $reflection->getMethods(); + /* + * No classes? + * Nothing to do + */ + if (empty($allClasses)) { + return null; + } - if (!empty($methods)) { - $className = self::getClassName($class); + $className = self::getClassName($class); - foreach ($methods as $method) { - if ($method instanceof ReflectionMethod) { - if ($withoutInheritance && $className !== $method->class) { - continue; - } + // Oops, cannot resolve class + if (null === $className) { + throw CannotResolveClassNameException::create(''); + } - $effect[] = $method->name; + $childClasses = []; + + foreach ($allClasses as $oneClass) { + if (self::isChildOfClass($oneClass, $className)) { + /* + * Attention. I have to use static::getRealClass() method to avoid problem with the proxy / cache + * classes. Example: + * - My\ExtraBundle\Entity\MyEntity + * - Proxies\__CG__\My\ExtraBundle\Entity\MyEntity + * + * It's actually the same class, so I have to skip it. + */ + $realClass = static::getRealClass($oneClass); + + if (in_array($realClass, $childClasses, true)) { + continue; } + + $childClasses[] = $realClass; } } - return $effect; + return $childClasses; + } + + /** + * Returns a class name for given source + * + * @param array|object|string $source An array of objects, namespaces, object or namespace + * @param bool $withoutNamespace (optional) If is set to true, namespace is omitted. Otherwise - + * not, full name of class is returned, with namespace. + * @return null|string + */ + public static function getClassName($source, bool $withoutNamespace = false): ?string + { + /* + * First argument is not proper source of class? + * Nothing to do + */ + if (empty($source) || (!is_array($source) && !is_object($source) && !is_string($source))) { + return null; + } + + $name = ''; + + /* + * An array of objects was provided? + * Let's use first of them + */ + if (is_array($source)) { + $source = Arrays::getFirstElement($source); + } + + // Let's prepare name of class + if (is_object($source)) { + $name = get_class($source); + } elseif (is_string($source) && (class_exists($source) || trait_exists($source))) { + $name = $source; + } + + /* + * Name of class is still unknown? + * Nothing to do + */ + if (empty($name)) { + return null; + } + + /* + * Namespace is not required? + * Let's return name of class only + */ + if ($withoutNamespace) { + $classOnly = Miscellaneous::getLastElementOfString($name, '\\'); + + if (null !== $classOnly) { + $name = $classOnly; + } + + return $name; + } + + return static::getRealClass($name); + } + + /** + * Returns namespace of class for given source + * + * @param array|object|string $source An array of objects, namespaces, object or namespace + * @return string + */ + public static function getClassNamespace($source): string + { + $fullClassName = self::getClassName($source); + + if (null === $fullClassName || '' === $fullClassName) { + return ''; + } + + $className = self::getClassName($source, true); + + if ($className === $fullClassName) { + return $className; + } + + return Miscellaneous::getStringWithoutLastElement($fullClassName, '\\'); + } + + /** + * Returns value of given constant + * + * @param object|string $class The object or name of object's class + * @param string $constant Name of the constant that contains a value + * @return mixed + */ + public static function getConstantValue($class, string $constant) + { + $reflection = new ReflectionClass($class); + + if (self::hasConstant($class, $constant)) { + return $reflection->getConstant($constant); + } + + return null; } /** @@ -101,60 +223,160 @@ class Reflection } /** - * Returns information if given class / object has given method + * Returns names of methods for given class / object * - * @param object|string $class The object or name of object's class - * @param string $method Name of the method to find - * @return bool + * @param object|string $class The object or name of object's class + * @param bool $withoutInheritance (optional) If is set to true, only methods for given class are returned. + * Otherwise - all methods, with inherited methods too. + * @return array */ - public static function hasMethod($class, string $method): bool + public static function getMethods($class, bool $withoutInheritance = false): array { - $reflection = new ReflectionClass($class); + $effect = []; - return $reflection->hasMethod($method); + $reflection = new ReflectionClass($class); + $methods = $reflection->getMethods(); + + if (!empty($methods)) { + $className = self::getClassName($class); + + foreach ($methods as $method) { + if ($method instanceof ReflectionMethod) { + if ($withoutInheritance && $className !== $method->class) { + continue; + } + + $effect[] = $method->name; + } + } + } + + return $effect; } /** - * Returns information if given class / object has given property + * Returns namespace of one child class which extends given class. + * Extended class should has only one child class. * - * @param object|string $class The object or name of object's class - * @param string $property Name of the property to find - * @return bool - */ - public static function hasProperty($class, string $property): bool - { - $reflection = new ReflectionClass($class); - - return $reflection->hasProperty($property); - } - - /** - * Returns information if given class / object has given constant - * - * @param object|string $class The object or name of object's class - * @param string $constant Name of the constant to find - * @return bool - */ - public static function hasConstant($class, string $constant): bool - { - $reflection = new ReflectionClass($class); - - return $reflection->hasConstant($constant); - } - - /** - * Returns value of given constant - * - * @param object|string $class The object or name of object's class - * @param string $constant Name of the constant that contains a value + * @param array|object|string $parentClass Class who child class should be returned. An array of objects, + * namespaces, object or namespace. * @return mixed + * @throws TooManyChildClassesException|MissingChildClassesException|CannotResolveClassNameException */ - public static function getConstantValue($class, string $constant) + public static function getOneChildClass($parentClass) { - $reflection = new ReflectionClass($class); + $childClasses = self::getChildClasses($parentClass); - if (self::hasConstant($class, $constant)) { - return $reflection->getConstant($constant); + /* + * No child classes? + * Oops, the base / parent class hasn't child class + */ + if (empty($childClasses)) { + throw MissingChildClassesException::create($parentClass); + } + + /* + * More than 1 child class? + * Oops, the base / parent class has too many child classes + */ + if (count($childClasses) > 1) { + throw TooManyChildClassesException::create($parentClass, $childClasses); + } + + return trim($childClasses[0]); + } + + /** + * Returns a parent class or false if there is no parent class + * + * @param array|object|string $source An array of objects, namespaces, object or namespace + * @return false|ReflectionClass + */ + public static function getParentClass($source) + { + $className = self::getClassName($source); + $reflection = new ReflectionClass($className); + + return $reflection->getParentClass(); + } + + /** + * Returns name of the parent class. + * If given class does not extend another, returns null. + * + * @param array|object|string $class An array of objects, namespaces, object or namespace + * @return null|string + */ + public static function getParentClassName($class): ?string + { + $className = self::getClassName($class); + $reflection = new ReflectionClass($className); + $parentClass = $reflection->getParentClass(); + + if (null === $parentClass || false === $parentClass) { + return null; + } + + return $parentClass->getName(); + } + + /** + * Returns given object properties + * + * @param array|object|string $source An array of objects, namespaces, object or namespace + * @param int $filter (optional) Filter of properties. Uses \ReflectionProperty class + * constants. By default all properties are returned. + * @param bool $includeParents (optional) If is set to true, properties of parent classes are + * included (recursively). Otherwise - not. + * @return ReflectionProperty[] + */ + public static function getProperties($source, int $filter = null, bool $includeParents = false): array + { + $className = self::getClassName($source); + $reflection = new ReflectionClass($className); + + if (null === $filter) { + $filter = ReflectionProperty::IS_PRIVATE + + ReflectionProperty::IS_PROTECTED + + ReflectionProperty::IS_PUBLIC + + ReflectionProperty::IS_STATIC; + } + + $properties = $reflection->getProperties($filter); + $parentProperties = []; + + if ($includeParents) { + $parent = self::getParentClass($source); + + if (false !== $parent) { + $parentClass = $parent->getName(); + $parentProperties = self::getProperties($parentClass, $filter, $includeParents); + } + } + + return array_merge($properties, $parentProperties); + } + + /** + * Returns property, the \ReflectionProperty instance, of given object + * + * @param array|object|string $class An array of objects, namespaces, object or namespace + * @param string $property Name of the property + * @param int|null $filter (optional) Filter of properties. Uses \ReflectionProperty class constants. + * By default all properties are allowed / processed. + * @return null|ReflectionProperty + */ + public static function getProperty($class, string $property, int $filter = null): ?ReflectionProperty + { + $className = self::getClassName($class); + $properties = self::getProperties($className, $filter); + + if (!empty($properties)) { + foreach ($properties as $reflectionProperty) { + if ($reflectionProperty->getName() === $property) { + return $reflectionProperty; + } + } } return null; @@ -243,101 +465,45 @@ class Reflection } /** - * Returns a class name for given source + * Returns information if given class / object has given constant * - * @param array|object|string $source An array of objects, namespaces, object or namespace - * @param bool $withoutNamespace (optional) If is set to true, namespace is omitted. Otherwise - - * not, full name of class is returned, with namespace. - * @return null|string - */ - public static function getClassName($source, bool $withoutNamespace = false): ?string - { - /* - * First argument is not proper source of class? - * Nothing to do - */ - if (empty($source) || (!is_array($source) && !is_object($source) && !is_string($source))) { - return null; - } - - $name = ''; - - /* - * An array of objects was provided? - * Let's use first of them - */ - if (is_array($source)) { - $source = Arrays::getFirstElement($source); - } - - // Let's prepare name of class - if (is_object($source)) { - $name = get_class($source); - } elseif (is_string($source) && (class_exists($source) || trait_exists($source))) { - $name = $source; - } - - /* - * Name of class is still unknown? - * Nothing to do - */ - if (empty($name)) { - return null; - } - - /* - * Namespace is not required? - * Let's return name of class only - */ - if ($withoutNamespace) { - $classOnly = Miscellaneous::getLastElementOfString($name, '\\'); - - if (null !== $classOnly) { - $name = $classOnly; - } - - return $name; - } - - return static::getRealClass($name); - } - - /** - * Returns namespace of class for given source - * - * @param array|object|string $source An array of objects, namespaces, object or namespace - * @return string - */ - public static function getClassNamespace($source): string - { - $fullClassName = self::getClassName($source); - - if (null === $fullClassName || '' === $fullClassName) { - return ''; - } - - $className = self::getClassName($source, true); - - if ($className === $fullClassName) { - return $className; - } - - return Miscellaneous::getStringWithoutLastElement($fullClassName, '\\'); - } - - /** - * Returns information if given interface is implemented by given class / object - * - * @param array|object|string $source An array of objects, namespaces, object or namespace - * @param string $interface The interface that should be implemented + * @param object|string $class The object or name of object's class + * @param string $constant Name of the constant to find * @return bool */ - public static function isInterfaceImplemented($source, string $interface): bool + public static function hasConstant($class, string $constant): bool { - $className = self::getClassName($source); - $interfaces = class_implements($className); + $reflection = new ReflectionClass($class); - return in_array($interface, $interfaces, true); + return $reflection->hasConstant($constant); + } + + /** + * Returns information if given class / object has given method + * + * @param object|string $class The object or name of object's class + * @param string $method Name of the method to find + * @return bool + */ + public static function hasMethod($class, string $method): bool + { + $reflection = new ReflectionClass($class); + + return $reflection->hasMethod($method); + } + + /** + * Returns information if given class / object has given property + * + * @param object|string $class The object or name of object's class + * @param string $property Name of the property to find + * @return bool + */ + public static function hasProperty($class, string $property): bool + { + $reflection = new ReflectionClass($class); + + return $reflection->hasProperty($property); } /** @@ -362,164 +528,69 @@ class Reflection } /** - * Returns given object properties + * Returns information if given interface is implemented by given class / object * - * @param array|object|string $source An array of objects, namespaces, object or namespace - * @param int $filter (optional) Filter of properties. Uses \ReflectionProperty class - * constants. By default all properties are returned. - * @param bool $includeParents (optional) If is set to true, properties of parent classes are - * included (recursively). Otherwise - not. - * @return ReflectionProperty[] + * @param array|object|string $source An array of objects, namespaces, object or namespace + * @param string $interface The interface that should be implemented + * @return bool */ - public static function getProperties($source, int $filter = null, bool $includeParents = false): array + public static function isInterfaceImplemented($source, string $interface): bool { $className = self::getClassName($source); - $reflection = new ReflectionClass($className); + $interfaces = class_implements($className); - if (null === $filter) { - $filter = ReflectionProperty::IS_PRIVATE - + ReflectionProperty::IS_PROTECTED - + ReflectionProperty::IS_PUBLIC - + ReflectionProperty::IS_STATIC; - } - - $properties = $reflection->getProperties($filter); - $parentProperties = []; - - if ($includeParents) { - $parent = self::getParentClass($source); - - if (false !== $parent) { - $parentClass = $parent->getName(); - $parentProperties = self::getProperties($parentClass, $filter, $includeParents); - } - } - - return array_merge($properties, $parentProperties); + return in_array($interface, $interfaces, true); } /** - * Returns a parent class or false if there is no parent class + * Sets values of properties in given object * - * @param array|object|string $source An array of objects, namespaces, object or namespace - * @return false|ReflectionClass + * @param mixed $object Object that should contains given property + * @param array $propertiesValues Key-value pairs, where key - name of the property, value - value of the property */ - public static function getParentClass($source) + public static function setPropertiesValues($object, array $propertiesValues): void { - $className = self::getClassName($source); - $reflection = new ReflectionClass($className); - - return $reflection->getParentClass(); - } - - /** - * Returns child classes of given class. - * It's an array of namespaces of the child classes or null (if given class has not child classes). - * - * @param array|object|string $class Class who child classes should be returned. An array of objects, strings, - * object or string. - * @return null|array - * @throws CannotResolveClassNameException - */ - public static function getChildClasses($class): ?array - { - $allClasses = get_declared_classes(); - /* - * No classes? + * No properties? * Nothing to do */ - if (empty($allClasses)) { - return null; + if (empty($propertiesValues)) { + return; } - $className = self::getClassName($class); - - // Oops, cannot resolve class - if (null === $className) { - throw CannotResolveClassNameException::create(''); + foreach ($propertiesValues as $property => $value) { + static::setPropertyValue($object, $property, $value); } - - $childClasses = []; - - foreach ($allClasses as $oneClass) { - if (self::isChildOfClass($oneClass, $className)) { - /* - * Attention. I have to use static::getRealClass() method to avoid problem with the proxy / cache - * classes. Example: - * - My\ExtraBundle\Entity\MyEntity - * - Proxies\__CG__\My\ExtraBundle\Entity\MyEntity - * - * It's actually the same class, so I have to skip it. - */ - $realClass = static::getRealClass($oneClass); - - if (in_array($realClass, $childClasses, true)) { - continue; - } - - $childClasses[] = $realClass; - } - } - - return $childClasses; } /** - * Returns namespace of one child class which extends given class. - * Extended class should has only one child class. + * Sets value of given property in given object * - * @param array|object|string $parentClass Class who child class should be returned. An array of objects, - * namespaces, object or namespace. - * @return mixed - * @throws TooManyChildClassesException|MissingChildClassesException|CannotResolveClassNameException + * @param mixed $object Object that should contains given property + * @param string $property Name of the property + * @param mixed $value Value of the property + * @throws NotExistingPropertyException */ - public static function getOneChildClass($parentClass) + public static function setPropertyValue($object, string $property, $value): void { - $childClasses = self::getChildClasses($parentClass); + $reflectionProperty = self::getProperty($object, $property); - /* - * No child classes? - * Oops, the base / parent class hasn't child class - */ - if (empty($childClasses)) { - throw MissingChildClassesException::create($parentClass); + // Oops, property does not exist + if (null === $reflectionProperty) { + throw NotExistingPropertyException::create($object, $property); } - /* - * More than 1 child class? - * Oops, the base / parent class has too many child classes - */ - if (count($childClasses) > 1) { - throw TooManyChildClassesException::create($parentClass, $childClasses); + $isPublic = $reflectionProperty->isPublic(); + + if (!$isPublic) { + $reflectionProperty->setAccessible(true); } - return trim($childClasses[0]); - } + $reflectionProperty->setValue($object, $value); - /** - * Returns property, the \ReflectionProperty instance, of given object - * - * @param array|object|string $class An array of objects, namespaces, object or namespace - * @param string $property Name of the property - * @param int|null $filter (optional) Filter of properties. Uses \ReflectionProperty class constants. - * By default all properties are allowed / processed. - * @return null|ReflectionProperty - */ - public static function getProperty($class, string $property, int $filter = null): ?ReflectionProperty - { - $className = self::getClassName($class); - $properties = self::getProperties($className, $filter); - - if (!empty($properties)) { - foreach ($properties as $reflectionProperty) { - if ($reflectionProperty->getName() === $property) { - return $reflectionProperty; - } - } + if (!$isPublic) { + $reflectionProperty->setAccessible(false); } - - return null; } /** @@ -563,135 +634,6 @@ class Reflection return $uses; } - /** - * Returns name of the parent class. - * If given class does not extend another, returns null. - * - * @param array|object|string $class An array of objects, namespaces, object or namespace - * @return null|string - */ - public static function getParentClassName($class): ?string - { - $className = self::getClassName($class); - $reflection = new ReflectionClass($className); - $parentClass = $reflection->getParentClass(); - - if (null === $parentClass || false === $parentClass) { - return null; - } - - return $parentClass->getName(); - } - - /** - * Sets value of given property in given object - * - * @param mixed $object Object that should contains given property - * @param string $property Name of the property - * @param mixed $value Value of the property - * @throws NotExistingPropertyException - */ - public static function setPropertyValue($object, string $property, $value): void - { - $reflectionProperty = self::getProperty($object, $property); - - // Oops, property does not exist - if (null === $reflectionProperty) { - throw NotExistingPropertyException::create($object, $property); - } - - $isPublic = $reflectionProperty->isPublic(); - - if (!$isPublic) { - $reflectionProperty->setAccessible(true); - } - - $reflectionProperty->setValue($object, $value); - - if (!$isPublic) { - $reflectionProperty->setAccessible(false); - } - } - - /** - * Sets values of properties in given object - * - * @param mixed $object Object that should contains given property - * @param array $propertiesValues Key-value pairs, where key - name of the property, value - value of the property - */ - public static function setPropertiesValues($object, array $propertiesValues): void - { - /* - * No properties? - * Nothing to do - */ - if (empty($propertiesValues)) { - return; - } - - foreach ($propertiesValues as $property => $value) { - static::setPropertyValue($object, $property, $value); - } - } - - /** - * Returns the real class name of a class name that could be a proxy - * - * @param string $class Class to verify - * @return string - */ - private static function getRealClass(string $class): string - { - if (false === $pos = strrpos($class, '\\' . Proxy::MARKER . '\\')) { - return $class; - } - - return substr($class, $pos + Proxy::MARKER_LENGTH + 2); - } - - /** - * Returns value of given property using the property represented by reflection. - * If value cannot be fetched, makes the property accessible temporarily. - * - * @param mixed $object Object that should contains given property - * @param string $property Name of the property that contains a value - * @param null|ReflectionProperty $reflectionProperty (optional) Property represented by reflection - * @return mixed - */ - private static function getPropertyValueByReflectionProperty( - $object, - string $property, - ?ReflectionProperty $reflectionProperty = null - ) { - $value = null; - $valueFound = false; - $className = self::getClassName($object); - - try { - if (null === $reflectionProperty) { - $reflectionProperty = new ReflectionProperty($className, $property); - } - - $value = $reflectionProperty->getValue($object); - $valueFound = true; - } catch (ReflectionException $exception) { - } - - if (null !== $reflectionProperty) { - $reflectionProperty->setAccessible(true); - - $value = $reflectionProperty->getValue($object); - $valueFound = true; - - $reflectionProperty->setAccessible(false); - } - - return [ - $value, - $valueFound, - ]; - } - /** * Returns value of given property using getter of the property * @@ -828,4 +770,62 @@ class Reflection return null; } + + /** + * Returns value of given property using the property represented by reflection. + * If value cannot be fetched, makes the property accessible temporarily. + * + * @param mixed $object Object that should contains given property + * @param string $property Name of the property that contains a value + * @param null|ReflectionProperty $reflectionProperty (optional) Property represented by reflection + * @return mixed + */ + private static function getPropertyValueByReflectionProperty( + $object, + string $property, + ?ReflectionProperty $reflectionProperty = null + ) { + $value = null; + $valueFound = false; + $className = self::getClassName($object); + + try { + if (null === $reflectionProperty) { + $reflectionProperty = new ReflectionProperty($className, $property); + } + + $value = $reflectionProperty->getValue($object); + $valueFound = true; + } catch (ReflectionException $exception) { + } + + if (null !== $reflectionProperty) { + $reflectionProperty->setAccessible(true); + + $value = $reflectionProperty->getValue($object); + $valueFound = true; + + $reflectionProperty->setAccessible(false); + } + + return [ + $value, + $valueFound, + ]; + } + + /** + * Returns the real class name of a class name that could be a proxy + * + * @param string $class Class to verify + * @return string + */ + private static function getRealClass(string $class): string + { + if (false === $pos = strrpos($class, '\\'.Proxy::MARKER.'\\')) { + return $class; + } + + return substr($class, $pos + Proxy::MARKER_LENGTH + 2); + } } diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index e605dd5..78fab4d 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -10,6 +10,7 @@ namespace Meritoo\Common\Utilities; use Meritoo\Common\Exception\Regex\IncorrectColorHexLengthException; use Meritoo\Common\Exception\Regex\InvalidColorHexValueException; +use Transliterator; /** * Useful methods related to regular expressions @@ -25,23 +26,23 @@ class Regex * @var array */ private static $patterns = [ - 'email' => '/^[\w\-.]{2,}@[\w\-]+\.[\w]{2,}+$/', - 'phone' => '/^\+?[0-9 ]+$/', - 'camelCasePart' => '/([a-z]|[A-Z]){1}[a-z]*/', - 'urlProtocol' => '/^([a-z]+:\/\/)', - 'urlDomain' => '([\da-z\.-]+)\.([a-z\.]{2,6})(\/)?([\w\.\-]*)?(\?)?([\w \.\-\/=&]*)\/?$/i', - 'letterOrDigit' => '/[a-zA-Z0-9]+/', - 'htmlEntity' => '/&[a-z0-9]+;/', - 'htmlAttribute' => '/([\w-]+)="([\w -]+)"/', - 'fileName' => '/[\w.\- +=!@$&()?]+\.\w+$/', // e.g. "this-1_2 3 & my! 4+file.jpg" - 'isQuoted' => '/^[\'"]{1}.+[\'"]{1}$/', + 'email' => '/^[\w\-.]{2,}@[\w\-]+\.[\w]{2,}+$/', + 'phone' => '/^\+?[0-9 ]+$/', + 'camelCasePart' => '/([a-z]|[A-Z]){1}[a-z]*/', + 'urlProtocol' => '/^([a-z]+:\/\/)', + 'urlDomain' => '([\da-z\.-]+)\.([a-z\.]{2,6})(\/)?([\w\.\-]*)?(\?)?([\w \.\-\/=&]*)\/?$/i', + 'letterOrDigit' => '/[a-zA-Z0-9]+/', + 'htmlEntity' => '/&[a-z0-9]+;/', + 'htmlAttribute' => '/([\w-]+)="([\w -]+)"/', + 'fileName' => '/[\w.\- +=!@$&()?]+\.\w+$/', // e.g. "this-1_2 3 & my! 4+file.jpg" + 'isQuoted' => '/^[\'"]{1}.+[\'"]{1}$/', 'windowsBasedPath' => '/^[A-Z]{1}:\\\.*$/', - 'money' => '/^[-+]?\d+([\.,]{1}\d*)?$/', - 'color' => '/^[a-f0-9]{6}$/i', - 'bundleName' => '/^(([A-Z]{1}[a-z0-9]+)((?2))*)(Bundle)$/', - 'binaryValue' => '/[^\x20-\x7E\t\r\n]/', - 'beginningSlash' => '|^\/|', - 'endingSlash' => '|\/$|', + 'money' => '/^[-+]?\d+([\.,]{1}\d*)?$/', + 'color' => '/^[a-f0-9]{6}$/i', + 'bundleName' => '/^(([A-Z]{1}[a-z0-9]+)((?2))*)(Bundle)$/', + 'binaryValue' => '/[^\x20-\x7E\t\r\n]/', + 'beginningSlash' => '|^\/|', + 'endingSlash' => '|\/$|', /* * Matches: @@ -53,175 +54,28 @@ class Regex * * Contains "%s" that should be replaced with separator used to split width and height. */ - 'size' => '/^[\ ]*(\d+)[\ ]*%s[\ ]*(\d+)[\ ]*$/', + 'size' => '/^[\ ]*(\d+)[\ ]*%s[\ ]*(\d+)[\ ]*$/', ]; /** - * Returns information if given e-mail address is valid + * Returns information if given html attributes are valid * - * @param string $email E-mail address to validate / verify + * @param string $htmlAttributes The html attributes to verify * @return bool - * - * Examples: - * a) valid e-mails: - * - ni@g-m.pl - * - ni@gm.pl - * - ni@g_m.pl - * b) invalid e-mails: - * - ni@g-m.p - * - n@g-m.pl */ - public static function isValidEmail($email) + public static function areValidHtmlAttributes($htmlAttributes) { /* * Not a string? * Nothing to do */ - if (!is_string($email)) { + if (!is_string($htmlAttributes)) { return false; } - $pattern = self::getEmailPattern(); + $pattern = self::getHtmlAttributePattern(); - return (bool)preg_match($pattern, $email); - } - - /** - * Returns information if given tax ID is valid (in Poland it's named "NIP") - * - * @param string $taxIdString Tax ID (NIP) string - * @return bool - */ - public static function isValidTaxId($taxIdString) - { - /* - * Not a string? - * Nothing to do - */ - if (!is_string($taxIdString)) { - return false; - } - - /* - * Empty/Unknown value? - * Nothing to do - */ - if (empty($taxIdString)) { - return false; - } - - $taxId = preg_replace('/[\s-]/', '', $taxIdString); - - /* - * Tax ID is not 10 characters length OR is not numeric? - * Nothing to do - */ - if (!is_numeric($taxId) || 10 !== strlen($taxId)) { - return false; - } - - $weights = [ - 6, - 5, - 7, - 2, - 3, - 4, - 5, - 6, - 7, - ]; - - $sum = 0; - - for ($x = 0; $x <= 8; ++$x) { - $sum += $taxId[$x] * $weights[$x]; - } - - /* - * Last number it's a remainder from dividing per 11? - * Tax ID is valid - */ - - return $sum % 11 === (int)$taxId[9]; - } - - /** - * Returns information if given url address is valid - * - * @param string $url The url to validate / verify - * @param bool $requireProtocol (optional) If is set to true, the protocol is required to be passed in the url. - * Otherwise - not. - * @return bool - */ - public static function isValidUrl($url, $requireProtocol = false) - { - /* - * Not a string? - * Nothing to do - */ - if (!is_string($url)) { - return false; - } - - $pattern = self::getUrlPattern($requireProtocol); - - return (bool)preg_match($pattern, $url); - } - - /** - * Returns information if given phone number is valid - * - * @param string $phoneNumber The phone number to validate / verify - * @return bool - */ - public static function isValidPhoneNumber($phoneNumber) - { - /* - * Not a string? - * Nothing to do - */ - if (!is_string($phoneNumber)) { - return false; - } - - $pattern = self::getPhoneNumberPattern(); - - return (bool)preg_match($pattern, trim($phoneNumber)); - } - - /** - * Returns array values that match given pattern (or values that keys match the pattern) - * - * @param string $pattern Pattern to match - * @param array $array The array (scalar values only) - * @param bool $itsKeyPattern (optional) If is set to true, keys will be checked if they match pattern. - * Otherwise - values will be checked (default behaviour). - * @return array - */ - public static function getArrayValuesByPattern($pattern, array $array, $itsKeyPattern = false) - { - /* - * No elements? - * Nothing to do - */ - if (empty($array)) { - return []; - } - - if ($itsKeyPattern) { - $effect = []; - - foreach ($array as $key => $value) { - if ((bool)preg_match($pattern, $key)) { - $effect[$key] = $value; - } - } - - return $effect; - } - - return preg_grep($pattern, $array); + return (bool) preg_match_all($pattern, $htmlAttributes); } /** @@ -285,48 +139,6 @@ class Regex return $effect; } - /** - * Performs regular expression match with many given patterns. - * Returns information if given $subject matches one or all given $patterns. - * - * @param array|string $patterns The patterns to match - * @param string $subject The string to check - * @param bool $mustAllMatch (optional) If is set to true, $subject must match all $patterns. Otherwise - - * not (default behaviour). - * @return bool - */ - public static function pregMultiMatch($patterns, $subject, $mustAllMatch = false) - { - /* - * No patterns? - * Nothing to do - */ - if (empty($patterns)) { - return false; - } - - $effect = false; - $patterns = Arrays::makeArray($patterns); - - if ($mustAllMatch) { - $effect = true; - } - - foreach ($patterns as $pattern) { - $matched = (bool)preg_match_all($pattern, $subject); - - if ($mustAllMatch) { - $effect = $effect && $matched; - } elseif ($matched) { - $effect = $matched; - - break; - } - } - - return $effect; - } - /** * Returns string in human readable style generated from given camel case string / text * @@ -356,21 +168,6 @@ class Regex return $string; } - /** - * Returns parts of given camel case string / text - * - * @param string $string The string / text to retrieve parts - * @return array - */ - public static function getCamelCaseParts($string) - { - $pattern = self::getCamelCasePartPattern(); - $matches = []; - preg_match_all($pattern, $string, $matches); - - return $matches[0]; - } - /** * Returns simple, lowercase string generated from given camel case string / text * @@ -394,6 +191,184 @@ class Regex return $string; } + public static function clearBeginningSlash(string $string): string + { + $pattern = static::$patterns['beginningSlash']; + + return preg_replace($pattern, '', $string); + } + + public static function clearEndingSlash(string $string): string + { + $pattern = static::$patterns['endingSlash']; + + return preg_replace($pattern, '', $string); + } + + /** + * Returns information if one string contains another string + * + * @param string $haystack The string to search in + * @param string $needle The string to be search for + * @return bool + */ + public static function contains($haystack, $needle) + { + if (1 === strlen($needle) && !self::isLetterOrDigit($needle)) { + $needle = '\\'.$needle; + } + + return (bool) preg_match('|.*'.$needle.'.*|', $haystack); + } + + /** + * Returns information if the string contains html entities + * + * @param string $string String to check + * @return bool + */ + public static function containsEntities($string) + { + $pattern = self::getHtmlEntityPattern(); + + return (bool) preg_match_all($pattern, $string); + } + + /** + * Returns slug for given value + * + * @param string $value Value that should be transformed to slug + * @return bool|string + */ + public static function createSlug($value) + { + /* + * Not a scalar value? + * Nothing to do + */ + if (!is_scalar($value)) { + return false; + } + + /* + * It's an empty string? + * Nothing to do + */ + if ('' === $value) { + return ''; + } + + $id = 'Latin-ASCII; NFD; [:Nonspacing Mark:] Remove; NFC; [:Punctuation:] Remove; Lower();'; + $transliterator = Transliterator::create($id); + + $cleanValue = trim($value); + $result = $transliterator->transliterate($cleanValue); + + return preg_replace('/[-\s]+/', '-', $result); + } + + /** + * Returns information if the string ends with given ending / characters + * + * @param string $string String to check + * @param string $ending The ending of string, one or more characters + * @return bool + */ + public static function endsWith($string, $ending) + { + if (1 === strlen($ending) && !self::isLetterOrDigit($ending)) { + $ending = '\\'.$ending; + } + + return (bool) preg_match('|'.$ending.'$|', $string); + } + + /** + * Returns information if the string ends with directory's separator + * + * @param string $text String that may contain a directory's separator at the end + * @param string $separator (optional) The directory's separator, e.g. "/". If is empty (not provided), system's + * separator is used. + * @return string + */ + public static function endsWithDirectorySeparator($text, $separator = '') + { + if (empty($separator)) { + $separator = DIRECTORY_SEPARATOR; + } + + return self::endsWith($text, $separator); + } + + /** + * Returns array values that match given pattern (or values that keys match the pattern) + * + * @param string $pattern Pattern to match + * @param array $array The array (scalar values only) + * @param bool $itsKeyPattern (optional) If is set to true, keys will be checked if they match pattern. + * Otherwise - values will be checked (default behaviour). + * @return array + */ + public static function getArrayValuesByPattern($pattern, array $array, $itsKeyPattern = false) + { + /* + * No elements? + * Nothing to do + */ + if (empty($array)) { + return []; + } + + if ($itsKeyPattern) { + $effect = []; + + foreach ($array as $key => $value) { + if ((bool) preg_match($pattern, $key)) { + $effect[$key] = $value; + } + } + + return $effect; + } + + return preg_grep($pattern, $array); + } + + /** + * Returns pattern used to validate / verify name of bundle + * + * @return string + */ + public static function getBundleNamePattern() + { + return self::$patterns['bundleName']; + } + + /** + * Returns pattern used to validate / verify or get camel case parts of string + * + * @return string + */ + public static function getCamelCasePartPattern() + { + return self::$patterns['camelCasePart']; + } + + /** + * Returns parts of given camel case string / text + * + * @param string $string The string / text to retrieve parts + * @return array + */ + public static function getCamelCaseParts($string) + { + $pattern = self::getCamelCasePartPattern(); + $matches = []; + preg_match_all($pattern, $string, $matches); + + return $matches[0]; + } + /** * Returns pattern used to validate / verify or get e-mail address * @@ -404,6 +379,66 @@ class Regex return self::$patterns['email']; } + /** + * Returns pattern used to validate / verify name of file + * + * @return string + */ + public static function getFileNamePattern(): string + { + return self::$patterns['fileName']; + } + + /** + * Returns pattern used to validate / verify html attribute + * + * @return string + */ + public static function getHtmlAttributePattern() + { + return self::$patterns['htmlAttribute']; + } + + /** + * Returns pattern used to validate / verify html entity + * + * @return string + */ + public static function getHtmlEntityPattern() + { + return self::$patterns['htmlEntity']; + } + + /** + * Returns pattern used to validate / verify if value is quoted (by apostrophes or quotation marks) + * + * @return string + */ + public static function getIsQuotedPattern() + { + return self::$patterns['isQuoted']; + } + + /** + * Returns pattern used to validate / verify letter or digit + * + * @return string + */ + public static function getLetterOrDigitPattern() + { + return self::$patterns['letterOrDigit']; + } + + /** + * Returns pattern used to validate / verify if given value is money-related value + * + * @return string + */ + public static function getMoneyPattern() + { + return self::$patterns['money']; + } + /** * Returns pattern used to validate / verify or get phone number * @@ -415,13 +450,31 @@ class Regex } /** - * Returns pattern used to validate / verify or get camel case parts of string + * Returns pattern used to validate / verify size * + * @param string $separator (optional) Separator used to split width and height. Default: " x ". * @return string */ - public static function getCamelCasePartPattern() + public static function getSizePattern($separator = ' x ') { - return self::$patterns['camelCasePart']; + $escapeMe = [ + '/', + '|', + '.', + '(', + ')', + '[', + ']', + ]; + + $cleanSeparator = trim($separator); + + if (in_array($cleanSeparator, $escapeMe, true)) { + // I have to escape special character of regular expression that may be used as separator + $separator = str_replace($cleanSeparator, '\\'.$cleanSeparator, $separator); + } + + return sprintf(self::$patterns['size'], $separator); } /** @@ -444,6 +497,161 @@ class Regex return sprintf('%s%s%s', $urlProtocol, $protocolPatternPart, $urlDomain); } + /** + * Returns valid given hexadecimal value of color. + * If the value is invalid, throws an exception or returns false. + * + * @param string $color Color to verify + * @param bool $throwException (optional) If is set to true, throws an exception if given color is invalid + * (default behaviour). Otherwise - not. + * @return bool|string + * @throws InvalidColorHexValueException + * @throws IncorrectColorHexLengthException + */ + public static function getValidColorHexValue($color, $throwException = true) + { + // Not a scalar value? + if (!is_scalar($color)) { + return false; + } + + $color = Miscellaneous::replace($color, '/#/', ''); + $length = strlen($color); + + // Color hasn't 3 or 6 characters length? + if (3 !== $length && 6 !== $length) { + if ($throwException) { + throw new IncorrectColorHexLengthException($color); + } + + return false; + } + + // Make the color 6 characters length, if has 3 + if (3 === $length) { + $color = Miscellaneous::replace($color, '/(.)(.)(.)/', '$1$1$2$2$3$3'); + } + + $pattern = self::$patterns['color']; + $match = (bool) preg_match($pattern, $color); + + // It's not a valid color + if (!$match) { + if ($throwException) { + throw new InvalidColorHexValueException($color); + } + + return false; + } + + return strtolower($color); + } + + /** + * Returns pattern used to validate / verify if given path is a Windows-based path, e.g. "C:\path\to\file.jpg" + * + * @return string + */ + public static function getWindowsBasedPathPattern() + { + return self::$patterns['windowsBasedPath']; + } + + /** + * Returns information if given value is a binary value + * + * @param string $value Value to verify + * @return bool + */ + public static function isBinaryValue($value) + { + /* + * Not a string? + * Nothing to do + */ + if (!is_string($value)) { + return false; + } + + $pattern = self::$patterns['binaryValue']; + + return (bool) preg_match($pattern, $value); + } + + /** + * Returns information if given name of file is a really name of file. + * Verifies if given name contains a dot and an extension, e.g. "My File 001.jpg". + * + * @param string $fileName Name of file to check. It may be path of file also. + * @return bool + */ + public static function isFileName(string $fileName): bool + { + $pattern = self::getFileNamePattern(); + + return (bool) preg_match($pattern, $fileName); + } + + /** + * Returns information if given character is a letter or digit + * + * @param string $char Character to check + * @return bool + */ + public static function isLetterOrDigit($char) + { + $pattern = self::getLetterOrDigitPattern(); + + return is_scalar($char) && (bool) preg_match($pattern, $char); + } + + /** + * Returns information if given value is quoted (by apostrophes or quotation marks) + * + * @param mixed $value The value to check + * @return bool + */ + public static function isQuoted($value) + { + $pattern = self::getIsQuotedPattern(); + + return is_scalar($value) && (bool) preg_match($pattern, $value); + } + + /** + * Returns information if uri contains parameter + * + * @param string $uri Uri string (e.g. $_SERVER['REQUEST_URI']) + * @param string $parameterName Uri parameter name + * @return bool + */ + public static function isSetUriParameter($uri, $parameterName) + { + return (bool) preg_match('|[?&]{1}'.$parameterName.'=|', $uri); // e.g. ?name=phil&type=4 -> '$type=' + } + + /** + * Returns information if given value is a size value + * + * @param string $value Value to verify + * @param string $separator (optional) Separator used to split width and height. Default: " x ". + * @return bool + */ + public static function isSizeValue($value, $separator = ' x ') + { + /* + * Not a string? + * Nothing to do + */ + if (!is_string($value)) { + return false; + } + + $pattern = self::getSizePattern($separator); + + return (bool) preg_match($pattern, $value); + } + /** * Returns information if given path is sub-path of another path, e.g. path file is owned by path of directory * @@ -471,223 +679,100 @@ class Regex $pattern = sprintf('/^%s.*/', $prepared); - return (bool)preg_match($pattern, $subPath); + return (bool) preg_match($pattern, $subPath); } /** - * Returns pattern used to validate / verify letter or digit + * Returns information if given name of bundle is valid * - * @return string - */ - public static function getLetterOrDigitPattern() - { - return self::$patterns['letterOrDigit']; - } - - /** - * Returns information if given character is a letter or digit - * - * @param string $char Character to check + * @param string $bundleName Full name of bundle to verify, e.g. "MyExtraBundle" * @return bool */ - public static function isLetterOrDigit($char) + public static function isValidBundleName($bundleName) { - $pattern = self::getLetterOrDigitPattern(); - - return is_scalar($char) && (bool)preg_match($pattern, $char); - } - - /** - * Returns information if the string starts with given beginning / characters - * - * @param string $string String to check - * @param string $beginning The beginning of string, one or more characters - * @return bool - */ - public static function startsWith($string, $beginning) - { - if (!empty($string) && !empty($beginning)) { - if (1 === strlen($beginning) && !self::isLetterOrDigit($beginning)) { - $beginning = '\\' . $beginning; - } - - $pattern = sprintf('|^%s|', $beginning); - - return (bool)preg_match($pattern, $string); + /* + * Not a string? + * Nothing to do + */ + if (!is_string($bundleName)) { + return false; } - return false; + $pattern = self::getBundleNamePattern(); + + return (bool) preg_match($pattern, $bundleName); } /** - * Returns information if the string ends with given ending / characters + * Returns information if given e-mail address is valid * - * @param string $string String to check - * @param string $ending The ending of string, one or more characters + * @param string $email E-mail address to validate / verify * @return bool + * + * Examples: + * a) valid e-mails: + * - ni@g-m.pl + * - ni@gm.pl + * - ni@g_m.pl + * b) invalid e-mails: + * - ni@g-m.p + * - n@g-m.pl */ - public static function endsWith($string, $ending) + public static function isValidEmail($email) { - if (1 === strlen($ending) && !self::isLetterOrDigit($ending)) { - $ending = '\\' . $ending; + /* + * Not a string? + * Nothing to do + */ + if (!is_string($email)) { + return false; } - return (bool)preg_match('|' . $ending . '$|', $string); + $pattern = self::getEmailPattern(); + + return (bool) preg_match($pattern, $email); } /** - * Returns information if the string starts with directory's separator + * Returns information if given html attribute is valid * - * @param string $string String that may contain a directory's separator at the start / beginning - * @param string $separator (optional) The directory's separator, e.g. "/". If is empty (not provided), system's - * separator is used. + * @param string $htmlAttribute The html attribute to verify * @return bool */ - public static function startsWithDirectorySeparator($string, $separator = '') + public static function isValidHtmlAttribute($htmlAttribute) { - if (empty($separator)) { - $separator = DIRECTORY_SEPARATOR; + /* + * Not a string? + * Nothing to do + */ + if (!is_string($htmlAttribute)) { + return false; } - return self::startsWith($string, $separator); + $pattern = self::getHtmlAttributePattern(); + + return (bool) preg_match($pattern, $htmlAttribute); } /** - * Returns information if the string ends with directory's separator + * Returns information if given value is valid money-related value * - * @param string $text String that may contain a directory's separator at the end - * @param string $separator (optional) The directory's separator, e.g. "/". If is empty (not provided), system's - * separator is used. - * @return string + * @param mixed $value Value to verify + * @return bool */ - public static function endsWithDirectorySeparator($text, $separator = '') + public static function isValidMoneyValue($value) { - if (empty($separator)) { - $separator = DIRECTORY_SEPARATOR; + /* + * Not a scalar value? + * Nothing to do + */ + if (!is_scalar($value)) { + return false; } - return self::endsWith($text, $separator); - } + $pattern = self::getMoneyPattern(); - /** - * Returns information if uri contains parameter - * - * @param string $uri Uri string (e.g. $_SERVER['REQUEST_URI']) - * @param string $parameterName Uri parameter name - * @return bool - */ - public static function isSetUriParameter($uri, $parameterName) - { - return (bool)preg_match('|[?&]{1}' . $parameterName . '=|', $uri); // e.g. ?name=phil&type=4 -> '$type=' - } - - /** - * Returns pattern used to validate / verify html entity - * - * @return string - */ - public static function getHtmlEntityPattern() - { - return self::$patterns['htmlEntity']; - } - - /** - * Returns information if the string contains html entities - * - * @param string $string String to check - * @return bool - */ - public static function containsEntities($string) - { - $pattern = self::getHtmlEntityPattern(); - - return (bool)preg_match_all($pattern, $string); - } - - /** - * Returns information if one string contains another string - * - * @param string $haystack The string to search in - * @param string $needle The string to be search for - * @return bool - */ - public static function contains($haystack, $needle) - { - if (1 === strlen($needle) && !self::isLetterOrDigit($needle)) { - $needle = '\\' . $needle; - } - - return (bool)preg_match('|.*' . $needle . '.*|', $haystack); - } - - /** - * Returns pattern used to validate / verify name of file - * - * @return string - */ - public static function getFileNamePattern(): string - { - return self::$patterns['fileName']; - } - - /** - * Returns information if given name of file is a really name of file. - * Verifies if given name contains a dot and an extension, e.g. "My File 001.jpg". - * - * @param string $fileName Name of file to check. It may be path of file also. - * @return bool - */ - public static function isFileName(string $fileName): bool - { - $pattern = self::getFileNamePattern(); - - return (bool)preg_match($pattern, $fileName); - } - - /** - * Returns pattern used to validate / verify if value is quoted (by apostrophes or quotation marks) - * - * @return string - */ - public static function getIsQuotedPattern() - { - return self::$patterns['isQuoted']; - } - - /** - * Returns information if given value is quoted (by apostrophes or quotation marks) - * - * @param mixed $value The value to check - * @return bool - */ - public static function isQuoted($value) - { - $pattern = self::getIsQuotedPattern(); - - return is_scalar($value) && (bool)preg_match($pattern, $value); - } - - /** - * Returns pattern used to validate / verify if given path is a Windows-based path, e.g. "C:\path\to\file.jpg" - * - * @return string - */ - public static function getWindowsBasedPathPattern() - { - return self::$patterns['windowsBasedPath']; - } - - /** - * Returns information if given path is a Windows-based path, e.g. "C:\path\to\file.jpg" - * - * @param string $path The path to verify - * @return bool - */ - public static function isWindowsBasedPath($path) - { - $pattern = self::getWindowsBasedPathPattern(); - - return (bool)preg_match($pattern, $path); + return (bool) preg_match($pattern, $value); } /** @@ -731,288 +816,204 @@ class Regex $modulo = $sum % 11; $numberControl = (10 === $modulo) ? 0 : $modulo; - return $numberControl === (int)$nip[9]; + return $numberControl === (int) $nip[9]; } /** - * Returns pattern used to validate / verify if given value is money-related value + * Returns information if given phone number is valid * - * @return string - */ - public static function getMoneyPattern() - { - return self::$patterns['money']; - } - - /** - * Returns information if given value is valid money-related value - * - * @param mixed $value Value to verify + * @param string $phoneNumber The phone number to validate / verify * @return bool */ - public static function isValidMoneyValue($value) - { - /* - * Not a scalar value? - * Nothing to do - */ - if (!is_scalar($value)) { - return false; - } - - $pattern = self::getMoneyPattern(); - - return (bool)preg_match($pattern, $value); - } - - /** - * Returns valid given hexadecimal value of color. - * If the value is invalid, throws an exception or returns false. - * - * @param string $color Color to verify - * @param bool $throwException (optional) If is set to true, throws an exception if given color is invalid - * (default behaviour). Otherwise - not. - * @throws IncorrectColorHexLengthException - * @throws InvalidColorHexValueException - * @return bool|string - */ - public static function getValidColorHexValue($color, $throwException = true) - { - // Not a scalar value? - if (!is_scalar($color)) { - return false; - } - - $color = Miscellaneous::replace($color, '/#/', ''); - $length = strlen($color); - - // Color hasn't 3 or 6 characters length? - if (3 !== $length && 6 !== $length) { - if ($throwException) { - throw new IncorrectColorHexLengthException($color); - } - - return false; - } - - // Make the color 6 characters length, if has 3 - if (3 === $length) { - $color = Miscellaneous::replace($color, '/(.)(.)(.)/', '$1$1$2$2$3$3'); - } - - $pattern = self::$patterns['color']; - $match = (bool)preg_match($pattern, $color); - - // It's not a valid color - if (!$match) { - if ($throwException) { - throw new InvalidColorHexValueException($color); - } - - return false; - } - - return strtolower($color); - } - - /** - * Returns information if given name of bundle is valid - * - * @param string $bundleName Full name of bundle to verify, e.g. "MyExtraBundle" - * @return bool - */ - public static function isValidBundleName($bundleName) + public static function isValidPhoneNumber($phoneNumber) { /* * Not a string? * Nothing to do */ - if (!is_string($bundleName)) { + if (!is_string($phoneNumber)) { return false; } - $pattern = self::getBundleNamePattern(); + $pattern = self::getPhoneNumberPattern(); - return (bool)preg_match($pattern, $bundleName); + return (bool) preg_match($pattern, trim($phoneNumber)); } /** - * Returns pattern used to validate / verify name of bundle + * Returns information if given tax ID is valid (in Poland it's named "NIP") * - * @return string - */ - public static function getBundleNamePattern() - { - return self::$patterns['bundleName']; - } - - /** - * Returns pattern used to validate / verify html attribute - * - * @return string - */ - public static function getHtmlAttributePattern() - { - return self::$patterns['htmlAttribute']; - } - - /** - * Returns information if given html attribute is valid - * - * @param string $htmlAttribute The html attribute to verify + * @param string $taxIdString Tax ID (NIP) string * @return bool */ - public static function isValidHtmlAttribute($htmlAttribute) + public static function isValidTaxId($taxIdString) { /* * Not a string? * Nothing to do */ - if (!is_string($htmlAttribute)) { + if (!is_string($taxIdString)) { return false; } - $pattern = self::getHtmlAttributePattern(); - - return (bool)preg_match($pattern, $htmlAttribute); - } - - /** - * Returns information if given html attributes are valid - * - * @param string $htmlAttributes The html attributes to verify - * @return bool - */ - public static function areValidHtmlAttributes($htmlAttributes) - { /* - * Not a string? + * Empty/Unknown value? * Nothing to do */ - if (!is_string($htmlAttributes)) { + if (empty($taxIdString)) { return false; } - $pattern = self::getHtmlAttributePattern(); + $taxId = preg_replace('/[\s-]/', '', $taxIdString); - return (bool)preg_match_all($pattern, $htmlAttributes); - } - - /** - * Returns information if given value is a binary value - * - * @param string $value Value to verify - * @return bool - */ - public static function isBinaryValue($value) - { /* - * Not a string? + * Tax ID is not 10 characters length OR is not numeric? * Nothing to do */ - if (!is_string($value)) { + if (!is_numeric($taxId) || 10 !== strlen($taxId)) { return false; } - $pattern = self::$patterns['binaryValue']; - - return (bool)preg_match($pattern, $value); - } - - /** - * Returns pattern used to validate / verify size - * - * @param string $separator (optional) Separator used to split width and height. Default: " x ". - * @return string - */ - public static function getSizePattern($separator = ' x ') - { - $escapeMe = [ - '/', - '|', - '.', - '(', - ')', - '[', - ']', + $weights = [ + 6, + 5, + 7, + 2, + 3, + 4, + 5, + 6, + 7, ]; - $cleanSeparator = trim($separator); + $sum = 0; - if (in_array($cleanSeparator, $escapeMe, true)) { - // I have to escape special character of regular expression that may be used as separator - $separator = str_replace($cleanSeparator, '\\' . $cleanSeparator, $separator); + for ($x = 0; $x <= 8; ++$x) { + $sum += $taxId[$x] * $weights[$x]; } - return sprintf(self::$patterns['size'], $separator); + /* + * Last number it's a remainder from dividing per 11? + * Tax ID is valid + */ + + return $sum % 11 === (int) $taxId[9]; } /** - * Returns information if given value is a size value + * Returns information if given url address is valid * - * @param string $value Value to verify - * @param string $separator (optional) Separator used to split width and height. Default: " x ". + * @param string $url The url to validate / verify + * @param bool $requireProtocol (optional) If is set to true, the protocol is required to be passed in the url. + * Otherwise - not. * @return bool */ - public static function isSizeValue($value, $separator = ' x ') + public static function isValidUrl($url, $requireProtocol = false) { /* * Not a string? * Nothing to do */ - if (!is_string($value)) { + if (!is_string($url)) { return false; } - $pattern = self::getSizePattern($separator); + $pattern = self::getUrlPattern($requireProtocol); - return (bool)preg_match($pattern, $value); + return (bool) preg_match($pattern, $url); } /** - * Returns slug for given value + * Returns information if given path is a Windows-based path, e.g. "C:\path\to\file.jpg" * - * @param string $value Value that should be transformed to slug - * @return bool|string + * @param string $path The path to verify + * @return bool */ - public static function createSlug($value) + public static function isWindowsBasedPath($path) + { + $pattern = self::getWindowsBasedPathPattern(); + + return (bool) preg_match($pattern, $path); + } + + /** + * Performs regular expression match with many given patterns. + * Returns information if given $subject matches one or all given $patterns. + * + * @param array|string $patterns The patterns to match + * @param string $subject The string to check + * @param bool $mustAllMatch (optional) If is set to true, $subject must match all $patterns. Otherwise - + * not (default behaviour). + * @return bool + */ + public static function pregMultiMatch($patterns, $subject, $mustAllMatch = false) { /* - * Not a scalar value? + * No patterns? * Nothing to do */ - if (!is_scalar($value)) { + if (empty($patterns)) { return false; } - /* - * It's an empty string? - * Nothing to do - */ - if ('' === $value) { - return ''; + $effect = false; + $patterns = Arrays::makeArray($patterns); + + if ($mustAllMatch) { + $effect = true; } - $id = 'Latin-ASCII; NFD; [:Nonspacing Mark:] Remove; NFC; [:Punctuation:] Remove; Lower();'; - $transliterator = \Transliterator::create($id); + foreach ($patterns as $pattern) { + $matched = (bool) preg_match_all($pattern, $subject); - $cleanValue = trim($value); - $result = $transliterator->transliterate($cleanValue); + if ($mustAllMatch) { + $effect = $effect && $matched; + } elseif ($matched) { + $effect = $matched; - return preg_replace('/[-\s]+/', '-', $result); + break; + } + } + + return $effect; } - public static function clearBeginningSlash(string $string): string + /** + * Returns information if the string starts with given beginning / characters + * + * @param string $string String to check + * @param string $beginning The beginning of string, one or more characters + * @return bool + */ + public static function startsWith($string, $beginning) { - $pattern = static::$patterns['beginningSlash']; + if (!empty($string) && !empty($beginning)) { + if (1 === strlen($beginning) && !self::isLetterOrDigit($beginning)) { + $beginning = '\\'.$beginning; + } - return preg_replace($pattern, '', $string); + $pattern = sprintf('|^%s|', $beginning); + + return (bool) preg_match($pattern, $string); + } + + return false; } - public static function clearEndingSlash(string $string): string + /** + * Returns information if the string starts with directory's separator + * + * @param string $string String that may contain a directory's separator at the start / beginning + * @param string $separator (optional) The directory's separator, e.g. "/". If is empty (not provided), system's + * separator is used. + * @return bool + */ + public static function startsWithDirectorySeparator($string, $separator = '') { - $pattern = static::$patterns['endingSlash']; + if (empty($separator)) { + $separator = DIRECTORY_SEPARATOR; + } - return preg_replace($pattern, '', $string); + return self::startsWith($string, $separator); } } diff --git a/src/Utilities/Repository.php b/src/Utilities/Repository.php index 6f95902..323d557 100644 --- a/src/Utilities/Repository.php +++ b/src/Utilities/Repository.php @@ -26,6 +26,86 @@ class Repository */ public const POSITION_KEY = 'position'; + /** + * Returns query builder for given entity's repository. + * The entity should contain given property, e.g. "name". + * + * @param EntityRepository $repository Repository of the entity + * @param string $property (optional) Name of property used by the ORDER BY clause + * @param string $direction (optional) Direction used by the ORDER BY clause ("ASC" or "DESC") + * @return QueryBuilder + */ + public static function getEntityOrderedQueryBuilder( + EntityRepository $repository, + $property = 'name', + $direction = 'ASC' + ) { + $alias = 'qb'; + $queryBuilder = $repository->createQueryBuilder($alias); + + if (empty($property)) { + return $queryBuilder; + } + + return $queryBuilder->orderBy(sprintf('%s.%s', $alias, $property), $direction); + } + + /** + * Returns extreme position (max or min) of given items + * + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param bool $max (optional) If is set to true, maximum value is returned. Otherwise - minimum. + * @return int + */ + public static function getExtremePosition(array $items, $max = true) + { + /* + * No items? + * Nothing to do + */ + if (empty($items)) { + return null; + } + + $extreme = null; + + foreach ($items as $item) { + // Not sortable? + if (!self::isSortable($item)) { + continue; + } + + $position = null; + + // Let's grab the position + if (is_object($item)) { + $position = $item->getPosition(); + } elseif (array_key_exists(static::POSITION_KEY, $item)) { + $position = $item[static::POSITION_KEY]; + } + + // Maximum value is expected? + if ($max) { + // Position was found and it's larger than previously found position (the extreme position)? + if (null === $extreme || (null !== $position && $position > $extreme)) { + $extreme = $position; + } + + continue; + } + + /* + * Minimum value is expected here. + * Position was found and it's smaller than previously found position (the extreme position)? + */ + if (null === $extreme || (null !== $position && $position < $extreme)) { + $extreme = $position; + } + } + + return $extreme; + } + /** * Replenishes positions of given items * @@ -92,86 +172,6 @@ class Repository } } - /** - * Returns extreme position (max or min) of given items - * - * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays - * @param bool $max (optional) If is set to true, maximum value is returned. Otherwise - minimum. - * @return int - */ - public static function getExtremePosition(array $items, $max = true) - { - /* - * No items? - * Nothing to do - */ - if (empty($items)) { - return null; - } - - $extreme = null; - - foreach ($items as $item) { - // Not sortable? - if (!self::isSortable($item)) { - continue; - } - - $position = null; - - // Let's grab the position - if (is_object($item)) { - $position = $item->getPosition(); - } elseif (array_key_exists(static::POSITION_KEY, $item)) { - $position = $item[static::POSITION_KEY]; - } - - // Maximum value is expected? - if ($max) { - // Position was found and it's larger than previously found position (the extreme position)? - if (null === $extreme || (null !== $position && $position > $extreme)) { - $extreme = $position; - } - - continue; - } - - /* - * Minimum value is expected here. - * Position was found and it's smaller than previously found position (the extreme position)? - */ - if (null === $extreme || (null !== $position && $position < $extreme)) { - $extreme = $position; - } - } - - return $extreme; - } - - /** - * Returns query builder for given entity's repository. - * The entity should contain given property, e.g. "name". - * - * @param EntityRepository $repository Repository of the entity - * @param string $property (optional) Name of property used by the ORDER BY clause - * @param string $direction (optional) Direction used by the ORDER BY clause ("ASC" or "DESC") - * @return QueryBuilder - */ - public static function getEntityOrderedQueryBuilder( - EntityRepository $repository, - $property = 'name', - $direction = 'ASC' - ) { - $alias = 'qb'; - $queryBuilder = $repository->createQueryBuilder($alias); - - if (empty($property)) { - return $queryBuilder; - } - - return $queryBuilder->orderBy(sprintf('%s.%s', $alias, $property), $direction); - } - /** * Returns information if given item is sortable * diff --git a/src/Utilities/Uri.php b/src/Utilities/Uri.php index 602262a..d740f0b 100644 --- a/src/Utilities/Uri.php +++ b/src/Utilities/Uri.php @@ -16,6 +16,45 @@ namespace Meritoo\Common\Utilities; */ class Uri { + /** + * Adds protocol to given url, if the url does not contain given protocol. + * Returns the new url. + * + * @param string $url Url string + * @param string $protocol (optional) Protocol string + * @return string + */ + public static function addProtocolToUrl($url, $protocol = 'http') + { + $pattern = sprintf('/^%s.*/', $protocol); + + if ((bool) preg_match($pattern, $url)) { + return $url; + } + + return sprintf('%s://%s', $protocol, $url); + } + + public static function buildUrl(string $rootUrl, string ...$urlParts): string + { + $rootUrl = Regex::clearEndingSlash($rootUrl); + + if (empty($urlParts) || Arrays::containsEmptyStringsOnly($urlParts)) { + return $rootUrl; + } + + array_walk($urlParts, static function (&$part) { + $part = Regex::clearBeginningSlash($part); + $part = Regex::clearEndingSlash($part); + }); + + return sprintf( + '%s/%s', + $rootUrl, + implode('/', $urlParts) + ); + } + /** * Returns full uri string * @@ -42,36 +81,7 @@ class Uri return $requestedUrl; } - return self::getServerNameOrIp(true) . $requestedUrl; - } - - /** - * Returns server name or IP address - * - * @param bool $withProtocol (optional) If is set to true, protocol name is included. Otherwise isn't. - * @return string - */ - public static function getServerNameOrIp($withProtocol = false) - { - $host = Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'HTTP_HOST'); - - /* - * Unknown host / server? - * Nothing to do - */ - if (empty($host)) { - return ''; - } - - /* - * With protocol? - * Let's include the protocol - */ - if ($withProtocol) { - return sprintf('%s://%s', self::getProtocolName(), $host); - } - - return $host; + return self::getServerNameOrIp(true).$requestedUrl; } /** @@ -108,6 +118,69 @@ class Uri return Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'HTTP_REFERER'); } + /** + * Returns url to resource secured by given htpasswd login and password + * + * @param string $url A path / url to some resource, e.g. page, image, css file + * @param string $user (optional) User name used to log in + * @param string $password (optional) User password used to log in + * @return string + */ + public static function getSecuredUrl($url, $user = '', $password = '') + { + /* + * Url is not provided? + * Nothing to do + */ + if (empty($url)) { + return ''; + } + + $protocol = self::getProtocolName(); + $host = self::getServerNameOrIp(); + + if (!Regex::startsWith($url, '/')) { + $url = sprintf('/%s', $url); + } + + $url = $host.$url; + + if (!empty($user) && !empty($password)) { + $url = sprintf('%s:%s@%s', $user, $password, $url); + } + + return sprintf('%s://%s', $protocol, $url); + } + + /** + * Returns server name or IP address + * + * @param bool $withProtocol (optional) If is set to true, protocol name is included. Otherwise isn't. + * @return string + */ + public static function getServerNameOrIp($withProtocol = false) + { + $host = Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'HTTP_HOST'); + + /* + * Unknown host / server? + * Nothing to do + */ + if (empty($host)) { + return ''; + } + + /* + * With protocol? + * Let's include the protocol + */ + if ($withProtocol) { + return sprintf('%s://%s', self::getProtocolName(), $host); + } + + return $host; + } + /** * Returns user's IP address * @@ -119,35 +192,26 @@ class Uri } /** - * Returns name and version of user's web browser + * Returns name of user's operating system * - * @param bool $withVersion (optional) If is set to true, version of the browser is returned too. Otherwise - - * name only. * @return string */ - public static function getUserWebBrowserName($withVersion = false) + public static function getUserOperatingSystemName() { $info = self::getUserWebBrowserInfo(); - $knownBrowsers = [ - 'Firefox/([\d\.]+)$' => 'Mozilla Firefox', - 'OPR/([\d\.]+)$' => 'Opera', - 'Chrome/([\d\.]+)$' => 'Google Chrome', - 'Safari/([\d\.]+)$' => 'Apple Safari', + $knownSystems = [ + 'Linux' => 'Linux', + 'Win' => 'Windows', + 'Mac' => 'Mac OS', ]; - foreach ($knownBrowsers as $pattern => $browserName) { + foreach ($knownSystems as $pattern => $systemName) { $matches = []; $matchCount = preg_match(sprintf('|%s|', $pattern), $info, $matches); if ($matchCount > 0) { - if ($withVersion) { - $version = $matches[1]; - - return sprintf('%s %s', $browserName, $version); - } - - return $browserName; + return $systemName; } } @@ -181,48 +245,41 @@ class Uri } /** - * Returns name of user's operating system + * Returns name and version of user's web browser * + * @param bool $withVersion (optional) If is set to true, version of the browser is returned too. Otherwise - + * name only. * @return string */ - public static function getUserOperatingSystemName() + public static function getUserWebBrowserName($withVersion = false) { $info = self::getUserWebBrowserInfo(); - $knownSystems = [ - 'Linux' => 'Linux', - 'Win' => 'Windows', - 'Mac' => 'Mac OS', + $knownBrowsers = [ + 'Firefox/([\d\.]+)$' => 'Mozilla Firefox', + 'OPR/([\d\.]+)$' => 'Opera', + 'Chrome/([\d\.]+)$' => 'Google Chrome', + 'Safari/([\d\.]+)$' => 'Apple Safari', ]; - foreach ($knownSystems as $pattern => $systemName) { + foreach ($knownBrowsers as $pattern => $browserName) { $matches = []; $matchCount = preg_match(sprintf('|%s|', $pattern), $info, $matches); if ($matchCount > 0) { - return $systemName; + if ($withVersion) { + $version = $matches[1]; + + return sprintf('%s %s', $browserName, $version); + } + + return $browserName; } } return ''; } - /** - * Returns information if running server is localhost - * - * @return bool - */ - public static function isServerLocalhost() - { - $serverNameOrIp = strtolower(self::getServerNameOrIp()); - - return in_array($serverNameOrIp, [ - 'localhost', - '127.0.0.1', - '127.0.1.1', - ]); - } - /** * Returns information if given url is external, from another server / domain * @@ -260,6 +317,22 @@ class Uri return !Regex::contains($url, $currentUrlPattern); } + /** + * Returns information if running server is localhost + * + * @return bool + */ + public static function isServerLocalhost() + { + $serverNameOrIp = strtolower(self::getServerNameOrIp()); + + return in_array($serverNameOrIp, [ + 'localhost', + '127.0.0.1', + '127.0.1.1', + ]); + } + /** * Replenishes protocol in the given url * @@ -298,77 +371,4 @@ class Uri return sprintf('%s://%s', $protocol, $url); } - - /** - * Returns url to resource secured by given htpasswd login and password - * - * @param string $url A path / url to some resource, e.g. page, image, css file - * @param string $user (optional) User name used to log in - * @param string $password (optional) User password used to log in - * @return string - */ - public static function getSecuredUrl($url, $user = '', $password = '') - { - /* - * Url is not provided? - * Nothing to do - */ - if (empty($url)) { - return ''; - } - - $protocol = self::getProtocolName(); - $host = self::getServerNameOrIp(); - - if (!Regex::startsWith($url, '/')) { - $url = sprintf('/%s', $url); - } - - $url = $host . $url; - - if (!empty($user) && !empty($password)) { - $url = sprintf('%s:%s@%s', $user, $password, $url); - } - - return sprintf('%s://%s', $protocol, $url); - } - - /** - * Adds protocol to given url, if the url does not contain given protocol. - * Returns the new url. - * - * @param string $url Url string - * @param string $protocol (optional) Protocol string - * @return string - */ - public static function addProtocolToUrl($url, $protocol = 'http') - { - $pattern = sprintf('/^%s.*/', $protocol); - - if ((bool)preg_match($pattern, $url)) { - return $url; - } - - return sprintf('%s://%s', $protocol, $url); - } - - public static function buildUrl(string $rootUrl, string ...$urlParts): string - { - $rootUrl = Regex::clearEndingSlash($rootUrl); - - if (empty($urlParts) || Arrays::containsEmptyStringsOnly($urlParts)) { - return $rootUrl; - } - - array_walk($urlParts, static function (&$part) { - $part = Regex::clearBeginningSlash($part); - $part = Regex::clearEndingSlash($part); - }); - - return sprintf( - '%s/%s', - $rootUrl, - implode('/', $urlParts) - ); - } } diff --git a/src/ValueObject/Address.php b/src/ValueObject/Address.php index 337f7ca..708c64b 100644 --- a/src/ValueObject/Address.php +++ b/src/ValueObject/Address.php @@ -88,13 +88,33 @@ class Address } /** - * Returns street + * Returns number of building * * @return string */ - public function getStreet() + public function getBuildingNumber() { - return $this->street; + return $this->buildingNumber; + } + + /** + * Returns city, location + * + * @return string + */ + public function getCity() + { + return $this->city; + } + + /** + * Returns number of flat + * + * @return string + */ + public function getFlatNumber() + { + return $this->flatNumber; } /** @@ -118,23 +138,13 @@ class Address } /** - * Returns number of building + * Returns street * * @return string */ - public function getBuildingNumber() + public function getStreet() { - return $this->buildingNumber; - } - - /** - * Returns number of flat - * - * @return string - */ - public function getFlatNumber() - { - return $this->flatNumber; + return $this->street; } /** @@ -146,14 +156,4 @@ class Address { return $this->zipCode; } - - /** - * Returns city, location - * - * @return string - */ - public function getCity() - { - return $this->city; - } } diff --git a/src/ValueObject/BankAccount.php b/src/ValueObject/BankAccount.php index 0b2c83f..db80cce 100644 --- a/src/ValueObject/BankAccount.php +++ b/src/ValueObject/BankAccount.php @@ -59,16 +59,6 @@ class BankAccount return Arrays::getNonEmptyValuesAsString($values); } - /** - * Returns name of bank - * - * @return string - */ - public function getBankName() - { - return $this->bankName; - } - /** * Returns number of bank's account * @@ -78,4 +68,14 @@ class BankAccount { return $this->accountNumber; } + + /** + * Returns name of bank + * + * @return string + */ + public function getBankName() + { + return $this->bankName; + } } diff --git a/src/ValueObject/Company.php b/src/ValueObject/Company.php index 2f3ae53..ebe1aac 100644 --- a/src/ValueObject/Company.php +++ b/src/ValueObject/Company.php @@ -69,16 +69,6 @@ class Company return Arrays::getNonEmptyValuesAsString($values); } - /** - * Returns name of company - * - * @return string - */ - public function getName() - { - return $this->name; - } - /** * Returns address of company * @@ -98,4 +88,14 @@ class Company { return $this->bankAccount; } + + /** + * Returns name of company + * + * @return string + */ + public function getName() + { + return $this->name; + } } diff --git a/src/ValueObject/Size.php b/src/ValueObject/Size.php index 3ad92c8..b6f4cd0 100644 --- a/src/ValueObject/Size.php +++ b/src/ValueObject/Size.php @@ -62,8 +62,8 @@ class Size */ private function __construct($width = null, $height = null, $unit = 'px') { - $width = (int)$width; - $height = (int)$height; + $width = (int) $width; + $height = (int) $height; if ($width < 0 || $height < 0) { throw new InvalidSizeDimensionsException($width, $height); @@ -88,14 +88,84 @@ class Size } /** - * Sets separator used when converting to string + * Creates new instance from given array * - * @param string $separator The separator + * The array should contain 2 elements: width and height. + * Examples: ['800', '600'], [800, 600]. + * + * @param array $array The size represented as array + * @param string $unit (optional) Unit used when width or height should be returned with unit. Default: "px". + * @return null|Size + */ + public static function fromArray(array $array, $unit = 'px') + { + // Requirements for given array: + // - indexes "0" and "1" + // - should contains exactly 2 elements + if ( + array_key_exists(0, $array) + && array_key_exists(1, $array) + && 2 === count($array) + ) { + [$width, $height] = $array; + + return new self($width, $height, $unit); + } + + return null; + } + + /** + * Creates new instance from given string + * + * @param string $size The size represented as string (width and height separated by given separator) + * @param string $unit (optional) Unit used when width or height should be returned with unit. Default: "px". + * @param string $separator (optional) Separator used to split width and height. Default: " x ". + * @return null|Size + */ + public static function fromString($size, $unit = 'px', $separator = ' x ') + { + if (is_string($size)) { + $matches = []; + $pattern = Regex::getSizePattern($separator); + + if ((bool) preg_match($pattern, $size, $matches)) { + $width = (int) $matches[1]; + $height = (int) $matches[2]; + $sizeObject = new self($width, $height, $unit); + + return $sizeObject->setSeparator($separator); + } + } + + return null; + } + + /** + * Returns the height + * + * @param bool $withUnit (optional) If is set to true, height is returned with unit ("px"). Otherwise - without + * (default behaviour). + * @return int|string + */ + public function getHeight($withUnit = false) + { + if ($withUnit) { + return sprintf('%d %s', $this->height, $this->unit); + } + + return $this->height; + } + + /** + * Sets the height + * + * @param int $height The height * @return Size */ - public function setSeparator($separator) + public function setHeight($height) { - $this->separator = $separator; + $this->height = (int) $height; return $this; } @@ -124,55 +194,24 @@ class Size */ public function setWidth($width) { - $this->width = (int)$width; + $this->width = (int) $width; return $this; } /** - * Returns the height + * Sets separator used when converting to string * - * @param bool $withUnit (optional) If is set to true, height is returned with unit ("px"). Otherwise - without - * (default behaviour). - * @return int|string - */ - public function getHeight($withUnit = false) - { - if ($withUnit) { - return sprintf('%d %s', $this->height, $this->unit); - } - - return $this->height; - } - - /** - * Sets the height - * - * @param int $height The height + * @param string $separator The separator * @return Size */ - public function setHeight($height) + public function setSeparator($separator) { - $this->height = (int)$height; + $this->separator = $separator; return $this; } - /** - * Returns string representation of instance of this class, e.g. '200 x 100' or '200x100' - * - * @param bool $withUnit (optional) If is set to true, width and height are returned with unit ("px"). Otherwise - * - without (default behaviour). - * @return string - */ - public function toString($withUnit = false) - { - $width = $this->getWidth($withUnit); - $height = $this->getHeight($withUnit); - - return sprintf('%s%s%s', $width, $this->separator, $height); - } - /** * Returns instance of this class as an array. * Values of the array are width and height, eg. [800, 600] or ['800px', '600px']. @@ -190,56 +229,17 @@ class Size } /** - * Creates new instance from given string + * Returns string representation of instance of this class, e.g. '200 x 100' or '200x100' * - * @param string $size The size represented as string (width and height separated by given separator) - * @param string $unit (optional) Unit used when width or height should be returned with unit. Default: "px". - * @param string $separator (optional) Separator used to split width and height. Default: " x ". - * @return null|Size + * @param bool $withUnit (optional) If is set to true, width and height are returned with unit ("px"). Otherwise + * - without (default behaviour). + * @return string */ - public static function fromString($size, $unit = 'px', $separator = ' x ') + public function toString($withUnit = false) { - if (is_string($size)) { - $matches = []; - $pattern = Regex::getSizePattern($separator); + $width = $this->getWidth($withUnit); + $height = $this->getHeight($withUnit); - if ((bool)preg_match($pattern, $size, $matches)) { - $width = (int)$matches[1]; - $height = (int)$matches[2]; - $sizeObject = new self($width, $height, $unit); - - return $sizeObject->setSeparator($separator); - } - } - - return null; - } - - /** - * Creates new instance from given array - * - * The array should contain 2 elements: width and height. - * Examples: ['800', '600'], [800, 600]. - * - * @param array $array The size represented as array - * @param string $unit (optional) Unit used when width or height should be returned with unit. Default: "px". - * @return null|Size - */ - public static function fromArray(array $array, $unit = 'px') - { - // Requirements for given array: - // - indexes "0" and "1" - // - should contains exactly 2 elements - if ( - array_key_exists(0, $array) - && array_key_exists(1, $array) - && 2 === count($array) - ) { - list($width, $height) = $array; - - return new self($width, $height, $unit); - } - - return null; + return sprintf('%s%s%s', $width, $this->separator, $height); } } diff --git a/src/ValueObject/Template.php b/src/ValueObject/Template.php index db22fc9..98cecf5 100644 --- a/src/ValueObject/Template.php +++ b/src/ValueObject/Template.php @@ -54,8 +54,8 @@ class Template * Returns content of the template filled with given values (by replacing placeholders with their proper values) * * @param array $values Pairs of key-value where: key - name of placeholder, value - value of the placeholder - * @throws MissingPlaceholdersInValuesException * @return string + * @throws MissingPlaceholdersInValuesException */ public function fill(array $values): string { @@ -82,41 +82,6 @@ class Template return $result; } - /** - * Returns information if given template is valid - * - * @param string $content Raw string with placeholders to validate (content of the template) - * @return bool - */ - private static function isValid(string $content): bool - { - if ('' === $content) { - return false; - } - - return (bool)preg_match_all(static::getPlaceholderPattern(), $content); - } - - /** - * Returns placeholders of given template - * - * @param string $content Content of template - * @return array - */ - private static function getPlaceholders(string $content): array - { - $result = []; - $matchCount = preg_match_all(static::getPlaceholderPattern(), $content, $result); - - if (false !== $matchCount && 0 < $matchCount) { - foreach ($result as $index => $placeholders) { - $result[$index] = array_unique($placeholders); - } - } - - return $result; - } - /** * Returns regular expression that defines format of placeholder * @@ -148,4 +113,39 @@ class Template static::PLACEHOLDER_TAG ); } + + /** + * Returns placeholders of given template + * + * @param string $content Content of template + * @return array + */ + private static function getPlaceholders(string $content): array + { + $result = []; + $matchCount = preg_match_all(static::getPlaceholderPattern(), $content, $result); + + if (false !== $matchCount && 0 < $matchCount) { + foreach ($result as $index => $placeholders) { + $result[$index] = array_unique($placeholders); + } + } + + return $result; + } + + /** + * Returns information if given template is valid + * + * @param string $content Raw string with placeholders to validate (content of the template) + * @return bool + */ + private static function isValid(string $content): bool + { + if ('' === $content) { + return false; + } + + return (bool) preg_match_all(static::getPlaceholderPattern(), $content); + } } diff --git a/src/ValueObject/Version.php b/src/ValueObject/Version.php index 8e0ddb8..344f95b 100644 --- a/src/ValueObject/Version.php +++ b/src/ValueObject/Version.php @@ -65,36 +65,41 @@ class Version } /** - * Returns the "major" part. - * Incremented when you make incompatible API changes. + * Returns new instance based on given version as array. + * Given version should contain 3 integers, 1 per each part ("major", "minor" and "patch"). * - * @return int + * Examples: + * [1, 0, 2]; + * [10, 4, 0]; + * + * @param array $version The version + * @return null|Version */ - public function getMajorPart() + public static function fromArray(array $version) { - return $this->majorPart; - } + /* + * No version provided? + * Nothing to do + */ + if (empty($version)) { + return null; + } - /** - * Returns the "minor" part. - * Incremented when you add functionality in a backwards-compatible manner. - * - * @return int - */ - public function getMinorPart() - { - return $this->minorPart; - } + $count = count($version); - /** - * Returns the "patch" part. - * Incremented when you make backwards-compatible bug fixes. - * - * @return int - */ - public function getPatchPart() - { - return $this->patchPart; + /* + * Incorrect version? + * Nothing to do + */ + if (3 !== $count) { + return null; + } + + $majorPart = (int) $version[0]; + $minorPart = (int) $version[1]; + $patchPart = (int) $version[2]; + + return new static($majorPart, $minorPart, $patchPart); } /** @@ -132,48 +137,43 @@ class Version return null; } - $majorPart = (int)$matches[1]; - $minorPart = (int)$matches[2]; - $patchPart = (int)$matches[3]; + $majorPart = (int) $matches[1]; + $minorPart = (int) $matches[2]; + $patchPart = (int) $matches[3]; return new static($majorPart, $minorPart, $patchPart); } /** - * Returns new instance based on given version as array. - * Given version should contain 3 integers, 1 per each part ("major", "minor" and "patch"). + * Returns the "major" part. + * Incremented when you make incompatible API changes. * - * Examples: - * [1, 0, 2]; - * [10, 4, 0]; - * - * @param array $version The version - * @return null|Version + * @return int */ - public static function fromArray(array $version) + public function getMajorPart() { - /* - * No version provided? - * Nothing to do - */ - if (empty($version)) { - return null; - } + return $this->majorPart; + } - $count = count($version); + /** + * Returns the "minor" part. + * Incremented when you add functionality in a backwards-compatible manner. + * + * @return int + */ + public function getMinorPart() + { + return $this->minorPart; + } - /* - * Incorrect version? - * Nothing to do - */ - if (3 !== $count) { - return null; - } - - $majorPart = (int)$version[0]; - $minorPart = (int)$version[1]; - $patchPart = (int)$version[2]; - - return new static($majorPart, $minorPart, $patchPart); + /** + * Returns the "patch" part. + * Incremented when you make backwards-compatible bug fixes. + * + * @return int + */ + public function getPatchPart() + { + return $this->patchPart; } } diff --git a/tests/Collection/BaseCollectionTest.php b/tests/Collection/BaseCollectionTest.php index 062b931..5d6eab9 100644 --- a/tests/Collection/BaseCollectionTest.php +++ b/tests/Collection/BaseCollectionTest.php @@ -53,402 +53,71 @@ class BaseCollectionTest extends BaseTestCase */ private $simpleElements; - public function testEmptyCollection() - { - static::assertSame(0, $this->emptyCollection->count()); - static::assertCount(0, $this->emptyCollection); - static::assertEmpty($this->emptyCollection); - - static::assertTrue($this->emptyCollection->isEmpty()); - static::assertSame([], $this->emptyCollection->toArray()); - static::assertEmpty($this->emptyCollection->toArray()); - - static::assertNull($this->emptyCollection->getFirst()); - static::assertNull($this->emptyCollection->getLast()); - static::assertNull($this->emptyCollection[1]); - static::assertNull($this->emptyCollection['abc']); - } - - public function testNotEmptyCollection() - { - static::assertSame(7, $this->simpleCollection->count()); - static::assertCount(7, $this->simpleCollection); - static::assertNotEmpty($this->simpleCollection); - - static::assertFalse($this->simpleCollection->isEmpty()); - static::assertSame($this->simpleElements, $this->simpleCollection->toArray()); - static::assertNotEmpty($this->simpleCollection->toArray()); - - static::assertSame('lorem', $this->simpleCollection->getFirst()); - static::assertSame('adipiscing elit', $this->simpleCollection->getLast()); - static::assertSame('dolor', $this->simpleCollection[123]); - } - - public function testCount() - { - static::assertSame(0, $this->emptyCollection->count()); - static::assertSame(7, $this->simpleCollection->count()); - } - - public function testOffsetExists() - { - static::assertFalse(isset($this->emptyCollection['abc'])); - static::assertFalse(isset($this->simpleCollection['abc'])); - - static::assertTrue(isset($this->simpleCollection[0])); - static::assertTrue(isset($this->simpleCollection[345])); - } - - public function testOffsetGet() - { - static::assertNull($this->emptyCollection['abc']); - static::assertNull($this->simpleCollection['abc']); - - static::assertSame('lorem', $this->simpleCollection[0]); - static::assertSame('sit', $this->simpleCollection[345]); - } - - public function testOffsetSet() - { - $this->emptyCollection['test1'] = 1234; - $this->simpleCollection['test2'] = 5678; - - static::assertTrue($this->emptyCollection->has(1234)); - static::assertSame(1234, $this->emptyCollection['test1']); - - static::assertTrue($this->simpleCollection->has(5678)); - static::assertSame(5678, $this->simpleCollection['test2']); - } - - public function testOffsetUnset() - { - unset($this->simpleCollection[0]); - - static::assertFalse($this->simpleCollection->has('lorem')); - static::assertSame('ipsum', $this->simpleCollection[1]); - static::assertSame(6, $this->simpleCollection->count()); - - unset($this->simpleCollection[123]); - - static::assertFalse($this->simpleCollection->has('dolor')); - static::assertSame('ipsum', $this->simpleCollection[1]); - static::assertSame(5, $this->simpleCollection->count()); - } - - public function testGetIterator() - { - static::assertInstanceOf(ArrayIterator::class, $this->simpleCollection->getIterator()); - } - - /** - * @param mixed $element The element to add - * @param int $expectedCount Expected count of elements in collection - * @param CollectionInterface $collection The collection - * - * @dataProvider provideElementToAddWithInvalidType - */ - public function testAddWithInvalidType( - $element, - int $expectedCount, - CollectionInterface $collection - ): void { - $collection->add($element); - - static::assertFalse($collection->has($element)); - static::assertSame($expectedCount, $collection->count()); - } - - /** - * @param mixed $element The element to add - * @param int $expectedCount Expected count of elements in collection - * @param int $expectedIndex Expected index of added element in collection - * @param CollectionInterface $collection The collection - * - * @dataProvider provideElementToAdd - */ - public function testAddWithoutIndex( - $element, - int $expectedCount, - int $expectedIndex, - CollectionInterface $collection - ) { - $collection->add($element); - - static::assertTrue($collection->has($element)); - static::assertSame($expectedCount, $collection->count()); - static::assertSame($element, $collection[$expectedIndex]); - } - - /** - * @param mixed $element The element to add - * @param mixed $index Index of element to add - * @param int $expectedCount Expected count of elements in collection - * @param int $expectedIndex Expected index of added element in collection - * @param CollectionInterface $collection The collection - * - * @dataProvider provideElementToAddWithIndex - */ - public function testAddWithIndex($element, $index, $expectedCount, $expectedIndex, CollectionInterface $collection) - { - $collection->add($element, $index); - - static::assertTrue($collection->has($element)); - static::assertSame($expectedCount, $collection->count()); - static::assertSame($element, $collection[$expectedIndex]); - } - - public function testAddMultipleUsingEmptyArray() - { - $this->emptyCollection->addMultiple([]); - - static::assertSame(0, $this->emptyCollection->count()); - static::assertTrue($this->emptyCollection->isEmpty()); - } - - public function testAddMultiple() - { - $elements = [ - 'test1', - 'test2', - 1234 => 'test3', - 5678 => 'test4', - ]; - - $this->emptyCollection->addMultiple($elements); - - static::assertFalse($this->emptyCollection->isEmpty()); - static::assertSame(4, $this->emptyCollection->count()); - - static::assertSame('test1', $this->emptyCollection[0]); - static::assertSame('test2', $this->emptyCollection[1]); - static::assertSame('test3', $this->emptyCollection[2]); - static::assertSame('test4', $this->emptyCollection[3]); - } - - public function testAddMultipleUsingIndexes() - { - $elements = [ - 'test1', - 'test2', - 1234 => 'test3', - 5678 => 'test4', - ]; - - $this->emptyCollection->addMultiple($elements, true); - - static::assertFalse($this->emptyCollection->isEmpty()); - static::assertSame(4, $this->emptyCollection->count()); - - static::assertSame('test1', $this->emptyCollection[0]); - static::assertSame('test2', $this->emptyCollection[1]); - static::assertSame('test3', $this->emptyCollection[1234]); - static::assertSame('test4', $this->emptyCollection[5678]); - } - - public function testPrepend() - { - $this->emptyCollection->prepend('lorem-ipsum'); - - static::assertFalse($this->emptyCollection->isEmpty()); - static::assertSame(1, $this->emptyCollection->count()); - static::assertSame('lorem-ipsum', $this->emptyCollection[0]); - - $this->simpleCollection->prepend('lorem-ipsum'); - - static::assertFalse($this->simpleCollection->isEmpty()); - static::assertSame(8, $this->simpleCollection->count()); - static::assertSame('lorem-ipsum', $this->simpleCollection[0]); - } - - public function testRemoveNotExistingElement() - { - $this->emptyCollection->remove('abc'); - - static::assertTrue($this->emptyCollection->isEmpty()); - static::assertSame(0, $this->emptyCollection->count()); - - $this->simpleCollection->remove('abc'); - - static::assertFalse($this->simpleCollection->isEmpty()); - static::assertSame(7, $this->simpleCollection->count()); - } - - public function testRemove() - { - static::assertFalse($this->simpleCollection->isEmpty()); - static::assertSame(7, $this->simpleCollection->count()); - static::assertSame('ipsum', $this->simpleCollection[1]); - - $this->simpleCollection->remove('ipsum'); - - static::assertFalse($this->simpleCollection->isEmpty()); - static::assertSame(6, $this->simpleCollection->count()); - static::assertNull($this->simpleCollection[1]); - } - - public function testIsEmpty() - { - static::assertTrue($this->emptyCollection->isEmpty()); - static::assertFalse($this->simpleCollection->isEmpty()); - } - - public function testIsFirst() - { - static::assertFalse($this->emptyCollection->isFirst('abc')); - static::assertFalse($this->simpleCollection->isFirst('abc')); - static::assertFalse($this->simpleCollection->isFirst('dolor')); - static::assertTrue($this->simpleCollection->isFirst('lorem')); - } - - public function testIsLast() - { - static::assertFalse($this->emptyCollection->isLast('abc')); - static::assertFalse($this->simpleCollection->isLast('abc')); - static::assertFalse($this->simpleCollection->isLast('dolor')); - static::assertTrue($this->simpleCollection->isLast('adipiscing elit')); - } - - public function testHas() - { - static::assertFalse($this->emptyCollection->has('abc')); - static::assertFalse($this->simpleCollection->has('abc')); - static::assertTrue($this->simpleCollection->has('lorem')); - static::assertTrue($this->simpleCollection->has('dolor')); - } - - public function testGetPrevious() - { - static::assertNull($this->emptyCollection->getPrevious('abc')); - static::assertNull($this->simpleCollection->getPrevious('abc')); - static::assertNull($this->simpleCollection->getPrevious('lorem')); - - static::assertSame('lorem', $this->simpleCollection->getPrevious('ipsum')); - static::assertSame('dolor', $this->simpleCollection->getPrevious('sit')); - } - - public function testGetNext() - { - static::assertNull($this->emptyCollection->getNext('abc')); - static::assertNull($this->simpleCollection->getNext('abc')); - static::assertNull($this->simpleCollection->getNext('adipiscing elit')); - - static::assertSame('dolor', $this->simpleCollection->getNext('ipsum')); - static::assertSame('sit', $this->simpleCollection->getNext('dolor')); - } - - public function testGetFirst() - { - static::assertNull($this->emptyCollection->getFirst()); - static::assertSame('lorem', $this->simpleCollection->getFirst()); - } - - public function testGetLast() - { - static::assertNull($this->emptyCollection->getLast()); - static::assertSame('adipiscing elit', $this->simpleCollection->getLast()); - } - - public function testToArray() - { - static::assertSame([], $this->emptyCollection->toArray()); - static::assertSame($this->simpleElements, $this->simpleCollection->toArray()); - } - - public function testExistsVisibilityAndArguments() - { - $reflectionClass = new ReflectionClass(BaseCollection::class); - $method = $reflectionClass->getMethod('exists'); - - static::assertMethodVisibility($method, OopVisibilityType::IS_PRIVATE); - static::assertMethodArgumentsCount($method, 1, 1); - } - - /** - * @param string $description Description of test - * @param CollectionInterface $collection Collection to search for element with given index - * @param mixed $index Index / key of the element - * @param mixed $expected Expected element with given index - * - * @dataProvider provideElementGetByIndex - */ - public function testGetByIndex($description, CollectionInterface $collection, $index, $expected) - { - static::assertEquals($expected, $collection->getByIndex($index), $description); - } - - /** - * @param string $description - * @param array $elements - * @param array $expected - * - * @dataProvider provideElementsToValidateType - */ - public function testGetElementsWithValidType(string $description, array $elements, array $expected): void - { - $collection = new FirstNamesCollection($elements); - static::assertSame($expected, $collection->toArray(), $description); - } - - public function testClearIfIsEmpty(): void - { - self::assertCount(0, $this->emptyCollection); - $this->emptyCollection->clear(); - self::assertCount(0, $this->emptyCollection); - } - - public function testClear(): void - { - self::assertCount(7, $this->simpleCollection); - $this->simpleCollection->clear(); - self::assertCount(0, $this->simpleCollection); - } - - public function testLimitIfIsEmpty(): void - { - $result = $this->emptyCollection->limit(10); - self::assertEquals(new StringCollection(), $result); - } - - /** - * @param array $expected - * @param int $max - * - * @dataProvider provideResultOfLimitWithDefaultOffset - */ - public function testLimitWithDefaultOffset(array $expected, int $max): void - { - $result = $this->simpleCollection->limit($max); - self::assertSame($expected, $result->toArray()); - } - - /** - * @param array $expected - * @param int $max - * @param int $offset - * - * @dataProvider provideResultOfLimit - */ - public function testLimit(array $expected, int $max, int $offset): void - { - $result = $this->simpleCollection->limit($max, $offset); - self::assertSame($expected, $result->toArray()); - } - - public function provideElementToAddWithInvalidType(): ?Generator + public function provideElementGetByIndex() { yield [ - ['test'], - 0, + 'An empty collection and empty index', new StringCollection(), + '', + null, ]; yield [ - 123, - 2, + 'An empty collection and non-empty index', + new StringCollection(), + 'test', + null, + ]; + + yield [ + 'Non-empty collection and not existing index', new StringCollection([ - 'I am 1st', - 'I am 2nd', + 'lorem' => 'ipsum', + 'dolor' => 'sit', ]), + 'test', + null, + ]; + + yield [ + 'Collection with existing index', + new StringCollection([ + 'lorem' => 'ipsum', + 'dolor' => 'sit', + ]), + 'lorem', + 'ipsum', + ]; + + yield [ + 'Collection with existing index (collection of arrays)', + new FirstNamesCollection([ + new User('John', 'Scott'), + new User('Jane', 'Brown'), + ]), + 0, + 'John', + ]; + + yield [ + 'Collection with existing index (collection of objects)', + new DateTimeCollection([ + 'x' => new DateTime(), + 'y' => new DateTime('2001-01-01'), + 'z' => new DateTime('yesterday'), + ]), + 'y', + new DateTime('2001-01-01'), + ]; + + yield [ + 'Collection with first names', + new FirstNamesCollection([ + new User('John', 'Scott'), + new User('Jane', 'Brown'), + ]), + 1, + 'Jane', ]; } @@ -542,8 +211,8 @@ class BaseCollectionTest extends BaseTestCase new StringCollection([ 'test1' => 'I am 1st', 'test2' => 'I am 2nd', - 2 => 'I am 3rd', - 3 => 'I am 4th', + 2 => 'I am 3rd', + 3 => 'I am 4th', ]), ]; @@ -555,77 +224,27 @@ class BaseCollectionTest extends BaseTestCase new StringCollection([ 'test1' => 'I am 1st', 'test2' => 'I am 2nd', - 2 => 'I am 3rd', - 3 => 'I am 4th', + 2 => 'I am 3rd', + 3 => 'I am 4th', ]), ]; } - public function provideElementGetByIndex() + public function provideElementToAddWithInvalidType(): ?Generator { yield [ - 'An empty collection and empty index', - new StringCollection(), - '', - null, - ]; - - yield [ - 'An empty collection and non-empty index', - new StringCollection(), - 'test', - null, - ]; - - yield [ - 'Non-empty collection and not existing index', - new StringCollection([ - 'lorem' => 'ipsum', - 'dolor' => 'sit', - ]), - 'test', - null, - ]; - - yield [ - 'Collection with existing index', - new StringCollection([ - 'lorem' => 'ipsum', - 'dolor' => 'sit', - ]), - 'lorem', - 'ipsum', - ]; - - yield [ - 'Collection with existing index (collection of arrays)', - new FirstNamesCollection([ - new User('John', 'Scott'), - new User('Jane', 'Brown'), - ]), + ['test'], 0, - 'John', + new StringCollection(), ]; yield [ - 'Collection with existing index (collection of objects)', - new DateTimeCollection([ - 'x' => new DateTime(), - 'y' => new DateTime('2001-01-01'), - 'z' => new DateTime('yesterday'), + 123, + 2, + new StringCollection([ + 'I am 1st', + 'I am 2nd', ]), - 'y', - new DateTime('2001-01-01'), - ]; - - yield [ - 'Collection with first names', - new FirstNamesCollection([ - new User('John', 'Scott'), - new User('Jane', 'Brown'), - ]), - 1, - 'Jane', ]; } @@ -668,48 +287,6 @@ class BaseCollectionTest extends BaseTestCase ]; } - public function provideResultOfLimitWithDefaultOffset(): ?Generator - { - yield 'Negative value of maximum' => [ - [], - -1, - ]; - - yield 'Maximum set to 0' => [ - [], - 0, - ]; - - yield 'Maximum set to 1' => [ - [ - 'lorem', - ], - 1, - ]; - - yield 'Maximum set to 3' => [ - [ - 'lorem', - 'ipsum', - 123 => 'dolor', - ], - 3, - ]; - - yield 'Maximum greater than size of collection' => [ - [ - 'lorem', - 'ipsum', - 123 => 'dolor', - 345 => 'sit', - 'a' => 'amet', - 'c' => 'consectetur', - 346 => 'adipiscing elit', - ], - 10, - ]; - } - public function provideResultOfLimit(): ?Generator { yield 'Negative value of maximum & negative offset' => [ @@ -768,6 +345,429 @@ class BaseCollectionTest extends BaseTestCase ]; } + public function provideResultOfLimitWithDefaultOffset(): ?Generator + { + yield 'Negative value of maximum' => [ + [], + -1, + ]; + + yield 'Maximum set to 0' => [ + [], + 0, + ]; + + yield 'Maximum set to 1' => [ + [ + 'lorem', + ], + 1, + ]; + + yield 'Maximum set to 3' => [ + [ + 'lorem', + 'ipsum', + 123 => 'dolor', + ], + 3, + ]; + + yield 'Maximum greater than size of collection' => [ + [ + 'lorem', + 'ipsum', + 123 => 'dolor', + 345 => 'sit', + 'a' => 'amet', + 'c' => 'consectetur', + 346 => 'adipiscing elit', + ], + 10, + ]; + } + + public function testAddMultiple() + { + $elements = [ + 'test1', + 'test2', + 1234 => 'test3', + 5678 => 'test4', + ]; + + $this->emptyCollection->addMultiple($elements); + + static::assertFalse($this->emptyCollection->isEmpty()); + static::assertSame(4, $this->emptyCollection->count()); + + static::assertSame('test1', $this->emptyCollection[0]); + static::assertSame('test2', $this->emptyCollection[1]); + static::assertSame('test3', $this->emptyCollection[2]); + static::assertSame('test4', $this->emptyCollection[3]); + } + + public function testAddMultipleUsingEmptyArray() + { + $this->emptyCollection->addMultiple([]); + + static::assertSame(0, $this->emptyCollection->count()); + static::assertTrue($this->emptyCollection->isEmpty()); + } + + public function testAddMultipleUsingIndexes() + { + $elements = [ + 'test1', + 'test2', + 1234 => 'test3', + 5678 => 'test4', + ]; + + $this->emptyCollection->addMultiple($elements, true); + + static::assertFalse($this->emptyCollection->isEmpty()); + static::assertSame(4, $this->emptyCollection->count()); + + static::assertSame('test1', $this->emptyCollection[0]); + static::assertSame('test2', $this->emptyCollection[1]); + static::assertSame('test3', $this->emptyCollection[1234]); + static::assertSame('test4', $this->emptyCollection[5678]); + } + + /** + * @param mixed $element The element to add + * @param mixed $index Index of element to add + * @param int $expectedCount Expected count of elements in collection + * @param int $expectedIndex Expected index of added element in collection + * @param CollectionInterface $collection The collection + * + * @dataProvider provideElementToAddWithIndex + */ + public function testAddWithIndex($element, $index, $expectedCount, $expectedIndex, CollectionInterface $collection) + { + $collection->add($element, $index); + + static::assertTrue($collection->has($element)); + static::assertSame($expectedCount, $collection->count()); + static::assertSame($element, $collection[$expectedIndex]); + } + + /** + * @param mixed $element The element to add + * @param int $expectedCount Expected count of elements in collection + * @param CollectionInterface $collection The collection + * + * @dataProvider provideElementToAddWithInvalidType + */ + public function testAddWithInvalidType( + $element, + int $expectedCount, + CollectionInterface $collection + ): void { + $collection->add($element); + + static::assertFalse($collection->has($element)); + static::assertSame($expectedCount, $collection->count()); + } + + /** + * @param mixed $element The element to add + * @param int $expectedCount Expected count of elements in collection + * @param int $expectedIndex Expected index of added element in collection + * @param CollectionInterface $collection The collection + * + * @dataProvider provideElementToAdd + */ + public function testAddWithoutIndex( + $element, + int $expectedCount, + int $expectedIndex, + CollectionInterface $collection + ) { + $collection->add($element); + + static::assertTrue($collection->has($element)); + static::assertSame($expectedCount, $collection->count()); + static::assertSame($element, $collection[$expectedIndex]); + } + + public function testClear(): void + { + self::assertCount(7, $this->simpleCollection); + $this->simpleCollection->clear(); + self::assertCount(0, $this->simpleCollection); + } + + public function testClearIfIsEmpty(): void + { + self::assertCount(0, $this->emptyCollection); + $this->emptyCollection->clear(); + self::assertCount(0, $this->emptyCollection); + } + + public function testCount() + { + static::assertSame(0, $this->emptyCollection->count()); + static::assertSame(7, $this->simpleCollection->count()); + } + + public function testEmptyCollection() + { + static::assertSame(0, $this->emptyCollection->count()); + static::assertCount(0, $this->emptyCollection); + static::assertEmpty($this->emptyCollection); + + static::assertTrue($this->emptyCollection->isEmpty()); + static::assertSame([], $this->emptyCollection->toArray()); + static::assertEmpty($this->emptyCollection->toArray()); + + static::assertNull($this->emptyCollection->getFirst()); + static::assertNull($this->emptyCollection->getLast()); + static::assertNull($this->emptyCollection[1]); + static::assertNull($this->emptyCollection['abc']); + } + + public function testExistsVisibilityAndArguments() + { + $reflectionClass = new ReflectionClass(BaseCollection::class); + $method = $reflectionClass->getMethod('exists'); + + static::assertMethodVisibility($method, OopVisibilityType::IS_PRIVATE); + static::assertMethodArgumentsCount($method, 1, 1); + } + + /** + * @param string $description Description of test + * @param CollectionInterface $collection Collection to search for element with given index + * @param mixed $index Index / key of the element + * @param mixed $expected Expected element with given index + * + * @dataProvider provideElementGetByIndex + */ + public function testGetByIndex($description, CollectionInterface $collection, $index, $expected) + { + static::assertEquals($expected, $collection->getByIndex($index), $description); + } + + /** + * @param string $description + * @param array $elements + * @param array $expected + * + * @dataProvider provideElementsToValidateType + */ + public function testGetElementsWithValidType(string $description, array $elements, array $expected): void + { + $collection = new FirstNamesCollection($elements); + static::assertSame($expected, $collection->toArray(), $description); + } + + public function testGetFirst() + { + static::assertNull($this->emptyCollection->getFirst()); + static::assertSame('lorem', $this->simpleCollection->getFirst()); + } + + public function testGetIterator() + { + static::assertInstanceOf(ArrayIterator::class, $this->simpleCollection->getIterator()); + } + + public function testGetLast() + { + static::assertNull($this->emptyCollection->getLast()); + static::assertSame('adipiscing elit', $this->simpleCollection->getLast()); + } + + public function testGetNext() + { + static::assertNull($this->emptyCollection->getNext('abc')); + static::assertNull($this->simpleCollection->getNext('abc')); + static::assertNull($this->simpleCollection->getNext('adipiscing elit')); + + static::assertSame('dolor', $this->simpleCollection->getNext('ipsum')); + static::assertSame('sit', $this->simpleCollection->getNext('dolor')); + } + + public function testGetPrevious() + { + static::assertNull($this->emptyCollection->getPrevious('abc')); + static::assertNull($this->simpleCollection->getPrevious('abc')); + static::assertNull($this->simpleCollection->getPrevious('lorem')); + + static::assertSame('lorem', $this->simpleCollection->getPrevious('ipsum')); + static::assertSame('dolor', $this->simpleCollection->getPrevious('sit')); + } + + public function testHas() + { + static::assertFalse($this->emptyCollection->has('abc')); + static::assertFalse($this->simpleCollection->has('abc')); + static::assertTrue($this->simpleCollection->has('lorem')); + static::assertTrue($this->simpleCollection->has('dolor')); + } + + public function testIsEmpty() + { + static::assertTrue($this->emptyCollection->isEmpty()); + static::assertFalse($this->simpleCollection->isEmpty()); + } + + public function testIsFirst() + { + static::assertFalse($this->emptyCollection->isFirst('abc')); + static::assertFalse($this->simpleCollection->isFirst('abc')); + static::assertFalse($this->simpleCollection->isFirst('dolor')); + static::assertTrue($this->simpleCollection->isFirst('lorem')); + } + + public function testIsLast() + { + static::assertFalse($this->emptyCollection->isLast('abc')); + static::assertFalse($this->simpleCollection->isLast('abc')); + static::assertFalse($this->simpleCollection->isLast('dolor')); + static::assertTrue($this->simpleCollection->isLast('adipiscing elit')); + } + + /** + * @param array $expected + * @param int $max + * @param int $offset + * + * @dataProvider provideResultOfLimit + */ + public function testLimit(array $expected, int $max, int $offset): void + { + $result = $this->simpleCollection->limit($max, $offset); + self::assertSame($expected, $result->toArray()); + } + + public function testLimitIfIsEmpty(): void + { + $result = $this->emptyCollection->limit(10); + self::assertEquals(new StringCollection(), $result); + } + + /** + * @param array $expected + * @param int $max + * + * @dataProvider provideResultOfLimitWithDefaultOffset + */ + public function testLimitWithDefaultOffset(array $expected, int $max): void + { + $result = $this->simpleCollection->limit($max); + self::assertSame($expected, $result->toArray()); + } + + public function testNotEmptyCollection() + { + static::assertSame(7, $this->simpleCollection->count()); + static::assertCount(7, $this->simpleCollection); + static::assertNotEmpty($this->simpleCollection); + + static::assertFalse($this->simpleCollection->isEmpty()); + static::assertSame($this->simpleElements, $this->simpleCollection->toArray()); + static::assertNotEmpty($this->simpleCollection->toArray()); + + static::assertSame('lorem', $this->simpleCollection->getFirst()); + static::assertSame('adipiscing elit', $this->simpleCollection->getLast()); + static::assertSame('dolor', $this->simpleCollection[123]); + } + + public function testOffsetExists() + { + static::assertFalse(isset($this->emptyCollection['abc'])); + static::assertFalse(isset($this->simpleCollection['abc'])); + + static::assertTrue(isset($this->simpleCollection[0])); + static::assertTrue(isset($this->simpleCollection[345])); + } + + public function testOffsetGet() + { + static::assertNull($this->emptyCollection['abc']); + static::assertNull($this->simpleCollection['abc']); + + static::assertSame('lorem', $this->simpleCollection[0]); + static::assertSame('sit', $this->simpleCollection[345]); + } + + public function testOffsetSet() + { + $this->emptyCollection['test1'] = 1234; + $this->simpleCollection['test2'] = 5678; + + static::assertTrue($this->emptyCollection->has(1234)); + static::assertSame(1234, $this->emptyCollection['test1']); + + static::assertTrue($this->simpleCollection->has(5678)); + static::assertSame(5678, $this->simpleCollection['test2']); + } + + public function testOffsetUnset() + { + unset($this->simpleCollection[0]); + + static::assertFalse($this->simpleCollection->has('lorem')); + static::assertSame('ipsum', $this->simpleCollection[1]); + static::assertSame(6, $this->simpleCollection->count()); + + unset($this->simpleCollection[123]); + + static::assertFalse($this->simpleCollection->has('dolor')); + static::assertSame('ipsum', $this->simpleCollection[1]); + static::assertSame(5, $this->simpleCollection->count()); + } + + public function testPrepend() + { + $this->emptyCollection->prepend('lorem-ipsum'); + + static::assertFalse($this->emptyCollection->isEmpty()); + static::assertSame(1, $this->emptyCollection->count()); + static::assertSame('lorem-ipsum', $this->emptyCollection[0]); + + $this->simpleCollection->prepend('lorem-ipsum'); + + static::assertFalse($this->simpleCollection->isEmpty()); + static::assertSame(8, $this->simpleCollection->count()); + static::assertSame('lorem-ipsum', $this->simpleCollection[0]); + } + + public function testRemove() + { + static::assertFalse($this->simpleCollection->isEmpty()); + static::assertSame(7, $this->simpleCollection->count()); + static::assertSame('ipsum', $this->simpleCollection[1]); + + $this->simpleCollection->remove('ipsum'); + + static::assertFalse($this->simpleCollection->isEmpty()); + static::assertSame(6, $this->simpleCollection->count()); + static::assertNull($this->simpleCollection[1]); + } + + public function testRemoveNotExistingElement() + { + $this->emptyCollection->remove('abc'); + + static::assertTrue($this->emptyCollection->isEmpty()); + static::assertSame(0, $this->emptyCollection->count()); + + $this->simpleCollection->remove('abc'); + + static::assertFalse($this->simpleCollection->isEmpty()); + static::assertSame(7, $this->simpleCollection->count()); + } + + public function testToArray() + { + static::assertSame([], $this->emptyCollection->toArray()); + static::assertSame($this->simpleElements, $this->simpleCollection->toArray()); + } + /** * {@inheritdoc} */ diff --git a/tests/Collection/DateTimeCollectionTest.php b/tests/Collection/DateTimeCollectionTest.php index ea6fd48..e68415c 100644 --- a/tests/Collection/DateTimeCollectionTest.php +++ b/tests/Collection/DateTimeCollectionTest.php @@ -27,6 +27,44 @@ use Meritoo\Common\Type\OopVisibilityType; */ class DateTimeCollectionTest extends BaseTestCase { + public function provideDifferentTypesOfElements(): ?Generator + { + yield [ + 'An empty array', + [], + [], + ]; + + yield [ + 'Valid elements only', + [ + new DateTime('2001-01-01'), + new DateTime('2001-01-02'), + ], + [ + new DateTime('2001-01-01'), + new DateTime('2001-01-02'), + ], + ]; + + yield [ + 'Mixed elements', + [ + 1, + 'test', + new DateTime('2001-01-01'), + '', + [], + 234, + new DateTime('2001-01-02'), + ], + [ + 2 => new DateTime('2001-01-01'), + 6 => new DateTime('2001-01-02'), + ], + ]; + } + public function testConstructor(): void { static::assertConstructorVisibilityAndArguments( @@ -51,42 +89,4 @@ class DateTimeCollectionTest extends BaseTestCase $collection = new DateTimeCollection($elements); static::assertEquals($expectedElements, $collection->toArray(), $description); } - - public function provideDifferentTypesOfElements(): ?Generator - { - yield[ - 'An empty array', - [], - [], - ]; - - yield[ - 'Valid elements only', - [ - new DateTime('2001-01-01'), - new DateTime('2001-01-02'), - ], - [ - new DateTime('2001-01-01'), - new DateTime('2001-01-02'), - ], - ]; - - yield[ - 'Mixed elements', - [ - 1, - 'test', - new DateTime('2001-01-01'), - '', - [], - 234, - new DateTime('2001-01-02'), - ], - [ - 2 => new DateTime('2001-01-01'), - 6 => new DateTime('2001-01-02'), - ], - ]; - } } diff --git a/tests/Collection/IntegerCollectionTest.php b/tests/Collection/IntegerCollectionTest.php index 4bc925c..53ffcb6 100644 --- a/tests/Collection/IntegerCollectionTest.php +++ b/tests/Collection/IntegerCollectionTest.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace Meritoo\Test\Common\Collection; +use Generator; use Meritoo\Common\Collection\IntegerCollection; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; @@ -25,6 +26,45 @@ use Meritoo\Common\Type\OopVisibilityType; */ class IntegerCollectionTest extends BaseTestCase { + public function provideDifferentTypesOfElements(): ?Generator + { + yield [ + 'An empty array', + [], + [], + ]; + + yield [ + 'Valid elements only', + [ + 1, + 2, + 3, + ], + [ + 1, + 2, + 3, + ], + ]; + + yield [ + 'Mixed elements', + [ + 1, + 'test', + '', + [], + 234, + 'test', + ], + [ + 0 => 1, + 4 => 234, + ], + ]; + } + public function testConstructor(): void { static::assertConstructorVisibilityAndArguments( @@ -49,43 +89,4 @@ class IntegerCollectionTest extends BaseTestCase $collection = new IntegerCollection($elements); static::assertSame($expectedElements, $collection->toArray(), $description); } - - public function provideDifferentTypesOfElements(): ?\Generator - { - yield[ - 'An empty array', - [], - [], - ]; - - yield[ - 'Valid elements only', - [ - 1, - 2, - 3, - ], - [ - 1, - 2, - 3, - ], - ]; - - yield[ - 'Mixed elements', - [ - 1, - 'test', - '', - [], - 234, - 'test', - ], - [ - 0 => 1, - 4 => 234, - ], - ]; - } } diff --git a/tests/Collection/StringCollectionTest.php b/tests/Collection/StringCollectionTest.php index 36c154e..cbab50a 100644 --- a/tests/Collection/StringCollectionTest.php +++ b/tests/Collection/StringCollectionTest.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace Meritoo\Test\Common\Collection; +use Generator; use Meritoo\Common\Collection\StringCollection; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; @@ -25,6 +26,46 @@ use Meritoo\Common\Type\OopVisibilityType; */ class StringCollectionTest extends BaseTestCase { + public function provideDifferentTypesOfElements(): ?Generator + { + yield [ + 'An empty array', + [], + [], + ]; + + yield [ + 'Valid elements only', + [ + '1', + 'test', + '', + ], + [ + '1', + 'test', + '', + ], + ]; + + yield [ + 'Mixed elements', + [ + 1, + 'test', + '', + [], + 234, + 'test', + ], + [ + 1 => 'test', + 2 => '', + 5 => 'test', + ], + ]; + } + public function testConstructor(): void { static::assertConstructorVisibilityAndArguments( @@ -49,44 +90,4 @@ class StringCollectionTest extends BaseTestCase $collection = new StringCollection($elements); static::assertSame($expectedElements, $collection->toArray(), $description); } - - public function provideDifferentTypesOfElements(): ?\Generator - { - yield[ - 'An empty array', - [], - [], - ]; - - yield[ - 'Valid elements only', - [ - '1', - 'test', - '', - ], - [ - '1', - 'test', - '', - ], - ]; - - yield[ - 'Mixed elements', - [ - 1, - 'test', - '', - [], - 234, - 'test', - ], - [ - 1 => 'test', - 2 => '', - 5 => 'test', - ], - ]; - } } diff --git a/tests/Collection/TemplatesTest.php b/tests/Collection/TemplatesTest.php index 2198728..adc84dd 100644 --- a/tests/Collection/TemplatesTest.php +++ b/tests/Collection/TemplatesTest.php @@ -26,6 +26,102 @@ use Meritoo\Common\ValueObject\Template; */ class TemplatesTest extends BaseTestCase { + public function provideArrayWithTemplates(): ?Generator + { + yield [ + 'An empty array', + [], + new Templates(), + ]; + + yield [ + 'Number-based indexes', + [ + 'First name: %first_name%', + 'Last name: %last_name%', + ], + new Templates([ + new Template('First name: %first_name%'), + new Template('Last name: %last_name%'), + ]), + ]; + + yield [ + 'String-based indexes', + [ + 'first' => 'First name: %first_name%', + 'last' => 'Last name: %last_name%', + ], + new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), + ]), + ]; + } + + public function provideTemplatesToFind(): ?Generator + { + yield [ + '2 templates only', + new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), + ]), + 'first', + new Template('First name: %first_name%'), + ]; + + yield [ + 'Different indexes', + new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), + 1 => new Template('Hi %name%, how are you?'), + '2' => new Template('Your score is: %score%'), + ]), + '1', + new Template('Hi %name%, how are you?'), + ]; + } + + public function provideTemplatesWithNotExistingIndex(): ?Generator + { + $template = 'Template with \'%s\' index was not found. Did you provide all required templates?'; + + yield [ + new Templates(), + 'test', + sprintf($template, 'test'), + ]; + + yield [ + new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), + ]), + 'test', + sprintf($template, 'test'), + ]; + + yield [ + new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), + ]), + '', + sprintf($template, ''), + ]; + + yield [ + new Templates([ + 'first' => new Template('First name: %first_name%'), + 'last' => new Template('Last name: %last_name%'), + ]), + '4', + sprintf($template, 4), + ]; + } + public function testConstructor(): void { static::assertConstructorVisibilityAndArguments( @@ -37,14 +133,15 @@ class TemplatesTest extends BaseTestCase /** * @param string $description Description of test - * @param array $templates Pairs of key-value where: key - template's index, value - template's content - * @param Templates $expected Expected collection/storage of templates + * @param Templates $templates All templates + * @param string $index Index that contains required template + * @param Template $expected Expected template * - * @dataProvider provideArrayWithTemplates + * @dataProvider provideTemplatesToFind */ - public function testFromArray(string $description, array $templates, Templates $expected): void + public function testFindTemplate(string $description, Templates $templates, string $index, Template $expected): void { - static::assertEquals($expected, Templates::fromArray($templates), $description); + static::assertEquals($expected, $templates->findTemplate($index), $description); } public function testFindTemplateUsingEmptyCollection(): void @@ -79,110 +176,13 @@ class TemplatesTest extends BaseTestCase /** * @param string $description Description of test - * @param Templates $templates All templates - * @param string $index Index that contains required template - * @param Template $expected Expected template + * @param array $templates Pairs of key-value where: key - template's index, value - template's content + * @param Templates $expected Expected collection/storage of templates * - * @dataProvider provideTemplatesToFind + * @dataProvider provideArrayWithTemplates */ - public function testFindTemplate(string $description, Templates $templates, string $index, Template $expected): void + public function testFromArray(string $description, array $templates, Templates $expected): void { - static::assertEquals($expected, $templates->findTemplate($index), $description); - } - - public function provideArrayWithTemplates(): ?Generator - { - yield[ - 'An empty array', - [], - new Templates(), - ]; - - yield[ - 'Number-based indexes', - [ - 'First name: %first_name%', - 'Last name: %last_name%', - ], - new Templates([ - new Template('First name: %first_name%'), - new Template('Last name: %last_name%'), - ]), - ]; - - yield[ - 'String-based indexes', - [ - 'first' => 'First name: %first_name%', - 'last' => 'Last name: %last_name%', - ], - new Templates([ - 'first' => new Template('First name: %first_name%'), - 'last' => new Template('Last name: %last_name%'), - ]), - ]; - } - - public function provideTemplatesWithNotExistingIndex(): ?Generator - { - $template = 'Template with \'%s\' index was not found. Did you provide all required templates?'; - - yield[ - new Templates(), - 'test', - sprintf($template, 'test'), - ]; - - yield[ - new Templates([ - 'first' => new Template('First name: %first_name%'), - 'last' => new Template('Last name: %last_name%'), - ]), - 'test', - sprintf($template, 'test'), - ]; - - yield[ - new Templates([ - 'first' => new Template('First name: %first_name%'), - 'last' => new Template('Last name: %last_name%'), - ]), - '', - sprintf($template, ''), - ]; - - yield[ - new Templates([ - 'first' => new Template('First name: %first_name%'), - 'last' => new Template('Last name: %last_name%'), - ]), - '4', - sprintf($template, 4), - ]; - } - - public function provideTemplatesToFind(): ?Generator - { - yield[ - '2 templates only', - new Templates([ - 'first' => new Template('First name: %first_name%'), - 'last' => new Template('Last name: %last_name%'), - ]), - 'first', - new Template('First name: %first_name%'), - ]; - - yield[ - 'Different indexes', - new Templates([ - 'first' => new Template('First name: %first_name%'), - 'last' => new Template('Last name: %last_name%'), - 1 => new Template('Hi %name%, how are you?'), - '2' => new Template('Your score is: %score%'), - ]), - '1', - new Template('Hi %name%, how are you?'), - ]; + static::assertEquals($expected, Templates::fromArray($templates), $description); } } diff --git a/tests/Exception/Base/UnknownTypeExceptionTest.php b/tests/Exception/Base/UnknownTypeExceptionTest.php index 2c75b95..c91547a 100644 --- a/tests/Exception/Base/UnknownTypeExceptionTest.php +++ b/tests/Exception/Base/UnknownTypeExceptionTest.php @@ -29,16 +29,16 @@ class UnknownTypeExceptionTest extends BaseTestCase static::assertConstructorVisibilityAndArguments(UnknownTypeException::class, OopVisibilityType::IS_PUBLIC, 3); } - public function testWithoutException() - { - self::assertEquals('Test 2', (new TestService())->getTranslatedType('test_2')); - } - public function testTheException() { $this->expectException(UnknownTestTypeException::class); self::assertEmpty((new TestService())->getTranslatedType('test_3')); } + + public function testWithoutException() + { + self::assertEquals('Test 2', (new TestService())->getTranslatedType('test_2')); + } } /** @@ -89,8 +89,8 @@ class TestService * Returns translated type (for testing purposes) * * @param string $type Type of something (for testing purposes) - * @throws UnknownTestTypeException * @return string + * @throws UnknownTestTypeException */ public function getTranslatedType(string $type): string { diff --git a/tests/Exception/Bundle/IncorrectBundleNameExceptionTest.php b/tests/Exception/Bundle/IncorrectBundleNameExceptionTest.php index a48dac5..d862480 100644 --- a/tests/Exception/Bundle/IncorrectBundleNameExceptionTest.php +++ b/tests/Exception/Bundle/IncorrectBundleNameExceptionTest.php @@ -20,10 +20,34 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\Bundle\IncorrectBundleNameException + * @covers \Meritoo\Common\Exception\Bundle\IncorrectBundleNameException */ class IncorrectBundleNameExceptionTest extends BaseTestCase { + public function provideBundleNameAndMessage(): Generator + { + $template = 'Name of bundle \'%s\' is incorrect. It should start with big letter and end with "Bundle". Is' + .' there everything ok?'; + + yield [ + 'An empty string as name of bundle', + '', + sprintf($template, ''), + ]; + + yield [ + 'String with spaces as name of bundle', + 'This is test', + sprintf($template, 'This is test'), + ]; + + yield [ + 'String without spaces as name of bundle', + 'ThisIsTest', + sprintf($template, 'ThisIsTest'), + ]; + } + public function testConstructor(): void { static::assertConstructorVisibilityAndArguments( @@ -45,28 +69,4 @@ class IncorrectBundleNameExceptionTest extends BaseTestCase $exception = IncorrectBundleNameException::create($bundleName); static::assertSame($expectedMessage, $exception->getMessage(), $description); } - - public function provideBundleNameAndMessage(): Generator - { - $template = 'Name of bundle \'%s\' is incorrect. It should start with big letter and end with "Bundle". Is' - . ' there everything ok?'; - - yield[ - 'An empty string as name of bundle', - '', - sprintf($template, ''), - ]; - - yield[ - 'String with spaces as name of bundle', - 'This is test', - sprintf($template, 'This is test'), - ]; - - yield[ - 'String without spaces as name of bundle', - 'ThisIsTest', - sprintf($template, 'ThisIsTest'), - ]; - } } diff --git a/tests/Exception/Date/UnknownDatePartTypeExceptionTest.php b/tests/Exception/Date/UnknownDatePartTypeExceptionTest.php index 13ddd0b..4bc5b7b 100644 --- a/tests/Exception/Date/UnknownDatePartTypeExceptionTest.php +++ b/tests/Exception/Date/UnknownDatePartTypeExceptionTest.php @@ -21,10 +21,39 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\Type\UnknownDatePartTypeException + * @covers \Meritoo\Common\Exception\Type\UnknownDatePartTypeException */ class UnknownDatePartTypeExceptionTest extends BaseTestCase { + /** + * Provides type of date part, incorrect value and expected exception's message + * + * @return Generator + */ + public function provideDatePartAndValue() + { + $template = 'The \'%s\' type of date part (with value %s) is unknown. Probably doesn\'t exist or there is a' + .' typo. You should use one of these types: day, hour, minute, month, second, year.'; + + yield [ + DatePartType::DAY, + '44', + sprintf($template, DatePartType::DAY, '44'), + ]; + + yield [ + DatePartType::MONTH, + '22', + sprintf($template, DatePartType::MONTH, '22'), + ]; + + yield [ + DatePartType::MINUTE, + '77', + sprintf($template, DatePartType::MINUTE, '77'), + ]; + } + public function testConstructorVisibilityAndArguments() { static::assertConstructorVisibilityAndArguments(UnknownDatePartTypeException::class, OopVisibilityType::IS_PUBLIC, 3); @@ -42,33 +71,4 @@ class UnknownDatePartTypeExceptionTest extends BaseTestCase $exception = UnknownDatePartTypeException::createException($unknownDatePart, $value); static::assertSame($expectedMessage, $exception->getMessage()); } - - /** - * Provides type of date part, incorrect value and expected exception's message - * - * @return Generator - */ - public function provideDatePartAndValue() - { - $template = 'The \'%s\' type of date part (with value %s) is unknown. Probably doesn\'t exist or there is a' - . ' typo. You should use one of these types: day, hour, minute, month, second, year.'; - - yield[ - DatePartType::DAY, - '44', - sprintf($template, DatePartType::DAY, '44'), - ]; - - yield[ - DatePartType::MONTH, - '22', - sprintf($template, DatePartType::MONTH, '22'), - ]; - - yield[ - DatePartType::MINUTE, - '77', - sprintf($template, DatePartType::MINUTE, '77'), - ]; - } } diff --git a/tests/Exception/File/EmptyFileExceptionTest.php b/tests/Exception/File/EmptyFileExceptionTest.php index f209bfe..0825b32 100644 --- a/tests/Exception/File/EmptyFileExceptionTest.php +++ b/tests/Exception/File/EmptyFileExceptionTest.php @@ -20,10 +20,30 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\File\EmptyFileException + * @covers \Meritoo\Common\Exception\File\EmptyFileException */ class EmptyFileExceptionTest extends BaseTestCase { + /** + * Provides path of the empty file and expected exception's message + * + * @return Generator + */ + public function providePathOfFile() + { + $template = 'File with path \'%s\' is empty (has no content). Did you provide path of proper file?'; + + yield [ + 'aa/bb/cc', + sprintf($template, 'aa/bb/cc'), + ]; + + yield [ + 'images/show/car.jpg', + sprintf($template, 'images/show/car.jpg'), + ]; + } + public function testConstructorVisibilityAndArguments() { static::assertConstructorVisibilityAndArguments(EmptyFileException::class, OopVisibilityType::IS_PUBLIC, 3); @@ -40,24 +60,4 @@ class EmptyFileExceptionTest extends BaseTestCase $exception = EmptyFileException::create($emptyFilePath); static::assertSame($expectedMessage, $exception->getMessage()); } - - /** - * Provides path of the empty file and expected exception's message - * - * @return Generator - */ - public function providePathOfFile() - { - $template = 'File with path \'%s\' is empty (has no content). Did you provide path of proper file?'; - - yield[ - 'aa/bb/cc', - sprintf($template, 'aa/bb/cc'), - ]; - - yield[ - 'images/show/car.jpg', - sprintf($template, 'images/show/car.jpg'), - ]; - } } diff --git a/tests/Exception/File/EmptyFilePathExceptionTest.php b/tests/Exception/File/EmptyFilePathExceptionTest.php index 97a2eff..560351c 100644 --- a/tests/Exception/File/EmptyFilePathExceptionTest.php +++ b/tests/Exception/File/EmptyFilePathExceptionTest.php @@ -19,18 +19,18 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\File\EmptyFilePathException + * @covers \Meritoo\Common\Exception\File\EmptyFilePathException */ class EmptyFilePathExceptionTest extends BaseTestCase { - public function testConstructorVisibilityAndArguments() - { - static::assertConstructorVisibilityAndArguments(EmptyFilePathException::class, OopVisibilityType::IS_PUBLIC, 3); - } - public function testConstructorMessage() { $exception = EmptyFilePathException::create(); static::assertSame('Path of the file is empty. Did you provide path of proper file?', $exception->getMessage()); } + + public function testConstructorVisibilityAndArguments() + { + static::assertConstructorVisibilityAndArguments(EmptyFilePathException::class, OopVisibilityType::IS_PUBLIC, 3); + } } diff --git a/tests/Exception/File/NotExistingFileExceptionTest.php b/tests/Exception/File/NotExistingFileExceptionTest.php index ce01a93..b8c6cb6 100644 --- a/tests/Exception/File/NotExistingFileExceptionTest.php +++ b/tests/Exception/File/NotExistingFileExceptionTest.php @@ -20,13 +20,28 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\File\NotExistingFileException + * @covers \Meritoo\Common\Exception\File\NotExistingFileException */ class NotExistingFileExceptionTest extends BaseTestCase { - public function testConstructorVisibilityAndArguments() + /** + * Provides path of not existing file and expected exception's message + * + * @return Generator + */ + public function providePathOfFile() { - static::assertConstructorVisibilityAndArguments(NotExistingFileException::class, OopVisibilityType::IS_PUBLIC, 3); + $template = 'File with path \'%s\' does not exist (or is not readable). Did you provide path of proper file?'; + + yield [ + 'aa/bb/cc', + sprintf($template, 'aa/bb/cc'), + ]; + + yield [ + 'images/show/car.jpg', + sprintf($template, 'images/show/car.jpg'), + ]; } /** @@ -41,23 +56,8 @@ class NotExistingFileExceptionTest extends BaseTestCase static::assertSame($expectedMessage, $exception->getMessage()); } - /** - * Provides path of not existing file and expected exception's message - * - * @return Generator - */ - public function providePathOfFile() + public function testConstructorVisibilityAndArguments() { - $template = 'File with path \'%s\' does not exist (or is not readable). Did you provide path of proper file?'; - - yield[ - 'aa/bb/cc', - sprintf($template, 'aa/bb/cc'), - ]; - - yield[ - 'images/show/car.jpg', - sprintf($template, 'images/show/car.jpg'), - ]; + static::assertConstructorVisibilityAndArguments(NotExistingFileException::class, OopVisibilityType::IS_PUBLIC, 3); } } diff --git a/tests/Exception/Method/DisabledMethodExceptionTest.php b/tests/Exception/Method/DisabledMethodExceptionTest.php index c7d4613..18af361 100644 --- a/tests/Exception/Method/DisabledMethodExceptionTest.php +++ b/tests/Exception/Method/DisabledMethodExceptionTest.php @@ -20,13 +20,31 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\Method\DisabledMethodException + * @covers \Meritoo\Common\Exception\Method\DisabledMethodException */ class DisabledMethodExceptionTest extends BaseTestCase { - public function testConstructorVisibilityAndArguments() + /** + * Provides name of the disabled method, name of the alternative method and expected exception's message + * + * @return Generator + */ + public function provideMethodsNames() { - static::assertConstructorVisibilityAndArguments(DisabledMethodException::class, OopVisibilityType::IS_PUBLIC, 3); + $templateShort = 'Method %s() cannot be called, because is disabled.'; + $templateLong = $templateShort.' Use %s() instead.'; + + yield [ + 'FooBar::loremIpsum', + '', + sprintf($templateShort, 'FooBar::loremIpsum'), + ]; + + yield [ + 'FooBar::loremIpsum', + 'AnotherClass::alternativeMethod', + sprintf($templateLong, 'FooBar::loremIpsum', 'AnotherClass::alternativeMethod'), + ]; } /** @@ -43,26 +61,8 @@ class DisabledMethodExceptionTest extends BaseTestCase static::assertSame($expectedMessage, $exception->getMessage()); } - /** - * Provides name of the disabled method, name of the alternative method and expected exception's message - * - * @return Generator - */ - public function provideMethodsNames() + public function testConstructorVisibilityAndArguments() { - $templateShort = 'Method %s() cannot be called, because is disabled.'; - $templateLong = $templateShort . ' Use %s() instead.'; - - yield[ - 'FooBar::loremIpsum', - '', - sprintf($templateShort, 'FooBar::loremIpsum'), - ]; - - yield[ - 'FooBar::loremIpsum', - 'AnotherClass::alternativeMethod', - sprintf($templateLong, 'FooBar::loremIpsum', 'AnotherClass::alternativeMethod'), - ]; + static::assertConstructorVisibilityAndArguments(DisabledMethodException::class, OopVisibilityType::IS_PUBLIC, 3); } } diff --git a/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php b/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php index afce710..059b8c3 100644 --- a/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php +++ b/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php @@ -25,6 +25,33 @@ use stdClass; */ class CannotResolveClassNameExceptionTest extends BaseTestCase { + /** + * Provides source of the class's / trait's name, information if message of this exception should be prepared for + * class and the expected exception's message + * + * @return Generator + */ + public function provideClassName(): Generator + { + yield [ + 'Not\Existing\Class', + true, + 'Name of class from given \'string\' Not\Existing\Class cannot be resolved. Is there everything ok?', + ]; + + yield [ + 'Not\Existing\Trait', + false, + 'Name of trait from given \'string\' Not\Existing\Trait cannot be resolved. Is there everything ok?', + ]; + + yield [ + stdClass::class, + true, + 'Name of class from given \'string\' stdClass cannot be resolved. Is there everything ok?', + ]; + } + public function testConstructorVisibilityAndArguments(): void { static::assertConstructorVisibilityAndArguments( @@ -34,14 +61,6 @@ class CannotResolveClassNameExceptionTest extends BaseTestCase ); } - public function testCreateUsingDefaults(): void - { - $exception = CannotResolveClassNameException::create(stdClass::class); - $expectedMessage = 'Name of class from given \'string\' stdClass cannot be resolved. Is there everything ok?'; - - static::assertSame($expectedMessage, $exception->getMessage()); - } - /** * @param string $source Source of name of the class or trait * @param bool $forClass (optional) If is set to true, message of this exception for class is prepared. @@ -56,30 +75,11 @@ class CannotResolveClassNameExceptionTest extends BaseTestCase static::assertSame($expectedMessage, $exception->getMessage()); } - /** - * Provides source of the class's / trait's name, information if message of this exception should be prepared for - * class and the expected exception's message - * - * @return Generator - */ - public function provideClassName(): Generator + public function testCreateUsingDefaults(): void { - yield[ - 'Not\Existing\Class', - true, - 'Name of class from given \'string\' Not\Existing\Class cannot be resolved. Is there everything ok?', - ]; + $exception = CannotResolveClassNameException::create(stdClass::class); + $expectedMessage = 'Name of class from given \'string\' stdClass cannot be resolved. Is there everything ok?'; - yield[ - 'Not\Existing\Trait', - false, - 'Name of trait from given \'string\' Not\Existing\Trait cannot be resolved. Is there everything ok?', - ]; - - yield[ - stdClass::class, - true, - 'Name of class from given \'string\' stdClass cannot be resolved. Is there everything ok?', - ]; + static::assertSame($expectedMessage, $exception->getMessage()); } } diff --git a/tests/Exception/Reflection/ClassWithoutConstructorExceptionTest.php b/tests/Exception/Reflection/ClassWithoutConstructorExceptionTest.php index 85c6fec..13e9eff 100644 --- a/tests/Exception/Reflection/ClassWithoutConstructorExceptionTest.php +++ b/tests/Exception/Reflection/ClassWithoutConstructorExceptionTest.php @@ -25,6 +25,23 @@ use Meritoo\Common\Utilities\Arrays; */ class ClassWithoutConstructorExceptionTest extends BaseTestCase { + public function provideClassName(): Generator + { + $template = 'Oops, class \'%s\' hasn\'t constructor. Did you use proper class?'; + + yield [ + 'An empty name of class', + '', + sprintf($template, ''), + ]; + + yield [ + 'The Arrays class', + Arrays::class, + sprintf($template, Arrays::class), + ]; + } + public function testConstructor(): void { static::assertConstructorVisibilityAndArguments( @@ -46,21 +63,4 @@ class ClassWithoutConstructorExceptionTest extends BaseTestCase $exception = ClassWithoutConstructorException::create($className); static::assertSame($expectedMessage, $exception->getMessage(), $description); } - - public function provideClassName(): Generator - { - $template = 'Oops, class \'%s\' hasn\'t constructor. Did you use proper class?'; - - yield[ - 'An empty name of class', - '', - sprintf($template, ''), - ]; - - yield[ - 'The Arrays class', - Arrays::class, - sprintf($template, Arrays::class), - ]; - } } diff --git a/tests/Exception/Reflection/MissingChildClassesExceptionTest.php b/tests/Exception/Reflection/MissingChildClassesExceptionTest.php index d3aaf2e..fccac2e 100644 --- a/tests/Exception/Reflection/MissingChildClassesExceptionTest.php +++ b/tests/Exception/Reflection/MissingChildClassesExceptionTest.php @@ -12,6 +12,7 @@ use Generator; use Meritoo\Common\Exception\Reflection\MissingChildClassesException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; +use stdClass; /** * Test case of an exception used while given class has no child classes @@ -24,6 +25,30 @@ use Meritoo\Common\Type\OopVisibilityType; */ class MissingChildClassesExceptionTest extends BaseTestCase { + /** + * Provides name of class that hasn't child classes, but it should, and expected exception's message + * + * @return Generator + */ + public function provideParentClass(): ?Generator + { + $template = 'The \'%s\' class requires one child class at least who will extend her (maybe is an abstract' + .' class), but the child classes are missing. Did you forget to extend this class?'; + + yield [ + MissingChildClassesException::class, + sprintf($template, MissingChildClassesException::class), + ]; + + yield [ + [ + new stdClass(), + new stdClass(), + ], + sprintf($template, stdClass::class), + ]; + } + public function testConstructorVisibilityAndArguments(): void { static::assertConstructorVisibilityAndArguments( @@ -45,28 +70,4 @@ class MissingChildClassesExceptionTest extends BaseTestCase $exception = MissingChildClassesException::create($parentClass); static::assertSame($expectedMessage, $exception->getMessage()); } - - /** - * Provides name of class that hasn't child classes, but it should, and expected exception's message - * - * @return Generator - */ - public function provideParentClass(): ?Generator - { - $template = 'The \'%s\' class requires one child class at least who will extend her (maybe is an abstract' - . ' class), but the child classes are missing. Did you forget to extend this class?'; - - yield[ - MissingChildClassesException::class, - sprintf($template, MissingChildClassesException::class), - ]; - - yield[ - [ - new \stdClass(), - new \stdClass(), - ], - sprintf($template, \stdClass::class), - ]; - } } diff --git a/tests/Exception/Reflection/NotExistingPropertyExceptionTest.php b/tests/Exception/Reflection/NotExistingPropertyExceptionTest.php index 605aa36..256a75c 100644 --- a/tests/Exception/Reflection/NotExistingPropertyExceptionTest.php +++ b/tests/Exception/Reflection/NotExistingPropertyExceptionTest.php @@ -8,9 +8,11 @@ namespace Meritoo\Test\Common\Exception\Reflection; +use Generator; use Meritoo\Common\Exception\Reflection\NotExistingPropertyException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; +use stdClass; /** * Class NotExistingPropertyExceptionTest @@ -23,6 +25,39 @@ use Meritoo\Common\Type\OopVisibilityType; */ class NotExistingPropertyExceptionTest extends BaseTestCase { + public function provideObjectPropertyAndMessage(): ?Generator + { + $template = 'Property \'%s\' does not exist in instance of class \'%s\'. Did you use proper name of property?'; + + yield [ + 'An empty string as name of property', + new stdClass(), + '', + sprintf($template, '', get_class(new stdClass())), + ]; + + yield [ + 'Null as name of property', + new stdClass(), + null, + sprintf($template, '', get_class(new stdClass())), + ]; + + yield [ + 'String with spaces as name of property', + new stdClass(), + 'This is test', + sprintf($template, 'This is test', get_class(new stdClass())), + ]; + + yield [ + 'String without spaces as name of property', + new stdClass(), + 'ThisIsTest', + sprintf($template, 'ThisIsTest', get_class(new stdClass())), + ]; + } + public function testConstructor(): void { static::assertConstructorVisibilityAndArguments( @@ -45,37 +80,4 @@ class NotExistingPropertyExceptionTest extends BaseTestCase $exception = NotExistingPropertyException::create($object, $property); static::assertSame($expectedMessage, $exception->getMessage(), $description); } - - public function provideObjectPropertyAndMessage(): ?\Generator - { - $template = 'Property \'%s\' does not exist in instance of class \'%s\'. Did you use proper name of property?'; - - yield[ - 'An empty string as name of property', - new \stdClass(), - '', - sprintf($template, '', get_class(new \stdClass())), - ]; - - yield[ - 'Null as name of property', - new \stdClass(), - null, - sprintf($template, '', get_class(new \stdClass())), - ]; - - yield[ - 'String with spaces as name of property', - new \stdClass(), - 'This is test', - sprintf($template, 'This is test', get_class(new \stdClass())), - ]; - - yield[ - 'String without spaces as name of property', - new \stdClass(), - 'ThisIsTest', - sprintf($template, 'ThisIsTest', get_class(new \stdClass())), - ]; - } } diff --git a/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php b/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php index b0d8dc6..9d0c58d 100644 --- a/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php +++ b/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php @@ -12,6 +12,7 @@ use Generator; use Meritoo\Common\Exception\Reflection\TooManyChildClassesException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; +use stdClass; /** * Test case of an exception used while given class has more than one child class @@ -24,6 +25,38 @@ use Meritoo\Common\Type\OopVisibilityType; */ class TooManyChildClassesExceptionTest extends BaseTestCase { + /** + * Provides name of class that has more than one child class, but it shouldn't, child classes, and expected + * exception's message + * + * @return Generator + */ + public function provideParentAndChildClasses(): ?Generator + { + $template = "The '%s' class requires one child class at most who will extend her, but more than one child" + ." class was found:\n- %s\n\nWhy did you create more than one classes that extend '%s' class?"; + + yield [ + BaseTestCase::class, + [ + stdClass::class, + OopVisibilityType::class, + ], + sprintf($template, BaseTestCase::class, implode("\n- ", [ + stdClass::class, + OopVisibilityType::class, + ]), BaseTestCase::class), + ]; + + yield [ + TooManyChildClassesException::class, + [ + stdClass::class, + ], + sprintf($template, TooManyChildClassesException::class, implode("\n- ", [stdClass::class]), TooManyChildClassesException::class), + ]; + } + public function testConstructor(): void { static::assertConstructorVisibilityAndArguments( @@ -46,36 +79,4 @@ class TooManyChildClassesExceptionTest extends BaseTestCase $exception = TooManyChildClassesException::create($parentClass, $childClasses); static::assertSame($expectedMessage, $exception->getMessage()); } - - /** - * Provides name of class that has more than one child class, but it shouldn't, child classes, and expected - * exception's message - * - * @return Generator - */ - public function provideParentAndChildClasses(): ?Generator - { - $template = "The '%s' class requires one child class at most who will extend her, but more than one child" - . " class was found:\n- %s\n\nWhy did you create more than one classes that extend '%s' class?"; - - yield[ - BaseTestCase::class, - [ - \stdClass::class, - OopVisibilityType::class, - ], - sprintf($template, BaseTestCase::class, implode("\n- ", [ - \stdClass::class, - OopVisibilityType::class, - ]), BaseTestCase::class), - ]; - - yield[ - TooManyChildClassesException::class, - [ - \stdClass::class, - ], - sprintf($template, TooManyChildClassesException::class, implode("\n- ", [\stdClass::class]), TooManyChildClassesException::class), - ]; - } } diff --git a/tests/Exception/Regex/IncorrectColorHexLengthExceptionTest.php b/tests/Exception/Regex/IncorrectColorHexLengthExceptionTest.php index 36c3fbb..754f8ab 100644 --- a/tests/Exception/Regex/IncorrectColorHexLengthExceptionTest.php +++ b/tests/Exception/Regex/IncorrectColorHexLengthExceptionTest.php @@ -20,13 +20,28 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\Regex\IncorrectColorHexLengthException + * @covers \Meritoo\Common\Exception\Regex\IncorrectColorHexLengthException */ class IncorrectColorHexLengthExceptionTest extends BaseTestCase { - public function testConstructorVisibilityAndArguments() + /** + * Provides incorrect hexadecimal value of color and expected exception's message + * + * @return Generator + */ + public function provideColor() { - static::assertConstructorVisibilityAndArguments(IncorrectColorHexLengthException::class, OopVisibilityType::IS_PUBLIC, 3); + $template = 'Length of hexadecimal value of color \'%s\' is incorrect. It\'s %d, but it should be 3 or 6. Is there everything ok?'; + + yield [ + '', + sprintf($template, '', strlen('')), + ]; + + yield [ + 'aa-bb-cc', + sprintf($template, 'aa-bb-cc', strlen('aa-bb-cc')), + ]; } /** @@ -41,23 +56,8 @@ class IncorrectColorHexLengthExceptionTest extends BaseTestCase static::assertSame($expectedMessage, $exception->getMessage()); } - /** - * Provides incorrect hexadecimal value of color and expected exception's message - * - * @return Generator - */ - public function provideColor() + public function testConstructorVisibilityAndArguments() { - $template = 'Length of hexadecimal value of color \'%s\' is incorrect. It\'s %d, but it should be 3 or 6. Is there everything ok?'; - - yield[ - '', - sprintf($template, '', strlen('')), - ]; - - yield[ - 'aa-bb-cc', - sprintf($template, 'aa-bb-cc', strlen('aa-bb-cc')), - ]; + static::assertConstructorVisibilityAndArguments(IncorrectColorHexLengthException::class, OopVisibilityType::IS_PUBLIC, 3); } } diff --git a/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php b/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php index 1de82d3..38b4cf0 100644 --- a/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php +++ b/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php @@ -20,13 +20,28 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\Regex\InvalidColorHexValueException + * @covers \Meritoo\Common\Exception\Regex\InvalidColorHexValueException */ class InvalidColorHexValueExceptionTest extends BaseTestCase { - public function testConstructorVisibilityAndArguments() + /** + * Provides invalid hexadecimal value of color and expected exception's message + * + * @return Generator + */ + public function provideColor() { - static::assertConstructorVisibilityAndArguments(InvalidColorHexValueException::class, OopVisibilityType::IS_PUBLIC, 3); + $template = 'Hexadecimal value of color \'%s\' is invalid. Is there everything ok?'; + + yield [ + '', + sprintf($template, ''), + ]; + + yield [ + 'aa-bb-cc', + sprintf($template, 'aa-bb-cc'), + ]; } /** @@ -41,23 +56,8 @@ class InvalidColorHexValueExceptionTest extends BaseTestCase static::assertSame($expectedMessage, $exception->getMessage()); } - /** - * Provides invalid hexadecimal value of color and expected exception's message - * - * @return Generator - */ - public function provideColor() + public function testConstructorVisibilityAndArguments() { - $template = 'Hexadecimal value of color \'%s\' is invalid. Is there everything ok?'; - - yield[ - '', - sprintf($template, ''), - ]; - - yield[ - 'aa-bb-cc', - sprintf($template, 'aa-bb-cc'), - ]; + static::assertConstructorVisibilityAndArguments(InvalidColorHexValueException::class, OopVisibilityType::IS_PUBLIC, 3); } } diff --git a/tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php b/tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php index 6b3cc33..799169d 100644 --- a/tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php +++ b/tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php @@ -20,13 +20,33 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\Regex\InvalidHtmlAttributesException + * @covers \Meritoo\Common\Exception\Regex\InvalidHtmlAttributesException */ class InvalidHtmlAttributesExceptionTest extends BaseTestCase { - public function testConstructorVisibilityAndArguments() + /** + * Provides html attributes + * + * @return Generator + */ + public function provideHtmlAttributes() { - static::assertConstructorVisibilityAndArguments(InvalidHtmlAttributesException::class, OopVisibilityType::IS_PUBLIC, 3); + $template = 'HTML attributes \'%s\' are invalid. Is there everything ok?'; + + yield [ + 'abc = def', + sprintf($template, 'abc = def'), + ]; + + yield [ + 'abc = def ghi = jkl', + sprintf($template, 'abc = def ghi = jkl'), + ]; + + yield [ + 'abc=def ghi=jkl', + sprintf($template, 'abc=def ghi=jkl'), + ]; } /** @@ -41,28 +61,8 @@ class InvalidHtmlAttributesExceptionTest extends BaseTestCase static::assertSame($expectedMessage, $exception->getMessage()); } - /** - * Provides html attributes - * - * @return Generator - */ - public function provideHtmlAttributes() + public function testConstructorVisibilityAndArguments() { - $template = 'HTML attributes \'%s\' are invalid. Is there everything ok?'; - - yield[ - 'abc = def', - sprintf($template, 'abc = def'), - ]; - - yield[ - 'abc = def ghi = jkl', - sprintf($template, 'abc = def ghi = jkl'), - ]; - - yield[ - 'abc=def ghi=jkl', - sprintf($template, 'abc=def ghi=jkl'), - ]; + static::assertConstructorVisibilityAndArguments(InvalidHtmlAttributesException::class, OopVisibilityType::IS_PUBLIC, 3); } } diff --git a/tests/Exception/Regex/InvalidUrlExceptionTest.php b/tests/Exception/Regex/InvalidUrlExceptionTest.php index 0910d0f..cee47d9 100644 --- a/tests/Exception/Regex/InvalidUrlExceptionTest.php +++ b/tests/Exception/Regex/InvalidUrlExceptionTest.php @@ -20,13 +20,28 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\Regex\InvalidUrlException + * @covers \Meritoo\Common\Exception\Regex\InvalidUrlException */ class InvalidUrlExceptionTest extends BaseTestCase { - public function testConstructorVisibilityAndArguments() + /** + * Provides invalid url and expected exception's message + * + * @return Generator + */ + public function provideUrl() { - static::assertConstructorVisibilityAndArguments(InvalidUrlException::class, OopVisibilityType::IS_PUBLIC, 3); + $template = 'Url \'%s\' is invalid. Is there everything ok?'; + + yield [ + 'aa/bb/cc', + sprintf($template, 'aa/bb/cc'), + ]; + + yield [ + 'http:/images\show\car.jpg', + sprintf($template, 'http:/images\show\car.jpg'), + ]; } /** @@ -41,23 +56,8 @@ class InvalidUrlExceptionTest extends BaseTestCase static::assertSame($expectedMessage, $exception->getMessage()); } - /** - * Provides invalid url and expected exception's message - * - * @return Generator - */ - public function provideUrl() + public function testConstructorVisibilityAndArguments() { - $template = 'Url \'%s\' is invalid. Is there everything ok?'; - - yield[ - 'aa/bb/cc', - sprintf($template, 'aa/bb/cc'), - ]; - - yield[ - 'http:/images\show\car.jpg', - sprintf($template, 'http:/images\show\car.jpg'), - ]; + static::assertConstructorVisibilityAndArguments(InvalidUrlException::class, OopVisibilityType::IS_PUBLIC, 3); } } diff --git a/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php b/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php index a4f836d..fb71f5b 100644 --- a/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php +++ b/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php @@ -25,13 +25,27 @@ use Meritoo\Common\Type\OopVisibilityType; */ class UnknownOopVisibilityTypeExceptionTest extends BaseTestCase { - public function testConstructorVisibilityAndArguments(): void + /** + * Provides path of the empty file and expected exception's message + * + * @return Generator + */ + public function provideUnknownType(): Generator { - static::assertConstructorVisibilityAndArguments( - UnknownOopVisibilityTypeException::class, - OopVisibilityType::IS_PUBLIC, - 3 - ); + $allTypes = (new OopVisibilityType())->getAll(); + + $template = 'The \'%s\' type of OOP-related visibility is unknown. Probably doesn\'t exist or there is a typo.' + .' You should use one of these types: %s.'; + + yield [ + '', + sprintf($template, '', implode(', ', $allTypes)), + ]; + + yield [ + 123, + sprintf($template, 123, implode(', ', $allTypes)), + ]; } /** @@ -46,26 +60,12 @@ class UnknownOopVisibilityTypeExceptionTest extends BaseTestCase static::assertSame($expectedMessage, $exception->getMessage()); } - /** - * Provides path of the empty file and expected exception's message - * - * @return Generator - */ - public function provideUnknownType(): Generator + public function testConstructorVisibilityAndArguments(): void { - $allTypes = (new OopVisibilityType())->getAll(); - - $template = 'The \'%s\' type of OOP-related visibility is unknown. Probably doesn\'t exist or there is a typo.' - . ' You should use one of these types: %s.'; - - yield[ - '', - sprintf($template, '', implode(', ', $allTypes)), - ]; - - yield[ - 123, - sprintf($template, 123, implode(', ', $allTypes)), - ]; + static::assertConstructorVisibilityAndArguments( + UnknownOopVisibilityTypeException::class, + OopVisibilityType::IS_PUBLIC, + 3 + ); } } diff --git a/tests/Exception/ValueObject/InvalidSizeDimensionsExceptionTest.php b/tests/Exception/ValueObject/InvalidSizeDimensionsExceptionTest.php index 87422e5..6487c98 100644 --- a/tests/Exception/ValueObject/InvalidSizeDimensionsExceptionTest.php +++ b/tests/Exception/ValueObject/InvalidSizeDimensionsExceptionTest.php @@ -19,10 +19,33 @@ use Meritoo\Common\Type\OopVisibilityType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Exception\ValueObject\InvalidSizeDimensionsException + * @covers \Meritoo\Common\Exception\ValueObject\InvalidSizeDimensionsException */ class InvalidSizeDimensionsExceptionTest extends BaseTestCase { + public function provideWidthAndHeight() + { + $template = 'Dimensions of size should be positive, but they are not: %d, %d. Is there everything ok?'; + + yield [ + 0, + 0, + sprintf($template, 0, 0), + ]; + + yield [ + -1, + -1, + sprintf($template, -1, -1), + ]; + + yield [ + 200, + 100, + sprintf($template, 200, 100), + ]; + } + public function testConstructorVisibilityAndArguments() { static::assertConstructorVisibilityAndArguments( @@ -44,27 +67,4 @@ class InvalidSizeDimensionsExceptionTest extends BaseTestCase $exception = InvalidSizeDimensionsException::create($width, $height); static::assertSame($expectedMessage, $exception->getMessage()); } - - public function provideWidthAndHeight() - { - $template = 'Dimensions of size should be positive, but they are not: %d, %d. Is there everything ok?'; - - yield[ - 0, - 0, - sprintf($template, 0, 0), - ]; - - yield[ - -1, - -1, - sprintf($template, -1, -1), - ]; - - yield[ - 200, - 100, - sprintf($template, 200, 100), - ]; - } } diff --git a/tests/Exception/ValueObject/Template/InvalidContentExceptionTest.php b/tests/Exception/ValueObject/Template/InvalidContentExceptionTest.php index e5bab54..6392407 100644 --- a/tests/Exception/ValueObject/Template/InvalidContentExceptionTest.php +++ b/tests/Exception/ValueObject/Template/InvalidContentExceptionTest.php @@ -24,6 +24,29 @@ use Meritoo\Common\Type\OopVisibilityType; */ class InvalidContentExceptionTest extends BaseTestCase { + public function provideContent(): ?Generator + { + $template = 'Content of template \'%s\' is invalid. Did you use string with 1 placeholder at least?'; + + yield [ + 'An empty string', + '', + sprintf($template, ''), + ]; + + yield [ + 'Simple string', + 'Lorem ipsum', + sprintf($template, 'Lorem ipsum'), + ]; + + yield [ + 'One sentence', + 'Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh.', + sprintf($template, 'Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh.'), + ]; + } + public function testConstructorVisibilityAndArguments(): void { static::assertConstructorVisibilityAndArguments( @@ -45,27 +68,4 @@ class InvalidContentExceptionTest extends BaseTestCase $exception = InvalidContentException::create($content); static::assertSame($expectedMessage, $exception->getMessage(), $description); } - - public function provideContent(): ?Generator - { - $template = 'Content of template \'%s\' is invalid. Did you use string with 1 placeholder at least?'; - - yield[ - 'An empty string', - '', - sprintf($template, ''), - ]; - - yield[ - 'Simple string', - 'Lorem ipsum', - sprintf($template, 'Lorem ipsum'), - ]; - - yield[ - 'One sentence', - 'Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh.', - sprintf($template, 'Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh.'), - ]; - } } diff --git a/tests/Exception/ValueObject/Template/MissingPlaceholdersInValuesExceptionTest.php b/tests/Exception/ValueObject/Template/MissingPlaceholdersInValuesExceptionTest.php index dfcd549..86a6602 100644 --- a/tests/Exception/ValueObject/Template/MissingPlaceholdersInValuesExceptionTest.php +++ b/tests/Exception/ValueObject/Template/MissingPlaceholdersInValuesExceptionTest.php @@ -8,6 +8,7 @@ namespace Meritoo\Test\Common\Exception\ValueObject\Template; +use Generator; use Meritoo\Common\Exception\ValueObject\Template\MissingPlaceholdersInValuesException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; @@ -23,6 +24,39 @@ use Meritoo\Common\Type\OopVisibilityType; */ class MissingPlaceholdersInValuesExceptionTest extends BaseTestCase { + public function provideContentAndMissingPlaceholders(): ?Generator + { + $template = 'Cannot fill template \'%s\', because of missing values for placeholder(s): %s. Did you provide all' + .' required values?'; + + yield [ + 'Missing 2nd placeholder', + '%test1% - %test2%', + [ + 'test2', + ], + sprintf( + $template, + '%test1% - %test2%', + 'test2' + ), + ]; + + yield [ + 'Missing 2nd and 3rd placeholder', + '%test1% / %test2% / %test3%', + [ + 'test2', + 'test3', + ], + sprintf( + $template, + '%test1% / %test2% / %test3%', + 'test2, test3' + ), + ]; + } + public function testConstructorVisibilityAndArguments(): void { static::assertConstructorVisibilityAndArguments( @@ -49,37 +83,4 @@ class MissingPlaceholdersInValuesExceptionTest extends BaseTestCase $exception = MissingPlaceholdersInValuesException::create($content, $missingPlaceholders); static::assertSame($expectedMessage, $exception->getMessage(), $description); } - - public function provideContentAndMissingPlaceholders(): ?\Generator - { - $template = 'Cannot fill template \'%s\', because of missing values for placeholder(s): %s. Did you provide all' - . ' required values?'; - - yield[ - 'Missing 2nd placeholder', - '%test1% - %test2%', - [ - 'test2', - ], - sprintf( - $template, - '%test1% - %test2%', - 'test2' - ), - ]; - - yield[ - 'Missing 2nd and 3rd placeholder', - '%test1% / %test2% / %test3%', - [ - 'test2', - 'test3', - ], - sprintf( - $template, - '%test1% / %test2% / %test3%', - 'test2, test3' - ), - ]; - } } diff --git a/tests/Exception/ValueObject/Template/TemplateNotFoundExceptionTest.php b/tests/Exception/ValueObject/Template/TemplateNotFoundExceptionTest.php index 3c2982d..4616f7a 100644 --- a/tests/Exception/ValueObject/Template/TemplateNotFoundExceptionTest.php +++ b/tests/Exception/ValueObject/Template/TemplateNotFoundExceptionTest.php @@ -24,6 +24,29 @@ use Meritoo\Common\Type\OopVisibilityType; */ class TemplateNotFoundExceptionTest extends BaseTestCase { + public function provideIndexAndException(): ?Generator + { + $template = 'Template with \'%s\' index was not found. Did you provide all required templates?'; + + yield [ + 'An empty string', + '', + new TemplateNotFoundException(sprintf($template, '')), + ]; + + yield [ + 'Non-empty string', + 'test', + new TemplateNotFoundException(sprintf($template, 'test')), + ]; + + yield [ + 'Integer', + '2', + new TemplateNotFoundException(sprintf($template, 2)), + ]; + } + public function testConstructor(): void { static::assertConstructorVisibilityAndArguments( @@ -45,27 +68,4 @@ class TemplateNotFoundExceptionTest extends BaseTestCase $created = TemplateNotFoundException::create($index); static::assertEquals($expected, $created, $description); } - - public function provideIndexAndException(): ?Generator - { - $template = 'Template with \'%s\' index was not found. Did you provide all required templates?'; - - yield[ - 'An empty string', - '', - new TemplateNotFoundException(sprintf($template, '')), - ]; - - yield[ - 'Non-empty string', - 'test', - new TemplateNotFoundException(sprintf($template, 'test')), - ]; - - yield[ - 'Integer', - '2', - new TemplateNotFoundException(sprintf($template, 2)), - ]; - } } diff --git a/tests/Test/Base/BaseTestCaseTest.php b/tests/Test/Base/BaseTestCaseTest.php index 83d024d..83c2308 100644 --- a/tests/Test/Base/BaseTestCaseTest.php +++ b/tests/Test/Base/BaseTestCaseTest.php @@ -21,28 +21,59 @@ use Meritoo\Common\Utilities\GeneratorUtility; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Test\Base\BaseTestCase + * @covers \Meritoo\Common\Test\Base\BaseTestCase */ class BaseTestCaseTest extends BaseTestCase { + /** + * Provides name of file and path of directory containing the file + * + * @return Generator + */ + public function provideFileNameAndDirectoryPath() + { + yield [ + 'abc.jpg', + '', + ]; + + yield [ + 'abc.def.jpg', + '', + ]; + + yield [ + 'abc.jpg', + 'def', + ]; + + yield [ + 'abc.def.jpg', + 'def', + ]; + } + public function testConstructor() { static::assertConstructorVisibilityAndArguments(BaseTestCase::class, OopVisibilityType::IS_PUBLIC, 3); } - public function testProvideEmptyValue() + /** + * @param string $fileName Name of file + * @param string $directoryPath Path of directory containing the file + * + * @dataProvider provideFileNameAndDirectoryPath + */ + public function testGetFilePathForTesting($fileName, $directoryPath) { - $elements = [ - [''], - [' '], - [null], - [0], - [false], - [[]], - ]; + $path = (new SimpleTestCase())->getFilePathForTesting($fileName, $directoryPath); - $generator = (new SimpleTestCase())->provideEmptyValue(); - self::assertEquals($elements, GeneratorUtility::getGeneratorElements($generator)); + if (!empty($directoryPath)) { + $directoryPath .= '/'; + } + + $expectedContains = sprintf('/data/tests/%s%s', $directoryPath, $fileName); + static::assertStringContainsString($expectedContains, $path); } public function testProvideBooleanValue() @@ -109,6 +140,21 @@ class BaseTestCaseTest extends BaseTestCase self::assertEquals($elements, GeneratorUtility::getGeneratorElements($generator)); } + public function testProvideEmptyValue() + { + $elements = [ + [''], + [' '], + [null], + [0], + [false], + [[]], + ]; + + $generator = (new SimpleTestCase())->provideEmptyValue(); + self::assertEquals($elements, GeneratorUtility::getGeneratorElements($generator)); + } + public function testProvideNotExistingFilePath() { $elements = [ @@ -120,52 +166,6 @@ class BaseTestCaseTest extends BaseTestCase $generator = (new SimpleTestCase())->provideNotExistingFilePath(); self::assertEquals($elements, GeneratorUtility::getGeneratorElements($generator)); } - - /** - * @param string $fileName Name of file - * @param string $directoryPath Path of directory containing the file - * - * @dataProvider provideFileNameAndDirectoryPath - */ - public function testGetFilePathForTesting($fileName, $directoryPath) - { - $path = (new SimpleTestCase())->getFilePathForTesting($fileName, $directoryPath); - - if (!empty($directoryPath)) { - $directoryPath .= '/'; - } - - $expectedContains = sprintf('/data/tests/%s%s', $directoryPath, $fileName); - static::assertStringContainsString($expectedContains, $path); - } - - /** - * Provides name of file and path of directory containing the file - * - * @return Generator - */ - public function provideFileNameAndDirectoryPath() - { - yield[ - 'abc.jpg', - '', - ]; - - yield[ - 'abc.def.jpg', - '', - ]; - - yield[ - 'abc.jpg', - 'def', - ]; - - yield[ - 'abc.def.jpg', - 'def', - ]; - } } /** diff --git a/tests/Traits/Test/Base/BaseTestCaseTraitTest.php b/tests/Traits/Test/Base/BaseTestCaseTraitTest.php index 7b9bf4b..d0e588d 100644 --- a/tests/Traits/Test/Base/BaseTestCaseTraitTest.php +++ b/tests/Traits/Test/Base/BaseTestCaseTraitTest.php @@ -33,6 +33,17 @@ class BaseTestCaseTraitTest extends BaseTestCase { use BaseTestCaseTrait; + public function testAssertConstructorVisibilityAndArgumentsUsingClassWithoutConstructor(): void + { + $this->expectException(ClassWithoutConstructorException::class); + static::assertConstructorVisibilityAndArguments(SimpleTestCase::class, OopVisibilityType::IS_PUBLIC); + } + + public function testAssertHasNoConstructor(): void + { + static::assertHasNoConstructor(SimpleTestCase::class); + } + public function testAssertMethodVisibility(): void { $method = new ReflectionMethod(SimpleTestCase::class, 'assertMethodVisibility'); @@ -53,54 +64,6 @@ class BaseTestCaseTraitTest extends BaseTestCase static::assertMethodVisibility($method, OopVisibilityType::IS_PRIVATE); } - public function testAssertConstructorVisibilityAndArgumentsUsingClassWithoutConstructor(): void - { - $this->expectException(ClassWithoutConstructorException::class); - static::assertConstructorVisibilityAndArguments(SimpleTestCase::class, OopVisibilityType::IS_PUBLIC); - } - - public function testAssertHasNoConstructor(): void - { - static::assertHasNoConstructor(SimpleTestCase::class); - } - - public function testProvideEmptyValue(): void - { - $testCase = new SimpleTestCase(); - $values = $testCase->provideEmptyValue(); - - $expected = [ - [''], - [' '], - [null], - [0], - [false], - [[]], - ]; - - foreach ($values as $index => $value) { - static::assertSame($expected[$index], $value); - } - } - - public function testProvideEmptyScalarValue(): void - { - $testCase = new SimpleTestCase(); - $values = $testCase->provideEmptyScalarValue(); - - $expected = [ - [''], - [' '], - [null], - [0], - [false], - ]; - - foreach ($values as $index => $value) { - static::assertSame($expected[$index], $value); - } - } - public function testProvideBooleanValue(): void { $testCase = new SimpleTestCase(); @@ -164,19 +127,40 @@ class BaseTestCaseTraitTest extends BaseTestCase } } - public function testProvideNotExistingFilePath(): void + public function testProvideEmptyScalarValue(): void { $testCase = new SimpleTestCase(); - $paths = $testCase->provideNotExistingFilePath(); + $values = $testCase->provideEmptyScalarValue(); $expected = [ - ['lets-test.doc'], - ['lorem/ipsum.jpg'], - ['surprise/me/one/more/time.txt'], + [''], + [' '], + [null], + [0], + [false], ]; - foreach ($paths as $index => $path) { - static::assertSame($expected[$index], $path); + foreach ($values as $index => $value) { + static::assertSame($expected[$index], $value); + } + } + + public function testProvideEmptyValue(): void + { + $testCase = new SimpleTestCase(); + $values = $testCase->provideEmptyValue(); + + $expected = [ + [''], + [' '], + [null], + [0], + [false], + [[]], + ]; + + foreach ($values as $index => $value) { + static::assertSame($expected[$index], $value); } } @@ -195,4 +179,20 @@ class BaseTestCaseTraitTest extends BaseTestCase static::assertEquals($expected[$index], $value); } } + + public function testProvideNotExistingFilePath(): void + { + $testCase = new SimpleTestCase(); + $paths = $testCase->provideNotExistingFilePath(); + + $expected = [ + ['lets-test.doc'], + ['lorem/ipsum.jpg'], + ['surprise/me/one/more/time.txt'], + ]; + + foreach ($paths as $index => $path) { + static::assertSame($expected[$index], $path); + } + } } diff --git a/tests/Type/Base/BaseTypeTest.php b/tests/Type/Base/BaseTypeTest.php index 282c59f..bf43078 100644 --- a/tests/Type/Base/BaseTypeTest.php +++ b/tests/Type/Base/BaseTypeTest.php @@ -23,6 +23,138 @@ use Meritoo\Common\Type\Base\BaseType; */ class BaseTypeTest extends BaseTestCase { + /** + * Provides type of something for testing the getAll() method + * + * @return Generator + */ + public function provideType(): ?Generator + { + yield [ + new TestEmptyType(), + [], + ]; + + yield [ + new TestType(), + [ + 'TEST_1' => TestType::TEST_1, + 'TEST_2' => TestType::TEST_2, + ], + ]; + } + + /** + * Provides type of something for testing the isCorrectType() method + * + * @return Generator + */ + public function provideTypeToVerifyUsingTestEmptyType(): ?Generator + { + yield [ + null, + false, + ]; + + yield [ + 'null', + false, + ]; + + yield [ + 'false', + false, + ]; + + yield [ + 'true', + false, + ]; + + yield [ + '', + false, + ]; + + yield [ + '0', + false, + ]; + + yield [ + '1', + false, + ]; + + yield [ + 'lorem', + false, + ]; + } + + /** + * Provides type of something for testing the isCorrectType() method + * + * @return Generator + */ + public function provideTypeToVerifyUsingTestType(): ?Generator + { + yield [ + null, + false, + ]; + + yield [ + 'null', + false, + ]; + + yield [ + 'false', + false, + ]; + + yield [ + 'true', + false, + ]; + + yield [ + '', + false, + ]; + + yield [ + '0', + false, + ]; + + yield [ + '1', + false, + ]; + + yield [ + 'lorem', + false, + ]; + + yield [ + 'test', + false, + ]; + + yield [ + 'test_1', + true, + ]; + + yield [ + 'test_2', + true, + ]; + } + public function testConstructor(): void { static::assertHasNoConstructor(BaseType::class); @@ -61,138 +193,6 @@ class BaseTypeTest extends BaseTestCase { self::assertEquals($isCorrect, TestType::isCorrectType($toVerifyType)); } - - /** - * Provides type of something for testing the getAll() method - * - * @return Generator - */ - public function provideType(): ?Generator - { - yield[ - new TestEmptyType(), - [], - ]; - - yield[ - new TestType(), - [ - 'TEST_1' => TestType::TEST_1, - 'TEST_2' => TestType::TEST_2, - ], - ]; - } - - /** - * Provides type of something for testing the isCorrectType() method - * - * @return Generator - */ - public function provideTypeToVerifyUsingTestEmptyType(): ?Generator - { - yield[ - null, - false, - ]; - - yield[ - 'null', - false, - ]; - - yield[ - 'false', - false, - ]; - - yield[ - 'true', - false, - ]; - - yield[ - '', - false, - ]; - - yield[ - '0', - false, - ]; - - yield[ - '1', - false, - ]; - - yield[ - 'lorem', - false, - ]; - } - - /** - * Provides type of something for testing the isCorrectType() method - * - * @return Generator - */ - public function provideTypeToVerifyUsingTestType(): ?Generator - { - yield[ - null, - false, - ]; - - yield[ - 'null', - false, - ]; - - yield[ - 'false', - false, - ]; - - yield[ - 'true', - false, - ]; - - yield[ - '', - false, - ]; - - yield[ - '0', - false, - ]; - - yield[ - '1', - false, - ]; - - yield[ - 'lorem', - false, - ]; - - yield[ - 'test', - false, - ]; - - yield[ - 'test_1', - true, - ]; - - yield[ - 'test_2', - true, - ]; - } } /** diff --git a/tests/Type/DatePartTypeTest.php b/tests/Type/DatePartTypeTest.php index 64d7c15..5a24fe1 100644 --- a/tests/Type/DatePartTypeTest.php +++ b/tests/Type/DatePartTypeTest.php @@ -20,7 +20,7 @@ use Meritoo\Common\Type\DatePartType; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Type\DatePartType + * @covers \Meritoo\Common\Type\DatePartType */ class DatePartTypeTest extends BaseTypeTestCase { @@ -29,52 +29,52 @@ class DatePartTypeTest extends BaseTypeTestCase */ public function provideTypeToVerify(): Generator { - yield[ + yield [ DatePartType::isCorrectType(''), false, ]; - yield[ + yield [ DatePartType::isCorrectType(null), false, ]; - yield[ + yield [ DatePartType::isCorrectType('0'), false, ]; - yield[ + yield [ DatePartType::isCorrectType('1'), false, ]; - yield[ + yield [ DatePartType::isCorrectType('day'), true, ]; - yield[ + yield [ DatePartType::isCorrectType('hour'), true, ]; - yield[ + yield [ DatePartType::isCorrectType('minute'), true, ]; - yield[ + yield [ DatePartType::isCorrectType('month'), true, ]; - yield[ + yield [ DatePartType::isCorrectType('second'), true, ]; - yield[ + yield [ DatePartType::isCorrectType('year'), true, ]; @@ -86,12 +86,12 @@ class DatePartTypeTest extends BaseTypeTestCase protected function getAllExpectedTypes(): array { return [ - 'DAY' => 'day', - 'HOUR' => 'hour', + 'DAY' => 'day', + 'HOUR' => 'hour', 'MINUTE' => 'minute', - 'MONTH' => 'month', + 'MONTH' => 'month', 'SECOND' => 'second', - 'YEAR' => 'year', + 'YEAR' => 'year', ]; } diff --git a/tests/Type/DatePeriodTest.php b/tests/Type/DatePeriodTest.php index c6ae1f8..a45bb3d 100644 --- a/tests/Type/DatePeriodTest.php +++ b/tests/Type/DatePeriodTest.php @@ -26,13 +26,222 @@ use Meritoo\Common\Type\OopVisibilityType; */ class DatePeriodTest extends BaseTypeTestCase { - public function testConstructorVisibilityAndArguments(): void + /** + * Provides the start and end date of date period + * + * @return Generator + */ + public function provideDatePeriod(): Generator { - static::assertConstructorVisibilityAndArguments( - DatePeriod::class, - OopVisibilityType::IS_PUBLIC, - 2 - ); + $startDate = new DateTime('2001-01-01'); + $endDate = new DateTime('2002-02-02'); + + yield [ + null, + null, + ]; + + yield [ + $startDate, + $startDate, + null, + ]; + + yield [ + null, + null, + $endDate, + ]; + + yield [ + $startDate, + $endDate, + ]; + } + + /** + * Provides period and format of date to verify + * + * @return Generator + */ + public function provideDatePeriodAndDateFormat(): Generator + { + $startDate = new DateTime('2001-01-01'); + $endDate = new DateTime('2002-02-02'); + + // For start date + yield [ + new DatePeriod($startDate, $endDate), + 'Y', + true, + '2001', + ]; + + yield [ + new DatePeriod($startDate, $endDate), + 'D', + true, + 'Mon', + ]; + + yield [ + new DatePeriod($startDate, $endDate), + 'Y-m-d', + true, + '2001-01-01', + ]; + + yield [ + new DatePeriod($startDate, $endDate), + 'Y-m-d H:i', + true, + '2001-01-01 00:00', + ]; + + // For end date + yield [ + new DatePeriod($startDate, $endDate), + 'Y', + false, + '2002', + ]; + + yield [ + new DatePeriod($startDate, $endDate), + 'D', + false, + 'Sat', + ]; + + yield [ + new DatePeriod($startDate, $endDate), + 'Y-m-d', + false, + '2002-02-02', + ]; + + yield [ + new DatePeriod($startDate, $endDate), + 'Y-m-d H:i', + false, + '2002-02-02 00:00', + ]; + } + + /** + * Provides period and format of date to verify using the start date + * + * @return Generator + */ + public function provideDatePeriodAndDateFormatUsingStartDateOnly(): Generator + { + $startDate = new DateTime('2001-01-01'); + $endDate = new DateTime('2002-02-02'); + + yield [ + new DatePeriod($startDate, $endDate), + 'Y', + '2001', + ]; + + yield [ + new DatePeriod($startDate, $endDate), + 'D', + 'Mon', + ]; + + yield [ + new DatePeriod($startDate, $endDate), + 'Y-m-d', + '2001-01-01', + ]; + + yield [ + new DatePeriod($startDate, $endDate), + 'Y-m-d H:i', + '2001-01-01 00:00', + ]; + } + + /** + * Provides period and incorrect format of date to verify + * + * @return Generator + */ + public function provideDatePeriodAndIncorrectDateFormat(): Generator + { + $startDate = new DateTime('2001-01-01'); + $endDate = new DateTime('2002-02-02'); + + yield [ + new DatePeriod($startDate, $endDate), + '', + ]; + + yield [ + new DatePeriod($startDate, $endDate), + false, + ]; + } + + public function provideDatePeriodAndUnknownDate(): ?Generator + { + $date = new DateTime('2001-01-01'); + + yield [ + new DatePeriod(), + 'Y-m-d', + false, + ]; + + yield [ + new DatePeriod(), + 'Y-m-d', + true, + ]; + + yield [ + new DatePeriod($date), + 'Y-m-d', + false, + ]; + + yield [ + new DatePeriod(null, $date), + 'Y-m-d', + true, + ]; + } + + /** + * {@inheritdoc} + */ + public function provideTypeToVerify(): Generator + { + yield [ + DatePeriod::isCorrectType(''), + false, + ]; + + yield [ + DatePeriod::isCorrectType('-1'), + false, + ]; + + yield [ + DatePeriod::isCorrectType('4'), + true, + ]; + + yield [ + DatePeriod::isCorrectType('3'), + true, + ]; + + yield [ + DatePeriod::isCorrectType('8'), + true, + ]; } /** @@ -49,6 +258,63 @@ class DatePeriodTest extends BaseTypeTestCase self::assertEquals($endDate, $period->getEndDate()); } + public function testConstructorVisibilityAndArguments(): void + { + static::assertConstructorVisibilityAndArguments( + DatePeriod::class, + OopVisibilityType::IS_PUBLIC, + 2 + ); + } + + /** + * @param DatePeriod $period The date period to verify + * @param string $format Format used to format the date + * @param bool $startDate If is set to true, start date is formatted. Otherwise - end date. + * @param string $expected Expected, formatted date + * + * @dataProvider provideDatePeriodAndDateFormat + */ + public function testGetFormattedDate(DatePeriod $period, $format, $startDate, $expected): void + { + self::assertEquals($expected, $period->getFormattedDate($format, $startDate)); + } + + /** + * @param DatePeriod $period The date period to verify + * @param string $format Format used to format the date + * + * @dataProvider provideDatePeriodAndIncorrectDateFormat + */ + public function testGetFormattedDateUsingIncorrectDateFormat(DatePeriod $period, $format): void + { + self::assertEquals('', $period->getFormattedDate($format)); + } + + /** + * @param DatePeriod $period The date period to verify + * @param string $format Format used to format the date + * @param string $expected Expected, formatted date + * + * @dataProvider provideDatePeriodAndDateFormatUsingStartDateOnly + */ + public function testGetFormattedDateUsingStartDateOnly(DatePeriod $period, $format, $expected): void + { + self::assertEquals($expected, $period->getFormattedDate($format)); + } + + /** + * @param DatePeriod $period The date period to verify + * @param string $format Format used to format the date + * @param bool $startDate If is set to true, start date is formatted. Otherwise - end date. + * + * @dataProvider provideDatePeriodAndUnknownDate + */ + public function testGetFormattedDateUsingUnknownDate(DatePeriod $period, $format, $startDate): void + { + self::assertEquals('', $period->getFormattedDate($format, $startDate)); + } + /** * @param DateTime $startDate (optional) Start date of period * @param DateTime $endDate (optional) End date of period @@ -66,272 +332,6 @@ class DatePeriodTest extends BaseTypeTestCase self::assertEquals($endDate, $period->getEndDate()); } - /** - * @param DatePeriod $period The date period to verify - * @param string $format Format used to format the date - * - * @dataProvider provideDatePeriodAndIncorrectDateFormat - */ - public function testGetFormattedDateUsingIncorrectDateFormat(DatePeriod $period, $format): void - { - self::assertEquals('', $period->getFormattedDate($format)); - } - - /** - * @param DatePeriod $period The date period to verify - * @param string $format Format used to format the date - * @param bool $startDate If is set to true, start date is formatted. Otherwise - end date. - * - * @dataProvider provideDatePeriodAndUnknownDate - */ - public function testGetFormattedDateUsingUnknownDate(DatePeriod $period, $format, $startDate): void - { - self::assertEquals('', $period->getFormattedDate($format, $startDate)); - } - - /** - * @param DatePeriod $period The date period to verify - * @param string $format Format used to format the date - * @param string $expected Expected, formatted date - * - * @dataProvider provideDatePeriodAndDateFormatUsingStartDateOnly - */ - public function testGetFormattedDateUsingStartDateOnly(DatePeriod $period, $format, $expected): void - { - self::assertEquals($expected, $period->getFormattedDate($format)); - } - - /** - * @param DatePeriod $period The date period to verify - * @param string $format Format used to format the date - * @param bool $startDate If is set to true, start date is formatted. Otherwise - end date. - * @param string $expected Expected, formatted date - * - * @dataProvider provideDatePeriodAndDateFormat - */ - public function testGetFormattedDate(DatePeriod $period, $format, $startDate, $expected): void - { - self::assertEquals($expected, $period->getFormattedDate($format, $startDate)); - } - - /** - * Provides the start and end date of date period - * - * @return Generator - */ - public function provideDatePeriod(): Generator - { - $startDate = new DateTime('2001-01-01'); - $endDate = new DateTime('2002-02-02'); - - yield[ - null, - null, - ]; - - yield[ - $startDate, - $startDate, - null, - ]; - - yield[ - null, - null, - $endDate, - ]; - - yield[ - $startDate, - $endDate, - ]; - } - - /** - * Provides period and incorrect format of date to verify - * - * @return Generator - */ - public function provideDatePeriodAndIncorrectDateFormat(): Generator - { - $startDate = new DateTime('2001-01-01'); - $endDate = new DateTime('2002-02-02'); - - yield[ - new DatePeriod($startDate, $endDate), - '', - ]; - - yield[ - new DatePeriod($startDate, $endDate), - false, - ]; - } - - public function provideDatePeriodAndUnknownDate(): ?Generator - { - $date = new DateTime('2001-01-01'); - - yield[ - new DatePeriod(), - 'Y-m-d', - false, - ]; - - yield[ - new DatePeriod(), - 'Y-m-d', - true, - ]; - - yield[ - new DatePeriod($date), - 'Y-m-d', - false, - ]; - - yield[ - new DatePeriod(null, $date), - 'Y-m-d', - true, - ]; - } - - /** - * Provides period and format of date to verify using the start date - * - * @return Generator - */ - public function provideDatePeriodAndDateFormatUsingStartDateOnly(): Generator - { - $startDate = new DateTime('2001-01-01'); - $endDate = new DateTime('2002-02-02'); - - yield[ - new DatePeriod($startDate, $endDate), - 'Y', - '2001', - ]; - - yield[ - new DatePeriod($startDate, $endDate), - 'D', - 'Mon', - ]; - - yield[ - new DatePeriod($startDate, $endDate), - 'Y-m-d', - '2001-01-01', - ]; - - yield[ - new DatePeriod($startDate, $endDate), - 'Y-m-d H:i', - '2001-01-01 00:00', - ]; - } - - /** - * Provides period and format of date to verify - * - * @return Generator - */ - public function provideDatePeriodAndDateFormat(): Generator - { - $startDate = new DateTime('2001-01-01'); - $endDate = new DateTime('2002-02-02'); - - // For start date - yield[ - new DatePeriod($startDate, $endDate), - 'Y', - true, - '2001', - ]; - - yield[ - new DatePeriod($startDate, $endDate), - 'D', - true, - 'Mon', - ]; - - yield[ - new DatePeriod($startDate, $endDate), - 'Y-m-d', - true, - '2001-01-01', - ]; - - yield[ - new DatePeriod($startDate, $endDate), - 'Y-m-d H:i', - true, - '2001-01-01 00:00', - ]; - - // For end date - yield[ - new DatePeriod($startDate, $endDate), - 'Y', - false, - '2002', - ]; - - yield[ - new DatePeriod($startDate, $endDate), - 'D', - false, - 'Sat', - ]; - - yield[ - new DatePeriod($startDate, $endDate), - 'Y-m-d', - false, - '2002-02-02', - ]; - - yield[ - new DatePeriod($startDate, $endDate), - 'Y-m-d H:i', - false, - '2002-02-02 00:00', - ]; - } - - /** - * {@inheritdoc} - */ - public function provideTypeToVerify(): Generator - { - yield[ - DatePeriod::isCorrectType(''), - false, - ]; - - yield[ - DatePeriod::isCorrectType('-1'), - false, - ]; - - yield[ - DatePeriod::isCorrectType('4'), - true, - ]; - - yield[ - DatePeriod::isCorrectType('3'), - true, - ]; - - yield[ - DatePeriod::isCorrectType('8'), - true, - ]; - } - /** * Returns all expected types of the tested type * @@ -341,14 +341,14 @@ class DatePeriodTest extends BaseTypeTestCase { return [ 'LAST_MONTH' => 4, - 'LAST_WEEK' => 1, - 'LAST_YEAR' => 7, + 'LAST_WEEK' => 1, + 'LAST_YEAR' => 7, 'NEXT_MONTH' => 6, - 'NEXT_WEEK' => 3, - 'NEXT_YEAR' => 9, + 'NEXT_WEEK' => 3, + 'NEXT_YEAR' => 9, 'THIS_MONTH' => 5, - 'THIS_WEEK' => 2, - 'THIS_YEAR' => 8, + 'THIS_WEEK' => 2, + 'THIS_YEAR' => 8, ]; } diff --git a/tests/Type/OopVisibilityTypeTest.php b/tests/Type/OopVisibilityTypeTest.php index 2f858cd..cc929c3 100644 --- a/tests/Type/OopVisibilityTypeTest.php +++ b/tests/Type/OopVisibilityTypeTest.php @@ -29,32 +29,32 @@ class OopVisibilityTypeTest extends BaseTypeTestCase */ public function provideTypeToVerify(): Generator { - yield[ + yield [ OopVisibilityType::isCorrectType(''), false, ]; - yield[ + yield [ OopVisibilityType::isCorrectType(null), false, ]; - yield[ + yield [ OopVisibilityType::isCorrectType('-1'), false, ]; - yield[ + yield [ OopVisibilityType::isCorrectType('1'), true, ]; - yield[ + yield [ OopVisibilityType::isCorrectType('2'), true, ]; - yield[ + yield [ OopVisibilityType::isCorrectType('3'), true, ]; @@ -66,9 +66,9 @@ class OopVisibilityTypeTest extends BaseTypeTestCase protected function getAllExpectedTypes(): array { return [ - 'IS_PRIVATE' => 3, + 'IS_PRIVATE' => 3, 'IS_PROTECTED' => 2, - 'IS_PUBLIC' => 1, + 'IS_PUBLIC' => 1, ]; } diff --git a/tests/Utilities/ArraysTest.php b/tests/Utilities/ArraysTest.php index 1c2d442..e119f82 100644 --- a/tests/Utilities/ArraysTest.php +++ b/tests/Utilities/ArraysTest.php @@ -31,271 +31,2312 @@ class ArraysTest extends BaseTestCase private $complexArray; private $superComplexArray; - public function testConstructor() + public function provideArrayToQuoteStrings() { - static::assertHasNoConstructor(Arrays::class); + yield [ + 'An empty array', + null, + [], + ]; + + yield [ + 'Simple array', + [ + 1, + 2, + 3, + '\'1\'', + '\'2\'', + ], + [ + 1, + 2, + 3, + '1', + '2', + ], + ]; + + yield [ + 'Complex array', + [ + 123, + '\'456\'', + [ + 'x' => [ + 0, + '\'0\'', + 1 => '\'1\'', + 2 => 2, + ], + '\'y\'', + ], + 444 => '\'\'', + [ + [ + [ + '\'test\'', + ], + ], + ], + ], + [ + 123, + '456', + [ + 'x' => [ + 0, + '0', + 1 => '1', + 2 => 2, + ], + 'y', + ], + 444 => '', + [ + [ + [ + 'test', + ], + ], + ], + ], + ]; + } + + public function provideArrayToRemoveMarginalElement(): Generator + { + yield [ + 'An empty array - remove last element', + [], + true, + null, + ]; + + yield [ + 'An empty array - remove first element', + [], + false, + null, + ]; + + yield [ + 'One-dimensional array - remove last element', + [ + 'Lorem', + 'ipsum', + 'dolor', + 'sit', + 'amet', + ], + true, + [ + 0 => 'Lorem', + 1 => 'ipsum', + 2 => 'dolor', + 3 => 'sit', + ], + ]; + + yield [ + 'One-dimensional array - remove first element', + [ + 'Lorem', + 'ipsum', + 'dolor', + 'sit', + 'amet', + ], + false, + [ + 1 => 'ipsum', + 2 => 'dolor', + 3 => 'sit', + 4 => 'amet', + ], + ]; + + yield [ + 'Multi-dimensional array - remove last element', + [ + 'lorem' => [ + 'ipsum' => [ + 'dolor' => 'sit', + 'diam' => [ + 'non' => 'egestas', + ], + ], + ], + 'consectetur' => 'adipiscing', + 'mollis' => 1234, + 2 => [], + 'sit' => [ + 'nullam' => 'donec', + 'aliquet' => [ + 'vitae' => [ + 'ligula' => 'quis', + ], + ], + 'elit', + ], + 'amet' => [ + 'iaculis', + 'primis', + ], + ], + true, + [ + 'lorem' => [ + 'ipsum' => [ + 'dolor' => 'sit', + 'diam' => [ + 'non' => 'egestas', + ], + ], + ], + 'consectetur' => 'adipiscing', + 'mollis' => 1234, + 2 => [], + 'sit' => [ + 'nullam' => 'donec', + 'aliquet' => [ + 'vitae' => [ + 'ligula' => 'quis', + ], + ], + 'elit', + ], + ], + ]; + + yield [ + 'Multi-dimensional array - remove first element', + [ + 'lorem' => [ + 'ipsum' => [ + 'dolor' => 'sit', + 'diam' => [ + 'non' => 'egestas', + ], + ], + ], + 'consectetur' => 'adipiscing', + 'mollis' => 1234, + 2 => [], + 'sit' => [ + 'nullam' => 'donec', + 'aliquet' => [ + 'vitae' => [ + 'ligula' => 'quis', + ], + ], + 'elit', + ], + 'amet' => [ + 'iaculis', + 'primis', + ], + ], + false, + [ + 'consectetur' => 'adipiscing', + 'mollis' => 1234, + 2 => [], + 'sit' => [ + 'nullam' => 'donec', + 'aliquet' => [ + 'vitae' => [ + 'ligula' => 'quis', + ], + ], + 'elit', + ], + 'amet' => [ + 'iaculis', + 'primis', + ], + ], + ]; + } + + public function provideArrayToReplaceKeys(): Generator + { + yield [ + 'An empty array', + [], + '', + '', + null, + ]; + + yield [ + '1st case', + [ + 'nullam' => 'donec', + 'aliquet' => [ + 'vitae' => [ + 'ligula' => 'quis', + ], + ], + 'elit', + ], + '|.*li.*|', + 'x', + [ + 'nullam' => 'donec', + 'x' => [ + 'vitae' => [ + 'x' => 'quis', + ], + ], + 'elit', + ], + ]; + + yield [ + '2nd case', + [ + 'Lorem', + 'ipsum', + 'dolor', + 'sit', + 'amet', + ], + '|[0-3]+|', + 'x', + [ + 'x' => 'sit', + 4 => 'amet', + ], + ]; + } + + public function provideArrayToVerifyIfContainsEmptyStringsOnly(): ?Generator + { + yield [ + [], + false, + ]; + + yield [ + [ + '', + 1, + ], + false, + ]; + + yield [ + [ + '', + null, + 1, + ], + false, + ]; + + yield [ + [ + '', + null, + ], + true, + ]; + + yield [ + [ + '', + null, + '', + ], + true, + ]; + } + + public function provideArrayValues2csv(): ?Generator + { + yield [ + 'An empty array', + null, + [], + ]; + + yield [ + 'Empty string, and empty array and null as row', + "1,2,3\n5,6,", + [ + 'test_1' => '', + 'test_2' => [], + 'test_3' => null, + 'test_4' => [ + 'aa' => 1, + 'bb' => 2, + 'cc' => 3, + ], + [ + 'dd' => 5, + 'ee' => 6, + 'ff' => '', + ], + ], + ]; + + yield [ + 'Empty string, and empty array and null as row (with custom separator)', + "1, 2, 3\n5, 6, ", + [ + 'test_1' => '', + 'test_2' => [], + 'test_3' => null, + 'test_4' => [ + 'aa' => 1, + 'bb' => 2, + 'cc' => 3, + ], + [ + 'dd' => 5, + 'ee' => 6, + 'ff' => '', + ], + ], + ', ', + ]; + + yield [ + 'Empty string as key, non-array as value', + "1,2,3\n5,6,", + [ + '' => 'test_1', + 1 => 'test_2', + '3' => [ + 'aa' => 1, + 'bb' => 2, + 'cc' => 3, + ], + [ + 'dd' => 5, + 'ee' => 6, + 'ff' => '', + ], + ], + ]; + + yield [ + 'Empty string as key, non-array as value (with custom separator)', + "1 | 2 | 3\n5 | 6 | ", + [ + '' => 'test_1', + 1 => 'test_2', + '3' => [ + 'aa' => 1, + 'bb' => 2, + 'cc' => 3, + ], + [ + 'dd' => 5, + 'ee' => 6, + 'ff' => '', + ], + ], + ' | ', + ]; + + yield [ + 'Invalid structure, not like database table', + "1,2,3\n5,6\n7,8,9,10", + [ + [ + 'aa' => 1, + 'bb' => 2, + 'cc' => 3, + ], + [ + 'dd' => 5, + 'ee' => 6, + ], + [ + 7, + 8, + 9, + 10, + ], + ], + ]; + + yield [ + 'Invalid structure, not like database table (with custom separator)', + "1 <-> 2 <-> 3\n5 <-> 6\n7 <-> 8 <-> 9 <-> 10", + [ + [ + 'aa' => 1, + 'bb' => 2, + 'cc' => 3, + ], + [ + 'dd' => 5, + 'ee' => 6, + ], + [ + 7, + 8, + 9, + 10, + ], + ], + ' <-> ', + ]; + + yield [ + 'Mixed types of keys and values', + "1,2,3.45\n5,6,\n7,8,9,,10", + [ + [ + 'aa' => 1, + 'bb' => 2, + 'cc' => 3.45, + ], + [ + 'dd' => 5, + 'ee' => 6, + null, + ], + [ + 7, + 8, + 'qq' => 9, + '', + 10, + ], + ], + ]; + + yield [ + 'Mixed types of keys and values (with custom separator)', + "1 // 2 // 3.45\n5 // 6 // \n7 // 8 // 9 // // 10", + [ + [ + 'aa' => 1, + 'bb' => 2, + 'cc' => 3.45, + ], + [ + 'dd' => 5, + 'ee' => 6, + null, + ], + [ + 7, + 8, + 'qq' => 9, + '', + 10, + ], + ], + ' // ', + ]; + + yield [ + 'With HTML code', + "
abc
,def,
ghi
\nc,d", + [ + [ + '<div>abc</div>', + 'def', + '<div>ghi</div>', + ], + [ + 'c', + 'd', + ], + ], + ]; + } + + public function provideArrayValues2string() + { + yield [ + 'An empty array', + null, + [], + ]; + + yield [ + 'Simple array', + 'Test 1,Test 2,Test 3', + [ + 1 => 'Test 1', + 2 => 'Test 2', + 3 => 'Test 3', + ], + ]; + + yield [ + 'Simple array (with custom separator)', + 'Test 1.Test 2.Test 3', + [ + 1 => 'Test 1', + 2 => 'Test 2', + 3 => 'Test 3', + ], + '', + '.', + ]; + + yield [ + 'Simple array (concrete column)', + 'Test 2', + [ + 1 => 'Test 1', + 2 => 'Test 2', + 3 => 'Test 3', + ], + 2, + ]; + + yield [ + 'Simple array (concrete column with custom separator)', + 'Test 2', + [ + 1 => 'Test 1', + 2 => 'Test 2', + 3 => 'Test 3', + ], + 2, + '.', + ]; + + yield [ + 'Complex array', + '1,2,3,test 1,test 2,test 3,,test 4,,bbb,3.45', + [ + [ + 1, + 2, + 3, + ], + [ + 'test 1', + 'test 2', + [ + 'test 3', + '', + 'test 4', + ], + ], + [], + [ + 'a' => '', + 'b' => 'bbb', + [], + 'c' => 3.45, + ], + ], + ]; + + yield [ + '1st complex array (concrete column)', + '2,test 2,', + [ + [ + 1, + 2, + 3, + ], + [ + 'test 1', + 'test 2', + [ + 'test 3', + '', + 'test 4', + ], + ], + [], + [ + 'a' => '', + 'b' => 'bbb', + [], + 'c' => 3.45, + ], + ], + 1, + ]; + + yield [ + '2nd complex array (concrete column)', + 'bb,1234,0xb', + [ + [ + 1, + 2, + 3, + ], + [ + 'a' => 'aa', + 'b' => 'bb', + 'c' => 'cc', + ], + [ + 'a', + 'b', + 'c', + ], + [ + 'a' => '', + 'b' => 1234, + ], + [ + 'c' => 5678, + 'b' => '0xb', + ], + ], + 'b', + ]; + + yield [ + '3rd complex array (concrete column with custom separator)', + 'bb - 1234 - 3xb - bbb', + [ + [ + 1, + 2, + 3, + ], + [ + 'a' => 'aa', + 'b' => 'bb', + 'c' => 'cc', + ], + [ + 'a', + 'b' => [], + 'c', + ], + [ + 'a' => '', + 'b' => 1234, + ], + [ + 'c' => 5678, + 'b' => [ + 'b1' => '0xb', + 'b2' => '1xb', + 'b' => '3xb', + ], + [ + 1, + 2, + 'a' => 'aaa', + 'b' => 'bbb', + ], + ], + ], + 'b', + ' - ', + ]; + } + + public function provideArrayValuesKeysConverted2string() + { + yield [ + 'An empty array', + null, + [], + ]; + + yield [ + 'Empty string and null as value', + 'test_1=,test_2=,test_3=3', + [ + 'test_1' => null, + 'test_2' => '', + 'test_3' => '3', + ], + ]; + + yield [ + 'Empty string and null as value (with custom separators)', + 'test_1="" test_2="" test_3="3"', + [ + 'test_1' => null, + 'test_2' => '', + 'test_3' => '3', + ], + ' ', + '=', + '"', + ]; + + yield [ + 'Empty string as key', + '1=test_1,=test_2,3=test_3', + [ + 1 => 'test_1', + '' => 'test_2', + '3' => 'test_3', + ], + ]; + + yield [ + 'Empty string as key (with custom separators)', + '1 => "test_1"; => "test_2"; 3 => "test_3"', + [ + 1 => 'test_1', + '' => 'test_2', + '3' => 'test_3', + ], + '; ', + ' => ', + '"', + ]; + + yield [ + 'Mixed types of keys and values', + 'test_1=test test,test_2=2,test_3=3.45', + [ + 'test_1' => 'test test', + 'test_2' => 2, + 'test_3' => 3.45, + ], + ]; + + yield [ + 'Mixed types of keys and values (with custom separators)', + 'test_1 --> *test test* | test_2 --> *2* | test_3 --> *3.45*', + [ + 'test_1' => 'test test', + 'test_2' => 2, + 'test_3' => 3.45, + ], + ' | ', + ' --> ', + '*', + ]; } /** - * @param string $description Description of test - * @param string $expected Expected array converted to string - * @param array $array Data to be converted - * @param string $arrayColumnKey (optional) Column name. Default: "". - * @param string $separator (optional) Separator used between values. Default: ",". + * Provides an array with duplicated values to set/replace values with keys * - * @dataProvider provideArrayValues2string + * @return Generator */ - public function testValues2string($description, $expected, array $array, $arrayColumnKey = '', $separator = ',') + public function provideArrayWithDuplicatedValuesToSetKeysAsValues() { - // Required to avoid failure: - // - // Failed asserting that two strings are identical - // 1,2,3,test 1,test 2,test 3,,test 4,,bbb,3.45 - expected - // 1,2,3,test 1,test 2,test 3,,test 4,,bbb,3,45 - actual - Locale::setLocale(LC_ALL, 'en', 'US'); + yield [ + [ + 'lorem' => 'ipsum', + 'dolor' => 'ipsum', + 'sit' => 'amet', + 'diam' => 'non', + 'elit' => 'non', + 'in' => 'non', + ], + [ + 'ipsum' => [ + 'lorem', + 'dolor', + ], + 'amet' => 'sit', + 'non' => [ + 'diam', + 'elit', + 'in', + ], + ], + ]; - self::assertSame($expected, Arrays::values2string($array, $arrayColumnKey, $separator), $description); + yield [ + [ + 'lorem' => [ + 'diam' => 'non', + 'elit' => 'non', + 'in' => 'non', + ], + 'dolor1' => 'ipsum', + 'dolor2' => 'ipsum', + 'sit' => 'amet', + ], + [ + 'lorem' => [ + 'non' => [ + 'diam', + 'elit', + 'in', + ], + ], + 'ipsum' => [ + 'dolor1', + 'dolor2', + ], + 'amet' => 'sit', + ], + ]; + } + + public function provideFirstElement(): ?Generator + { + yield [ + 'An empty array (first level only)', + null, + [], + ]; + + yield [ + 'An empty array', + null, + [], + false, + ]; + + yield [ + 'Multidimensional array (first level only)', + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + ]; + + yield [ + 'Multidimensional array', + 'abc', + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + false, + ]; + } + + public function provideIsFirstElement(): ?Generator + { + yield [ + 'An empty array (first level only)', + false, + [], + '', + ]; + + yield [ + 'An empty array', + false, + [], + '', + false, + ]; + + yield [ + 'Non-existing integer in array with integers (first level only)', + false, + [ + 1, + 2, + 3, + ], + 4, + ]; + + yield [ + 'Existing integer in array with integers (first level only)', + true, + [ + 1, + 2, + 3, + ], + 1, + ]; + + yield [ + 'Existing integer in array with integers', + true, + [ + 1, + 2, + 3, + ], + 1, + false, + ]; + + yield [ + 'Non-existing integer in multidimensional array with integers (first level only)', + false, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 9, + ]; + + yield [ + 'Non-existing integer in multidimensional array with integers', + false, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 9, + false, + ]; + + yield [ + 'Existing integer in multidimensional array with integers, but first level only checked', + false, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 1, + ]; + + yield [ + 'Existing integer in multidimensional array with integers', + true, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 1, + false, + ]; + + yield [ + 'Non-existing element in multidimensional array (first level only)', + false, + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + 9, + ]; + + yield [ + 'Existing element in multidimensional array, but first level only checked', + false, + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + 'abc', + ]; + + yield [ + 'Existing element in multidimensional array', + true, + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + 'abc', + false, + ]; + } + + public function provideIsLastElement(): ?Generator + { + yield [ + 'An empty array (first level only)', + false, + [], + '', + ]; + + yield [ + 'An empty array', + false, + [], + '', + false, + ]; + + yield [ + 'Non-existing integer in array with integers (first level only)', + false, + [ + 1, + 2, + 3, + ], + 4, + ]; + + yield [ + 'Existing integer in array with integers (first level only)', + true, + [ + 1, + 2, + 3, + ], + 3, + ]; + + yield [ + 'Existing integer in array with integers', + true, + [ + 1, + 2, + 3, + ], + 3, + false, + ]; + + yield [ + 'Non-existing integer in multidimensional array with integers (first level only)', + false, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 11, + ]; + + yield [ + 'Non-existing integer in multidimensional array with integers', + false, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 11, + false, + ]; + + yield [ + 'Existing integer in multidimensional array with integers, but first level only checked', + false, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 10, + ]; + + yield [ + 'Existing integer in multidimensional array with integers', + true, + [ + [ + [ + 1, + 2, + 3, + ], + 4, + ], + 5, + [ + 6, + 7, + [ + 8, + 9, + 10, + ], + ], + ], + 10, + false, + ]; + + yield [ + 'Non-existing element in multidimensional array (first level only)', + false, + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + 9, + ]; + + yield [ + 'Existing element in multidimensional array, but first level only checked', + false, + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 10, + '...', + 'jkl', + ], + ], + ], + 'jkl', + ]; + + yield [ + 'Existing element in multidimensional array', + true, + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 10, + '...', + 'jkl', + ], + ], + ], + 'jkl', + false, + ]; + } + + public function provideLastElement(): ?Generator + { + yield [ + 'An empty array (first level only)', + null, + [], + ]; + + yield [ + 'An empty array', + null, + [], + false, + ]; + + yield [ + 'One-dimensional array (first level only)', + 3, + [ + 1, + 2, + 3, + ], + ]; + + yield [ + 'One-dimensional array (first level only)', + 3, + [ + 1, + 2, + 3, + ], + false, + ]; + + yield [ + 'Multidimensional array (first level only)', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + ]; + + yield [ + 'Multidimensional array', + 10, + [ + [ + [ + 'abc', + 2, + 'def', + ], + 4, + ], + '---', + [ + 'ghi', + 7, + [ + 'jkl', + '...', + 10, + ], + ], + ], + false, + ]; + } + + public function provideLastRow(): ?Generator + { + yield [ + 'An empty array', + null, + [], + ]; + + yield [ + 'One-dimensional array', + [], + [ + 'a', + 'b', + 1, + 2, + ], + ]; + + yield [ + 'Multidimensional array with scalar as last element', + [], + [ + 'a', + [ + 'b', + 'c', + ], + [ + 'e', + 'f', + ], + 1, + 2, + ], + ]; + + yield [ + 'Multidimensional array with an empty array as last element', + [], + [ + 'a', + [ + 'b', + 'c', + ], + 1, + 2, + [], + ], + ]; + + yield [ + 'Multidimensional array', + [ + 'e', + 'f', + ], + [ + 'a', + [ + 'b', + 'c', + ], + 1, + 2, + [ + 'e', + 'f', + ], + ], + ]; } /** - * @param string $description Description of test - * @param string $expected Expected array converted to string - * @param array $array Data to be converted - * @param string $separator (optional) Separator used between name-value pairs. Default: ",". - * @param string $valuesKeysSeparator (optional) Separator used between name and value. Default: "=". - * @param string $valuesWrapper (optional) Wrapper used to wrap values, e.g. double-quote: key="value". - * Default: "". + * Provides simple array to set/replace values with keys * - * @dataProvider provideArrayValuesKeysConverted2string + * @return Generator */ - public function testValuesKeys2string( - $description, - $expected, - array $array, - $separator = ',', - $valuesKeysSeparator = '=', - $valuesWrapper = '' - ) { - // Required to avoid failure: - // - // Failed asserting that two strings are identical - // test_1=test test,test_2=2,test_3=3.45 - expected - // test_1=test test,test_2=2,test_3=3,45 - actual - Locale::setLocale(LC_ALL, 'en', 'US'); + public function provideSimpleArrayToSetKeysAsValues() + { + yield [ + [ + 1, + 2, + 3, + 4, + ], + [ + 1 => 0, + 2 => 1, + 3 => 2, + 4 => 3, + ], + ]; - self::assertSame( - $expected, - Arrays::valuesKeys2string($array, $separator, $valuesKeysSeparator, $valuesWrapper), - $description - ); - - self::assertSame( - '0=Lorem,1=ipsum,2=dolor,3=sit,4=amet', - Arrays::valuesKeys2string($this->simpleArray), - 'Simple array' - ); - - self::assertSame( - '0=Lorem;1=ipsum;2=dolor;3=sit;4=amet', - Arrays::valuesKeys2string($this->simpleArray, ';'), - 'Simple array (with custom separator)' - ); - - self::assertSame( - '0=Lorem 1=ipsum 2=dolor 3=sit 4=amet', - Arrays::valuesKeys2string($this->simpleArray, ' '), - 'Simple array (with custom separator)' - ); - - self::assertSame( - '0="Lorem" 1="ipsum" 2="dolor" 3="sit" 4="amet"', - Arrays::valuesKeys2string($this->simpleArray, ' ', '=', '"'), - 'Simple array (with custom separators)' - ); - - self::assertSame( - '0="Lorem", 1="ipsum", 2="dolor", 3="sit", 4="amet"', - Arrays::valuesKeys2string($this->simpleArray, ', ', '=', '"'), - 'Simple array (with custom separators)' - ); + yield [ + [ + 'Lorem', + 'ipsum', + 'dolor', + 'sit', + 'amet', + ], + [ + 'Lorem' => 0, + 'ipsum' => 1, + 'dolor' => 2, + 'sit' => 3, + 'amet' => 4, + ], + ]; } /** - * @param string $description Description of test - * @param string $expected Expected array converted to csv string - * @param array $array Data to be converted. It have to be an array that represents database table. - * @param string $separator (optional) Separator used between values. Default: ",". + * Provides patterns of keys or paths that matched will stop the process and the expected array for the + * getLastElementsPaths() method * - * @dataProvider provideArrayValues2csv + * @return Generator */ - public function testValues2csv(string $description, ?string $expected, array $array, string $separator = ','): void + public function provideStopIfMatchedByForGetLastElementsPaths(): ?Generator { - // Required to avoid failure: - // - // Failed asserting that two strings are identical - // 1,2,3.45 - expected - // 1,2,3,45 - actual - Locale::setLocale(LC_ALL, 'en', 'US'); + // Special exception: do not use, stop recursive on the "diam" key + yield [ + ['diam'], + '.', + [ + 'ipsum.quis.vestibulum.porta-1.0' => 'turpis', + 'ipsum.quis.vestibulum.porta-1.1' => 'urna', + 'ipsum.quis.vestibulum.porta-2.tortor.in.0' => 'dui', + 'ipsum.quis.vestibulum.porta-2.tortor.in.dolor.0' => 'aliquam', + 'ipsum.quis.vestibulum.porta-3.0' => 1, + 'ipsum.quis.vestibulum.porta-3.1' => 2, + 'ipsum.quis.vestibulum.porta-3.2' => 3, + 'primis.0.0' => 'in', + 'primis.0.1' => 'faucibus', + 'primis.0.2' => 'orci', + 'primis.1.0' => 'luctus', + 'primis.1.1' => 'et', + 'primis.1.2' => 'ultrices', + ], + ]; - static::assertSame($expected, Arrays::values2csv($array, $separator), $description); + /* + * Stop building of paths on these keys: + * - "tortor" + * - "primis" + */ + yield [ + [ + 'tortor', + 'primis', + ], + ' . ', + [ + 'ipsum . quis . vestibulum . porta-1 . 0' => 'turpis', + 'ipsum . quis . vestibulum . porta-1 . 1' => 'urna', + 'ipsum . quis . vestibulum . porta-2 . tortor' => [ + 'in' => [ + 'dui', + 'dolor' => [ + 'aliquam', + ], + ], + ], + 'ipsum . quis . vestibulum . porta-3 . 0' => 1, + 'ipsum . quis . vestibulum . porta-3 . 1' => 2, + 'ipsum . quis . vestibulum . porta-3 . 2' => 3, + 'primis' => [ + [ + 'in', + 'faucibus', + 'orci', + ], + [ + 'luctus', + 'et', + 'ultrices', + ], + ], + ], + ]; + + // Stop building of paths on more sophisticated keys + yield [ + [ + 'porta\-\d+', + '^\d+$', + ], + ' > ', + [ + 'ipsum > quis > vestibulum > porta-1' => [ + 'turpis', + 'urna', + ], + 'ipsum > quis > vestibulum > porta-2' => [ + 'tortor' => [ + 'in' => [ + 'dui', + 'dolor' => [ + 'aliquam', + ], + ], + ], + ], + 'ipsum > quis > vestibulum > porta-3' => [ + 1, + 2, + 3, + ], + 'primis > 0' => [ + 'in', + 'faucibus', + 'orci', + ], + 'primis > 1' => [ + 'luctus', + 'et', + 'ultrices', + ], + ], + ]; + + /* + * Stop building of paths on these: + * - keys + * and + * - paths (verify paths too) + */ + yield [ + [ + 'porta-1', + 'porta-2 > tortor > in', + ], + ' > ', + [ + 'ipsum > quis > vestibulum > porta-1' => [ + 'turpis', + 'urna', + ], + 'ipsum > quis > vestibulum > porta-2 > tortor > in' => [ + 'dui', + 'dolor' => [ + 'aliquam', + ], + ], + 'ipsum > quis > vestibulum > porta-3 > 0' => 1, + 'ipsum > quis > vestibulum > porta-3 > 1' => 2, + 'ipsum > quis > vestibulum > porta-3 > 2' => 3, + 'primis > 0 > 0' => 'in', + 'primis > 0 > 1' => 'faucibus', + 'primis > 0 > 2' => 'orci', + 'primis > 1 > 0' => 'luctus', + 'primis > 1 > 1' => 'et', + 'primis > 1 > 2' => 'ultrices', + ], + ]; + + // Stop building of paths on these paths (verify paths only) + yield [ + [ + 'ipsum > quis > vestibulum > porta-1', + 'ipsum > quis > vestibulum > porta-2 > tortor', + 'primis > 1', + ], + ' > ', + [ + 'ipsum > quis > vestibulum > porta-1' => [ + 'turpis', + 'urna', + ], + 'ipsum > quis > vestibulum > porta-2 > tortor' => [ + 'in' => [ + 'dui', + 'dolor' => [ + 'aliquam', + ], + ], + ], + 'ipsum > quis > vestibulum > porta-3 > 0' => 1, + 'ipsum > quis > vestibulum > porta-3 > 1' => 2, + 'ipsum > quis > vestibulum > porta-3 > 2' => 3, + 'primis > 0 > 0' => 'in', + 'primis > 0 > 1' => 'faucibus', + 'primis > 0 > 2' => 'orci', + 'primis > 1' => [ + 'luctus', + 'et', + 'ultrices', + ], + ], + ]; + + // Stop building of paths if path contains any of these part (verify part of paths only) + yield [ + [ + 'vestibulum > porta-1', + 'tortor > in', + '[a-z]+ > \d+', + ], + ' > ', + [ + 'ipsum > quis > vestibulum > porta-1' => [ + 'turpis', + 'urna', + ], + 'ipsum > quis > vestibulum > porta-2 > tortor > in' => [ + 'dui', + 'dolor' => [ + 'aliquam', + ], + ], + 'ipsum > quis > vestibulum > porta-3 > 0' => 1, + 'ipsum > quis > vestibulum > porta-3 > 1' => 2, + 'ipsum > quis > vestibulum > porta-3 > 2' => 3, + 'primis > 0' => [ + 'in', + 'faucibus', + 'orci', + ], + 'primis > 1' => [ + 'luctus', + 'et', + 'ultrices', + ], + ], + ]; } - public function testGetFirstKey() + public function provideValueToIsEmptyArray(): ?Generator + { + yield [ + 'An empty string', + '', + false, + ]; + + yield [ + 'Non-empty string', + 'test', + false, + ]; + + yield [ + 'Null', + null, + false, + ]; + + yield [ + 'An integer equals 0', + 1234, + false, + ]; + + yield [ + 'An integer greater than 0', + 1234, + false, + ]; + + yield [ + 'An empty array', + [], + true, + ]; + + yield [ + 'Non-empty array', + [ + 'test', + ], + false, + ]; + } + + public function provideValueToIsNotEmptyArray(): ?Generator + { + yield [ + 'An empty string', + '', + false, + ]; + + yield [ + 'Non-empty string', + 'test', + false, + ]; + + yield [ + 'Null', + null, + false, + ]; + + yield [ + 'An integer equals 0', + 1234, + false, + ]; + + yield [ + 'An integer greater than 0', + 1234, + false, + ]; + + yield [ + 'An empty array', + [], + false, + ]; + + yield [ + 'Non-empty array', + [ + 'test', + ], + true, + ]; + } + + /** + * Provide values to filter and get non-empty values + * + * @return Generator + */ + public function provideValuesToFilterNonEmpty(): ?Generator + { + $simpleObject = new SimpleToString('1234'); + + yield [ + 'All values are empty', + [ + '', + null, + [], + ], + [], + ]; + + yield [ + '5 values with 2 empty strings', + [ + 'test 1', + '', + 'test 2', + 'test 3', + '', + ], + [ + 0 => 'test 1', + 2 => 'test 2', + 3 => 'test 3', + ], + ]; + + yield [ + '"0" shouldn\'t be treated like an empty value', + [ + 123, + 0, + 456, + ], + [ + 123, + 0, + 456, + ], + ]; + + yield [ + 'Object shouldn\'t be treated like an empty value', + [ + 'test 1', + $simpleObject, + 'test 2', + null, + 'test 3', + ], + [ + 0 => 'test 1', + 1 => $simpleObject, + 2 => 'test 2', + 4 => 'test 3', + ], + ]; + + yield [ + 'Mixed values (non-empty, empty, strings, integers, objects)', + [ + 'test 1', + '', + 123, + null, + 'test 2', + 'test 3', + 0, + $simpleObject, + 456, + [], + $simpleObject, + ], + [ + 0 => 'test 1', + 2 => 123, + 4 => 'test 2', + 5 => 'test 3', + 6 => 0, + 7 => $simpleObject, + 8 => 456, + 10 => $simpleObject, + ], + ]; + } + + /** + * Provide values to filter and get non-empty values concatenated by given separator + * + * @return Generator + */ + public function provideValuesToFilterNonEmptyAsString() + { + yield [ + 'An empty array (no values to filter)', + [], + ' | ', + null, + ]; + + yield [ + 'All values are empty', + [ + '', + null, + [], + ], + ' | ', + '', + ]; + + yield [ + '5 values with 2 empty strings', + [ + 'test 1', + '', + 'test 2', + 'test 3', + '', + ], + ' | ', + 'test 1 | test 2 | test 3', + ]; + + yield [ + 'Numbers with "0" that shouldn\'t be treated like an empty value', + [ + 123, + 0, + 456, + ], + ' <-> ', + '123 <-> 0 <-> 456', + ]; + + yield [ + 'Object shouldn\'t be treated like an empty value', + [ + 'test 1', + new SimpleToString('1234'), + 'test 2', + null, + 'test 3', + ], + ' | ', + 'test 1 | Instance with ID: 1234 | test 2 | test 3', + ]; + + yield [ + 'Mixed values (non-empty, empty, strings, integers, objects)', + [ + 'test 1', + '', + 123, + null, + 'test 2', + 'test 3', + 0, + new SimpleToString('A1XC90Z'), + 456, + [], + new SimpleToString('FF-45-0Z'), + ], + ';', + 'test 1;123;test 2;test 3;0;Instance with ID: A1XC90Z;456;Instance with ID: FF-45-0Z', + ]; + } + + /** + * Provide values to filter and get non-empty values concatenated by default separator + * + * @return Generator + */ + public function provideValuesToFilterNonEmptyAsStringUsingDefaultSeparator() + { + yield [ + 'An empty array (no values to filter)', + [], + null, + ]; + + yield [ + 'All values are empty', + [ + '', + null, + [], + ], + '', + ]; + + yield [ + '5 values with 2 empty strings', + [ + 'test 1', + '', + 'test 2', + 'test 3', + '', + ], + 'test 1, test 2, test 3', + ]; + + yield [ + 'Numbers with "0" that shouldn\'t be treated like an empty value', + [ + 123, + 0, + 456, + ], + '123, 0, 456', + ]; + + yield [ + 'Object shouldn\'t be treated like an empty value', + [ + 'test 1', + new SimpleToString('1234'), + 'test 2', + null, + 'test 3', + ], + 'test 1, Instance with ID: 1234, test 2, test 3', + ]; + + yield [ + 'Mixed values (non-empty, empty, strings, integers, objects)', + [ + 'test 1', + '', + 123, + null, + 'test 2', + 'test 3', + 0, + new SimpleToString('A1XC90Z'), + 456, + [], + new SimpleToString('FF-45-0Z'), + ], + 'test 1, 123, test 2, test 3, 0, Instance with ID: A1XC90Z, 456, Instance with ID: FF-45-0Z', + ]; + } + + public function testAreAllKeysIntegers() + { + self::assertFalse(Arrays::areAllKeysIntegers([])); + self::assertEquals(1, Arrays::areAllKeysIntegers($this->simpleArray)); + self::assertEquals(2, Arrays::areAllKeysIntegers($this->simpleArray)); + self::assertEquals('', Arrays::areAllKeysIntegers($this->complexArray)); + } + + public function testAreAllKeysMatchedByPattern(): void + { + $pattern = '\d+'; + + // Empty array + self::assertFalse(Arrays::areAllKeysMatchedByPattern([], $pattern)); + + // Simple array with integers as keys only + self::assertTrue(Arrays::areAllKeysMatchedByPattern($this->simpleArray, $pattern)); + + // Complex array with strings and integers as keys + self::assertFalse(Arrays::areAllKeysMatchedByPattern($this->complexArray, $pattern)); + + $array = [ + 'a' => 'b', + 'c' => 'd', + ]; + + // Yet another simple array, but with strings as keys + self::assertFalse(Arrays::areAllKeysMatchedByPattern($array, $pattern)); + + // The same array with another pattern + $pattern = '\w+'; + self::assertTrue(Arrays::areAllKeysMatchedByPattern($array, $pattern)); + + // The same array with mixed keys (strings and integers as keys) + $array[1] = 'x'; + $pattern = '\d+'; + self::assertFalse(Arrays::areAllKeysMatchedByPattern($array, $pattern)); + + // Multidimensional array - negative case + $array['e'] = ['f' => 'g']; + self::assertFalse(Arrays::areAllKeysMatchedByPattern($array, $pattern)); + + // Multidimensional array - positive case + unset($array[1]); + $pattern = '\w+'; + self::assertTrue(Arrays::areAllKeysMatchedByPattern($array, $pattern)); + } + + public function testAreAllValuesEmpty() { // Negative cases - self::assertNull(Arrays::getFirstKey([])); + self::assertFalse(Arrays::areAllValuesEmpty([])); + self::assertFalse(Arrays::areAllValuesEmpty([], true)); + self::assertFalse(Arrays::areAllValuesEmpty($this->simpleArray)); + self::assertFalse(Arrays::areAllValuesEmpty($this->simpleArray, true)); + + $array = [ + null, + 0, + ]; + self::assertFalse(Arrays::areAllValuesEmpty($array, true)); + + $array = [ + null, + [ + null, + ], + ]; + self::assertFalse(Arrays::areAllValuesEmpty($array, true)); // Positive cases - self::assertEquals(0, Arrays::getFirstKey($this->simpleArray)); - self::assertEquals('lorem', Arrays::getFirstKey($this->complexArray)); + $array = [ + '', + 0, + ]; + self::assertTrue(Arrays::areAllValuesEmpty($array)); + + $array = [ + null, + null, + ]; + self::assertTrue(Arrays::areAllValuesEmpty($array, true)); } - public function testGetLastKey() + public function testAreKeysInArray(): void { - self::assertNull(Arrays::getLastKey([])); - self::assertEquals(4, Arrays::getLastKey($this->simpleArray)); - self::assertEquals('amet', Arrays::getLastKey($this->complexArray)); - } + // Negative cases + self::assertFalse(Arrays::areKeysInArray([], [])); + self::assertFalse(Arrays::areKeysInArray([null], $this->simpleArray)); + self::assertFalse(Arrays::areKeysInArray([''], $this->simpleArray)); + self::assertFalse(Arrays::areKeysInArray(['dolorrr'], $this->simpleArrayWithKeys)); - /** - * @param string $description - * @param $expected - * @param array $array - * @param null|bool $firstLevelOnly - * - * @dataProvider provideFirstElement - */ - public function testGetFirstElement( - string $description, - $expected, - array $array, - ?bool $firstLevelOnly = null - ): void { - if (null === $firstLevelOnly) { - static::assertSame($expected, Arrays::getFirstElement($array), $description); + $keys1 = [ + 1, + 3, + 9, + ]; - return; - } + self::assertFalse(Arrays::areKeysInArray($keys1, $this->simpleArray)); + self::assertFalse(Arrays::areKeysInArray($keys1, $this->complexArray)); + self::assertFalse(Arrays::areKeysInArray($keys1, $this->complexArray, false)); - static::assertSame($expected, Arrays::getFirstElement($array, $firstLevelOnly), $description); - } + // Positive cases + $keys12 = [ + 2, + 'mollis', + ]; - /** - * @param string $description - * @param bool $expected - * @param array $array - * @param $element - * @param bool $firstLevelOnly - * - * @dataProvider provideIsFirstElement - */ - public function testIsFirstElement( - string $description, - bool $expected, - array $array, - $element, - ?bool $firstLevelOnly = null - ): void { - if (null === $firstLevelOnly) { - static::assertSame($expected, Arrays::isFirstElement($array, $element), $description); + $keys13 = [ + 1, + 3, + ]; - return; - } + $keys14 = [ + 'dolor', + 'amet', + ]; - static::assertSame($expected, Arrays::isFirstElement($array, $element, $firstLevelOnly), $description); - } + $keys15 = [ + 'dolor', + 'amet', + ]; - /** - * @param string $description - * @param $expected - * @param array $array - * @param null|bool $firstLevelOnly - * - * @dataProvider provideLastElement - */ - public function testGetLastElement( - string $description, - $expected, - array $array, - ?bool $firstLevelOnly = null - ): void { - if (null === $firstLevelOnly) { - static::assertSame($expected, Arrays::getLastElement($array), $description); + $keys16 = [ + 'a' => 'lorem', + 11 => 'amet', + ]; - return; - } + $keys17 = [ + 'a' => 'lorem', + 11 => 'amet', + 'c' => 'sit__', + ]; - static::assertSame($expected, Arrays::getLastElement($array, $firstLevelOnly), $description); - } + self::assertTrue(Arrays::areKeysInArray([1], $this->simpleArray)); + self::assertTrue(Arrays::areKeysInArray($keys12, $this->simpleArray, false)); + self::assertTrue(Arrays::areKeysInArray($keys12, $this->complexArray)); + self::assertTrue(Arrays::areKeysInArray($keys13, $this->simpleArray)); + self::assertTrue(Arrays::areKeysInArray($keys14, $this->simpleArrayWithKeys)); + self::assertTrue(Arrays::areKeysInArray($keys15, $this->simpleArrayWithKeys)); - /** - * @param string $description - * @param bool $expected - * @param array $array - * @param $element - * @param null|bool $firstLevelOnly - * - * @dataProvider provideIsLastElement - */ - public function testIsLastElement( - string $description, - bool $expected, - array $array, - $element, - ?bool $firstLevelOnly = null - ): void { - if (null === $firstLevelOnly) { - static::assertSame($expected, Arrays::isLastElement($array, $element), $description); + self::assertTrue(Arrays::areKeysInArray(['a' => 'dolor'], $this->simpleArrayWithKeys)); + self::assertTrue(Arrays::areKeysInArray(['a' => 'dolor'], $this->simpleArrayWithKeys, false)); - return; - } - - static::assertSame($expected, Arrays::isLastElement($array, $element, $firstLevelOnly), $description); - } - - public function testGetLastElementBreadCrumb() - { - self::assertNull(Arrays::getLastElementBreadCrumb([])); - self::assertEquals('4/amet', Arrays::getLastElementBreadCrumb($this->simpleArray)); - self::assertEquals('2/3/eleifend', Arrays::getLastElementBreadCrumb($this->twoDimensionsArray)); - self::assertEquals('amet/1/primis', Arrays::getLastElementBreadCrumb($this->complexArray)); - } - - /** - * @param string $description - * @param null|array $expected - * @param array $array - * - * @dataProvider provideLastRow - */ - public function testGetLastRow(string $description, ?array $expected, array $array): void - { - static::assertSame($expected, Arrays::getLastRow($array), $description); - } - - /** - * @param string $description Description of test case - * @param array $array Array which keys should be replaced - * @param string $oldKeyPattern Regular expression of the old key - * @param string $newKey Name of the new key - * @param array $expected Expected result - * - * @dataProvider provideArrayToReplaceKeys - */ - public function testReplaceKeys( - string $description, - array $array, - string $oldKeyPattern, - string $newKey, - ?array $expected - ): void { - self::assertSame($expected, Arrays::replaceKeys($array, $oldKeyPattern, $newKey), $description); - } - - public function testMakeArray(): void - { - self::assertSame($this->simpleArray, Arrays::makeArray($this->simpleArray)); - self::assertSame(['test'], Arrays::makeArray('test')); + self::assertTrue(Arrays::areKeysInArray($keys16, $this->complexArray)); + self::assertTrue(Arrays::areKeysInArray($keys17, $this->complexArray, false)); } public function testArray2JavaScript(): void @@ -369,909 +2410,20 @@ letsTest[2] = value_2;'; self::assertEquals($effect, Arrays::array2JavaScript($this->twoDimensionsArray, 'letsTest', true)); } - /** - * @param string $description Description of test case - * @param null|array $expected Expected new array (with quoted elements) - * @param array $array The array to check for string values - * - * @dataProvider provideArrayToQuoteStrings - */ - public function testQuoteStrings(string $description, ?array $expected, array $array): void + public function testConstructor() { - self::assertSame($expected, Arrays::quoteStrings($array), $description); + static::assertHasNoConstructor(Arrays::class); } /** - * @param string $description Description of test case - * @param array $array The array which should be shortened - * @param bool $last If is set to true, last element is removed (default behaviour). Otherwise - first. - * @param null|array $expected Expected result + * @param array $array + * @param bool $expected * - * @dataProvider provideArrayToRemoveMarginalElement + * @dataProvider provideArrayToVerifyIfContainsEmptyStringsOnly */ - public function testRemoveMarginalElement(string $description, array $array, bool $last, ?array $expected): void + public function testContainsEmptyStringsOnly(array $array, bool $expected): void { - self::assertSame($expected, Arrays::removeMarginalElement($array, $last), $description); - } - - public function testRemoveElements(): void - { - $array1 = $this->simpleArray; - $array2 = $this->simpleArray; - - Arrays::removeElements($array1, 'ipsum'); - self::assertSame([ - 1 => 'ipsum', - 2 => 'dolor', - 3 => 'sit', - 4 => 'amet', - ], $array1); - - Arrays::removeElements($array2, 'sit', false); - self::assertSame([ - 0 => 'Lorem', - 1 => 'ipsum', - 2 => 'dolor', - 3 => 'sit', - ], $array2); - - Arrays::removeElements($this->complexArray['lorem'], 'sit', false); - self::assertSame(['ipsum' => ['dolor' => 'sit']], $this->complexArray['lorem']); - } - - public function testRemoveElement() - { - self::assertFalse(Arrays::removeElement($this->simpleArray, 'eeee')); - self::assertTrue(is_array(Arrays::removeElement($this->simpleArray, 'Lorem'))); - - Arrays::removeElement($this->simpleArray, 'amet'); - self::assertFalse(isset($this->simpleArray['amet'])); - } - - public function testSetKeysAsValuesEmptyArray() - { - self::assertNull(Arrays::setKeysAsValues([])); - } - - public function testSetKeysAsValuesSameKeysValues() - { - $array = [ - 0, - 1, - 2, - 3, - ]; - - self::assertEquals($array, Arrays::setKeysAsValues($array)); - } - - /** - * @param array $array The array to change values with keys - * @param array $replaced The array with replaced values with keys - * - * @dataProvider provideSimpleArrayToSetKeysAsValues - */ - public function testSetKeysAsValuesSimpleArray($array, $replaced) - { - self::assertEquals($replaced, Arrays::setKeysAsValues($array)); - } - - public function testSetKeysAsValuesTwoDimensionsArray() - { - $replaced = [ - [ - 'lorem' => 0, - 'ipsum' => 1, - 'dolor' => 2, - 'sit' => 3, - 'amet' => 4, - ], - [ - 'consectetur' => 0, - 'adipiscing' => 1, - 'elit' => 2, - ], - [ - 'donec' => 0, - 'sagittis' => 1, - 'fringilla' => 2, - 'eleifend' => 3, - ], - ]; - - self::assertEquals($replaced, Arrays::setKeysAsValues($this->twoDimensionsArray)); - } - - /** - * @param array $array The array to change values with keys - * @param array $replaced The array with replaced values with keys - * - * @dataProvider provideArrayWithDuplicatedValuesToSetKeysAsValues - */ - public function testSetKeysAsValuesDuplicatedValues($array, $replaced) - { - self::assertEquals($replaced, Arrays::setKeysAsValues($array, false)); - } - - public function testGetNonArrayElementsCount(): void - { - // Negative cases - self::assertNull(Arrays::getNonArrayElementsCount([])); - - // Positive cases - self::assertEquals(5, Arrays::getNonArrayElementsCount($this->simpleArray)); - self::assertEquals(3, Arrays::getNonArrayElementsCount($this->simpleArrayWithKeys)); - self::assertEquals(12, Arrays::getNonArrayElementsCount($this->twoDimensionsArray)); - } - - public function testString2array(): void - { - // Negative cases - self::assertNull(Arrays::string2array('')); - - // Positive cases - $array = [ - 'light' => '#fff', - 'dark' => '#000', - ]; - - self::assertEquals($array, Arrays::string2array('light:#fff|dark:#000')); - self::assertEquals($array, Arrays::string2array('light: #fff | dark: #000')); - - $array = [ - 'red' => '#f00', - 'green' => '#0f0', - 'blue' => '#00f', - ]; - - self::assertEquals($array, Arrays::string2array('red:#f00|green:#0f0|blue:#00f')); - self::assertEquals($array, Arrays::string2array('red: #f00 | green: #0f0 | blue: #00f')); - self::assertEquals($array, Arrays::string2array('red : #f00 | green : #0f0 | blue : #00f')); - } - - public function testAreKeysInArray(): void - { - // Negative cases - self::assertFalse(Arrays::areKeysInArray([], [])); - self::assertFalse(Arrays::areKeysInArray([null], $this->simpleArray)); - self::assertFalse(Arrays::areKeysInArray([''], $this->simpleArray)); - self::assertFalse(Arrays::areKeysInArray(['dolorrr'], $this->simpleArrayWithKeys)); - - $keys1 = [ - 1, - 3, - 9, - ]; - - self::assertFalse(Arrays::areKeysInArray($keys1, $this->simpleArray)); - self::assertFalse(Arrays::areKeysInArray($keys1, $this->complexArray)); - self::assertFalse(Arrays::areKeysInArray($keys1, $this->complexArray, false)); - - // Positive cases - $keys12 = [ - 2, - 'mollis', - ]; - - $keys13 = [ - 1, - 3, - ]; - - $keys14 = [ - 'dolor', - 'amet', - ]; - - $keys15 = [ - 'dolor', - 'amet', - ]; - - $keys16 = [ - 'a' => 'lorem', - 11 => 'amet', - ]; - - $keys17 = [ - 'a' => 'lorem', - 11 => 'amet', - 'c' => 'sit__', - ]; - - self::assertTrue(Arrays::areKeysInArray([1], $this->simpleArray)); - self::assertTrue(Arrays::areKeysInArray($keys12, $this->simpleArray, false)); - self::assertTrue(Arrays::areKeysInArray($keys12, $this->complexArray)); - self::assertTrue(Arrays::areKeysInArray($keys13, $this->simpleArray)); - self::assertTrue(Arrays::areKeysInArray($keys14, $this->simpleArrayWithKeys)); - self::assertTrue(Arrays::areKeysInArray($keys15, $this->simpleArrayWithKeys)); - - self::assertTrue(Arrays::areKeysInArray(['a' => 'dolor'], $this->simpleArrayWithKeys)); - self::assertTrue(Arrays::areKeysInArray(['a' => 'dolor'], $this->simpleArrayWithKeys, false)); - - self::assertTrue(Arrays::areKeysInArray($keys16, $this->complexArray)); - self::assertTrue(Arrays::areKeysInArray($keys17, $this->complexArray, false)); - } - - public function testGetLastElementsPathsUsingEmptyArray(): void - { - self::assertNull(Arrays::getLastElementsPaths([])); - } - - public function testGetLastElementsPathsUsingDefaults(): void - { - // Using default separator and other default arguments - $expected = [ - 'lorem.ipsum.dolor' => 'sit', - 'lorem.ipsum.diam.non' => 'egestas', - 'consectetur' => 'adipiscing', - 'mollis' => 1234, - 2 => [], - 'sit.nullam' => 'donec', - 'sit.aliquet.vitae.ligula' => 'quis', - 'sit.0' => 'elit', - 'amet.0' => 'iaculis', - 'amet.1' => 'primis', - ]; - - self::assertEquals($expected, Arrays::getLastElementsPaths($this->complexArray)); - } - - public function testGetLastElementsPathsUsingCustomSeparator(): void - { - // Using custom separator - $separator = ' -> '; - $expected = [ - sprintf('lorem%sipsum%sdolor', $separator, $separator) => 'sit', - sprintf('lorem%sipsum%sdiam%snon', $separator, $separator, $separator) => 'egestas', - 'consectetur' => 'adipiscing', - 'mollis' => 1234, - 2 => [], - sprintf('sit%snullam', $separator) => 'donec', - sprintf('sit%saliquet%svitae%sligula', $separator, $separator, $separator) => 'quis', - sprintf('sit%s0', $separator) => 'elit', - sprintf('amet%s0', $separator) => 'iaculis', - sprintf('amet%s1', $separator) => 'primis', - ]; - - self::assertEquals($expected, Arrays::getLastElementsPaths($this->complexArray, $separator)); - } - - /** - * @param array $stopIfMatchedBy Patterns of keys or paths that matched will stop the process of path building and - * including children of those keys or paths (recursive will not be used for keys in - * lower level of given array) - * @param string $separator Separator used in resultant strings. Default: ".". - * @param array $expected Expected array - * - * @dataProvider provideStopIfMatchedByForGetLastElementsPaths - */ - public function testGetLastElementsPathsUsingStopIfMatchedBy( - array $stopIfMatchedBy, - string $separator, - array $expected - ): void { - $paths = Arrays::getLastElementsPaths($this->superComplexArray, $separator, '', $stopIfMatchedBy); - self::assertEquals($expected, $paths); - } - - public function testAreAllKeysMatchedByPattern(): void - { - $pattern = '\d+'; - - // Empty array - self::assertFalse(Arrays::areAllKeysMatchedByPattern([], $pattern)); - - // Simple array with integers as keys only - self::assertTrue(Arrays::areAllKeysMatchedByPattern($this->simpleArray, $pattern)); - - // Complex array with strings and integers as keys - self::assertFalse(Arrays::areAllKeysMatchedByPattern($this->complexArray, $pattern)); - - $array = [ - 'a' => 'b', - 'c' => 'd', - ]; - - // Yet another simple array, but with strings as keys - self::assertFalse(Arrays::areAllKeysMatchedByPattern($array, $pattern)); - - // The same array with another pattern - $pattern = '\w+'; - self::assertTrue(Arrays::areAllKeysMatchedByPattern($array, $pattern)); - - // The same array with mixed keys (strings and integers as keys) - $array[1] = 'x'; - $pattern = '\d+'; - self::assertFalse(Arrays::areAllKeysMatchedByPattern($array, $pattern)); - - // Multidimensional array - negative case - $array['e'] = ['f' => 'g']; - self::assertFalse(Arrays::areAllKeysMatchedByPattern($array, $pattern)); - - // Multidimensional array - positive case - unset($array[1]); - $pattern = '\w+'; - self::assertTrue(Arrays::areAllKeysMatchedByPattern($array, $pattern)); - } - - public function testAreAllKeysIntegers() - { - self::assertFalse(Arrays::areAllKeysIntegers([])); - self::assertEquals(1, Arrays::areAllKeysIntegers($this->simpleArray)); - self::assertEquals(2, Arrays::areAllKeysIntegers($this->simpleArray)); - self::assertEquals('', Arrays::areAllKeysIntegers($this->complexArray)); - } - - public function testIssetRecursive() - { - // Negative cases - self::assertFalse(Arrays::issetRecursive([], [])); - - // Positive cases - $unExistingKeys = [ - 'a', - 'b', - 3, - ]; - - $existingKeys = [ - 'simpleArray' => [ - 1, - 3, - 4, - ], - 'simpleArrayWithKeys' => [ - 'dolor', - 'amet', - ], - 'twoDimensionsArray' => [ - 2, - 3, - ], - 'complexArray' => [ - 'sit', - 'aliquet', - 'vitae', - ], - ]; - - self::assertFalse(Arrays::issetRecursive($this->simpleArray, $unExistingKeys)); - self::assertTrue(Arrays::issetRecursive($this->simpleArray, $existingKeys['simpleArray'])); - - self::assertFalse(Arrays::issetRecursive($this->simpleArrayWithKeys, $unExistingKeys)); - self::assertTrue(Arrays::issetRecursive($this->simpleArrayWithKeys, $existingKeys['simpleArrayWithKeys'])); - - self::assertFalse(Arrays::issetRecursive($this->twoDimensionsArray, $unExistingKeys)); - self::assertTrue(Arrays::issetRecursive($this->twoDimensionsArray, $existingKeys['twoDimensionsArray'])); - - self::assertFalse(Arrays::issetRecursive($this->complexArray, $unExistingKeys)); - self::assertTrue(Arrays::issetRecursive($this->complexArray, $existingKeys['complexArray'])); - } - - public function testGetValueByKeysPath() - { - // Negative cases - self::assertNull(Arrays::getValueByKeysPath([], [])); - - // Positive cases - self::assertNull(Arrays::getValueByKeysPath($this->simpleArray, [])); - self::assertEquals('ipsum', Arrays::getValueByKeysPath($this->simpleArray, [1])); - self::assertEquals('sit', Arrays::getValueByKeysPath($this->simpleArray, [3])); - self::assertEquals('sit', Arrays::getValueByKeysPath($this->simpleArrayWithKeys, ['dolor'])); - - $keys = [ - 'twoDimensionsArray' => [ - 2, - 2, - ], - 'complexArray' => [ - [ - 'lorem', - 'ipsum', - 'diam', - ], - [ - 'sit', - 'aliquet', - ], - ], - ]; - - $value = [ - [ - 'non' => 'egestas', - ], - [ - 'vitae' => [ - 'ligula' => 'quis', - ], - ], - ]; - - self::assertEquals('fringilla', Arrays::getValueByKeysPath($this->twoDimensionsArray, $keys['twoDimensionsArray'])); - self::assertEquals($value[0], Arrays::getValueByKeysPath($this->complexArray, $keys['complexArray'][0])); - self::assertEquals($value[1], Arrays::getValueByKeysPath($this->complexArray, $keys['complexArray'][1])); - } - - public function testGetAllValuesOfKeyEmptyValue() - { - self::assertNull(Arrays::getAllValuesOfKey([], '')); - self::assertNull(Arrays::getAllValuesOfKey([], 'test')); - } - - public function testGetAllValuesOfKeyNotExistingKey() - { - self::assertNull(Arrays::getAllValuesOfKey([], 'ipsum')); - self::assertEquals([], Arrays::getAllValuesOfKey($this->simpleArray, 'ipsum')); - } - - public function testGetAllValuesOfKey() - { - // Positive case - 1-dimension array - self::assertEquals(['ipsum'], Arrays::getAllValuesOfKey($this->simpleArray, 1)); - - // Positive case - 2-dimensions array - $effect = [ - [ - 'lorem', - 'ipsum', - 'dolor', - 'sit', - 'amet', - ], - 1 => 'consectetur', - 2 => 'donec', - ]; - - self::assertEquals($effect, Arrays::getAllValuesOfKey($this->twoDimensionsArray, 0)); - - // Positive case - multi-dimensions array - self::assertEquals(['primis'], Arrays::getAllValuesOfKey($this->complexArray, 1)); - - // Positive case - multi-dimensions array - $effect = [ - 0 => [ - 'in' => [ - 'dui', - 'dolor' => [ - 'aliquam', - ], - ], - ], - ]; - - self::assertEquals($effect, Arrays::getAllValuesOfKey($this->superComplexArray, 'tortor')); - } - - public function testKsortRecursive() - { - // Negative cases - $array = []; - self::assertNull(Arrays::ksortRecursive($array)); - - // Positive cases - self::assertEquals($this->simpleArray, Arrays::ksortRecursive($this->simpleArray)); - self::assertEquals($this->simpleArray, Arrays::ksortRecursive($this->simpleArray, SORT_NUMERIC)); - self::assertEquals($this->twoDimensionsArray, Arrays::ksortRecursive($this->twoDimensionsArray)); - - // Positive case - multi-dimensions array - $effect = [ - 'amet' => [ - 'iaculis', - 'primis', - ], - 'consectetur' => 'adipiscing', - 'lorem' => [ - 'ipsum' => [ - 'dolor' => 'sit', - 'diam' => [ - 'non' => 'egestas', - ], - ], - ], - 'mollis' => 1234, - 'sit' => [ - 'nullam' => 'donec', - 'aliquet' => [ - 'vitae' => [ - 'ligula' => 'quis', - ], - ], - 'elit', - ], - 2 => [], - ]; - - self::assertEquals($effect, Arrays::ksortRecursive($this->complexArray)); - - // Positive case - multi-dimensions array - with options of ksort() function - $effect = [ - 2 => [], - 'amet' => [ - 'iaculis', - 'primis', - ], - 'consectetur' => 'adipiscing', - 'lorem' => [ - 'ipsum' => [ - 'dolor' => 'sit', - 'diam' => [ - 'non' => 'egestas', - ], - ], - ], - 'mollis' => 1234, - 'sit' => [ - 'nullam' => 'donec', - 'aliquet' => [ - 'vitae' => [ - 'ligula' => 'quis', - ], - ], - 'elit', - ], - ]; - - self::assertEquals($effect, Arrays::ksortRecursive($this->complexArray, SORT_STRING & SORT_NATURAL)); - } - - public function testSetPositions() - { - // Negative cases - self::assertNull(Arrays::setPositions([])); - - // Positive case - 1-dimension array - $array = [ - 'abc', - ]; - - self::assertEquals($array, Arrays::setPositions($array)); - - // Positive case - 2-dimensions array - $effect = $this->twoDimensionsArray; - $effect[0][Arrays::POSITION_KEY_NAME] = 1; - $effect[1][Arrays::POSITION_KEY_NAME] = 2; - $effect[2][Arrays::POSITION_KEY_NAME] = 3; - - self::assertEquals($effect, Arrays::setPositions($this->twoDimensionsArray)); - - // Positive case - multidimensional array - $array = [ - 'lorem', - 'ipsum' => [ - 'dolor', - 'sit', - ], - 'amet' => [ - 'consectetur', - 'adipiscing' => [ - 'elit' => [ - 'cras', - 'quis', - 'ligula', - ], - ], - ], - ]; - - $effect = [ - 'lorem', - 'ipsum' => [ - 'dolor', - 'sit', - Arrays::POSITION_KEY_NAME => 1, - ], - 'amet' => [ - 'consectetur', - 'adipiscing' => [ - 'elit' => [ - 'cras', - 'quis', - 'ligula', - Arrays::POSITION_KEY_NAME => 1, - ], - Arrays::POSITION_KEY_NAME => 1, - ], - Arrays::POSITION_KEY_NAME => 2, - ], - ]; - - self::assertEquals($effect, Arrays::setPositions($array)); - - // Positive case - non-default name of key with position value & 2-dimensions array - $keyName = 'level'; - $effect = $this->twoDimensionsArray; - - $effect[0][$keyName] = 1; - $effect[1][$keyName] = 2; - $effect[2][$keyName] = 3; - - self::assertEquals($effect, Arrays::setPositions($this->twoDimensionsArray, $keyName)); - - // Positive case - non-default start value of position & 2-dimensions array - $startPosition = 5; - $effect = $this->twoDimensionsArray; - - $effect[Arrays::POSITION_KEY_NAME] = $startPosition; - $effect[0][Arrays::POSITION_KEY_NAME] = 1; - $effect[1][Arrays::POSITION_KEY_NAME] = 2; - $effect[2][Arrays::POSITION_KEY_NAME] = 3; - - self::assertEquals($effect, Arrays::setPositions($this->twoDimensionsArray, Arrays::POSITION_KEY_NAME, $startPosition)); - } - - public function testTrimRecursive() - { - // Negative cases - self::assertSame([], Arrays::trimRecursive([])); - - // Positive cases - self::assertEquals(['a'], Arrays::trimRecursive([' a '])); - self::assertEquals([ - 'a', - 'b', - ], Arrays::trimRecursive([ - ' a ', - 'b ', - ])); - - $array = [ - 'abc ', - [ - 'def', - 'ghi ', - ], - ]; - - $result = [ - 'abc', - [ - 'def', - 'ghi', - ], - ]; - - self::assertEquals($result, Arrays::trimRecursive($array)); - - $array = [ - 'abc ', - [ - ' def ', - 'ghi ', - 'oo' => [ - ' ee ', - 'g' => 'h hhh ', - ], - ], - ]; - - $result = [ - 'abc', - [ - 'def', - 'ghi', - 'oo' => [ - 'ee', - 'g' => 'h hhh', - ], - ], - ]; - - self::assertEquals($result, Arrays::trimRecursive($array)); - } - - public function testSortByCustomKeysOrder() - { - // Negative cases - self::assertNull(Arrays::sortByCustomKeysOrder([], [])); - - // Positive cases - self::assertEquals([0], Arrays::sortByCustomKeysOrder([0], [])); - self::assertEquals($this->simpleArray, Arrays::sortByCustomKeysOrder($this->simpleArray, [])); - - $keysOrder = [ - 'amet', - 'dolor', - 'Lorem', - ]; - - $sorted = [ - 'dolor' => 'sit', - 'amet' => 'consectetur', - 'Lorem' => 'ipsum', - ]; - - self::assertEquals($sorted, Arrays::sortByCustomKeysOrder($this->simpleArrayWithKeys, $keysOrder)); - - $array = [ - 'Lorem', - 'ipsum', - 'dolor', - 'sit', - 'amet', - ]; - - $keysOrder = [ - 0, - 3, - 1, - 2, - ]; - - $sorted = [ - 0 => 'Lorem', - 3 => 'sit', - 1 => 'ipsum', - 2 => 'dolor', - 4 => 'amet', - ]; - - self::assertEquals($sorted, Arrays::sortByCustomKeysOrder($array, $keysOrder)); - - $array = [ - 'Lorem', - 'ipsum', - 'dolor', - 'sit', - 'amet', - ]; - - $keysOrder = [ - 0, - 3, - ]; - - $sorted = [ - 0 => 'Lorem', - 3 => 'sit', - 1 => 'ipsum', - 2 => 'dolor', - 4 => 'amet', - ]; - - self::assertEquals($sorted, Arrays::sortByCustomKeysOrder($array, $keysOrder)); - } - - public function testImplodeSmart() - { - $separator = '/'; - - // Empty array - self::assertNull(Arrays::implodeSmart([], $separator)); - - // Simple, One-dimensional array - self::assertEquals(implode($separator, $this->simpleArray), Arrays::implodeSmart($this->simpleArray, $separator)); - - // An array with elements that contain separator - $array = [ - 'lorem' . $separator, - 'ipsum', - $separator . 'dolor', - ]; - - self::assertEquals(implode($separator, [ - 'lorem', - 'ipsum', - 'dolor', - ]), Arrays::implodeSmart($array, $separator)); - - // Complex array - self::assertEquals(implode($separator, [ - 'donec', - 'quis', - 'elit', - ]), Arrays::implodeSmart($this->complexArray['sit'], $separator)); - } - - public function testGetNextElement() - { - // Negative cases - self::assertNull(Arrays::getNextElement($this->simpleArray, 'amet')); - self::assertNull(Arrays::getNextElement($this->simpleArray, 'xyz')); - self::assertNull(Arrays::getNextElement($this->simpleArray, 0)); - self::assertNull(Arrays::getNextElement([], '')); - self::assertNull(Arrays::getNextElement([], null)); - - // Positive cases - self::assertEquals('ipsum', Arrays::getNextElement($this->simpleArray, 'Lorem')); - self::assertEquals('sit', Arrays::getNextElement($this->simpleArray, 'dolor')); - } - - public function testGetPreviousElement() - { - // Negative cases - self::assertNull(Arrays::getPreviousElement($this->simpleArray, 'Lorem')); - self::assertNull(Arrays::getPreviousElement($this->simpleArray, 'xyz')); - self::assertNull(Arrays::getPreviousElement($this->simpleArray, 0)); - self::assertNull(Arrays::getPreviousElement([], '')); - self::assertNull(Arrays::getPreviousElement([], null)); - - // Positive cases - self::assertEquals('ipsum', Arrays::getPreviousElement($this->simpleArray, 'dolor')); - self::assertEquals('sit', Arrays::getPreviousElement($this->simpleArray, 'amet')); - } - - public function testGetIndexOf() - { - // Negative cases - self::assertFalse(Arrays::getIndexOf([], 'a')); - self::assertNull(Arrays::getIndexOf($this->simpleArray, 'loremmm')); - - // Positive cases - self::assertEquals(1, Arrays::getIndexOf($this->simpleArray, 'ipsum')); - self::assertEquals('dolor', Arrays::getIndexOf($this->simpleArrayWithKeys, 'sit')); - self::assertEquals('mollis', Arrays::getIndexOf($this->complexArray, 1234)); - } - - public function testIncrementIndexes() - { - // Negative cases - self::assertNull(Arrays::incrementIndexes([])); - - // Positive cases - $array = [ - 1 => 'Lorem', - 2 => 'ipsum', - 3 => 'dolor', - 4 => 'sit', - 5 => 'amet', - ]; - self::assertEquals($array, Arrays::incrementIndexes($this->simpleArray)); - - $array = [ - 0 => 'Lorem', - 2 => 'ipsum', - 3 => 'dolor', - 4 => 'sit', - 5 => 'amet', - ]; - self::assertEquals($array, Arrays::incrementIndexes($this->simpleArray, 1)); - - $array = [ - 0 => 'Lorem', - 1 => 'ipsum', - 3 => 'dolor', - 4 => 'sit', - 5 => 'amet', - ]; - self::assertEquals($array, Arrays::incrementIndexes($this->simpleArray, 2)); - } - - public function testAreAllValuesEmpty() - { - // Negative cases - self::assertFalse(Arrays::areAllValuesEmpty([])); - self::assertFalse(Arrays::areAllValuesEmpty([], true)); - self::assertFalse(Arrays::areAllValuesEmpty($this->simpleArray)); - self::assertFalse(Arrays::areAllValuesEmpty($this->simpleArray, true)); - - $array = [ - null, - 0, - ]; - self::assertFalse(Arrays::areAllValuesEmpty($array, true)); - - $array = [ - null, - [ - null, - ], - ]; - self::assertFalse(Arrays::areAllValuesEmpty($array, true)); - - // Positive cases - $array = [ - '', - 0, - ]; - self::assertTrue(Arrays::areAllValuesEmpty($array)); - - $array = [ - null, - null, - ]; - self::assertTrue(Arrays::areAllValuesEmpty($array, true)); + static::assertSame($expected, Arrays::containsEmptyStringsOnly($array)); } public function testDiffRecursive() @@ -1430,6 +2582,56 @@ letsTest[2] = value_2;'; self::assertEquals($diff, Arrays::arrayDiffRecursive($array, $this->twoDimensionsArray, true)); } + public function testGetAllValuesOfKey() + { + // Positive case - 1-dimension array + self::assertEquals(['ipsum'], Arrays::getAllValuesOfKey($this->simpleArray, 1)); + + // Positive case - 2-dimensions array + $effect = [ + [ + 'lorem', + 'ipsum', + 'dolor', + 'sit', + 'amet', + ], + 1 => 'consectetur', + 2 => 'donec', + ]; + + self::assertEquals($effect, Arrays::getAllValuesOfKey($this->twoDimensionsArray, 0)); + + // Positive case - multi-dimensions array + self::assertEquals(['primis'], Arrays::getAllValuesOfKey($this->complexArray, 1)); + + // Positive case - multi-dimensions array + $effect = [ + 0 => [ + 'in' => [ + 'dui', + 'dolor' => [ + 'aliquam', + ], + ], + ], + ]; + + self::assertEquals($effect, Arrays::getAllValuesOfKey($this->superComplexArray, 'tortor')); + } + + public function testGetAllValuesOfKeyEmptyValue() + { + self::assertNull(Arrays::getAllValuesOfKey([], '')); + self::assertNull(Arrays::getAllValuesOfKey([], 'test')); + } + + public function testGetAllValuesOfKeyNotExistingKey() + { + self::assertNull(Arrays::getAllValuesOfKey([], 'ipsum')); + self::assertEquals([], Arrays::getAllValuesOfKey($this->simpleArray, 'ipsum')); + } + public function testGetDimensionsCount() { // Basic cases @@ -1445,126 +2647,6 @@ letsTest[2] = value_2;'; self::assertEquals(4, Arrays::getDimensionsCount($this->complexArray)); } - public function testIsMultiDimensional() - { - // Negative cases - self::assertNull(Arrays::isMultiDimensional([])); - - // Positive cases - self::assertFalse(Arrays::isMultiDimensional($this->simpleArray)); - self::assertFalse(Arrays::isMultiDimensional($this->simpleArrayWithKeys)); - - self::assertTrue(Arrays::isMultiDimensional($this->twoDimensionsArray)); - self::assertTrue(Arrays::isMultiDimensional($this->complexArray)); - } - - public function testGetNonEmptyValuesUsingEmptyArray() - { - self::assertNull(Arrays::getNonEmptyValues([])); - } - - /** - * @param string $description Description of test case - * @param array $values The values to filter - * @param array $expected Expected non-empty values - * - * @dataProvider provideValuesToFilterNonEmpty - */ - public function testGetNonEmptyValues($description, array $values, array $expected) - { - self::assertSame($expected, Arrays::getNonEmptyValues($values), $description); - } - - /** - * @param string $description Description of test case - * @param array $values The values to filter - * @param string $expected Expected non-empty values (as string) - * - * @dataProvider provideValuesToFilterNonEmptyAsStringUsingDefaultSeparator - */ - public function testGetNonEmptyValuesAsStringUsingDefaultSeparator($description, array $values, $expected) - { - self::assertSame($expected, Arrays::getNonEmptyValuesAsString($values), $description); - } - - /** - * @param string $description Description of test case - * @param array $values The values to filter - * @param string $separator Separator used to implode the values - * @param string $expected Expected non-empty values (as string) - * - * @dataProvider provideValuesToFilterNonEmptyAsString - */ - public function testGetNonEmptyValuesAsString($description, array $values, $separator, $expected) - { - self::assertSame($expected, Arrays::getNonEmptyValuesAsString($values, $separator), $description); - } - - /** - * @param string $description Description of test case - * @param mixed $value The value to verify - * @param bool $expected Expected information - * - * @dataProvider provideValueToIsEmptyArray - */ - public function testIsEmptyArray(string $description, $value, bool $expected): void - { - self::assertSame($expected, Arrays::isEmptyArray($value), $description); - } - - /** - * @param string $description Description of test case - * @param mixed $value The value to verify - * @param bool $expected Expected information - * - * @dataProvider provideValueToIsNotEmptyArray - */ - public function testIsNotEmptyArray(string $description, $value, bool $expected): void - { - self::assertSame($expected, Arrays::isNotEmptyArray($value), $description); - } - - /** - * @param array $array - * @param bool $expected - * - * @dataProvider provideArrayToVerifyIfContainsEmptyStringsOnly - */ - public function testContainsEmptyStringsOnly(array $array, bool $expected): void - { - static::assertSame($expected, Arrays::containsEmptyStringsOnly($array)); - } - - public function testGetElementsFromLevelIfArrayIsEmpty(): void - { - self::assertNull(Arrays::getElementsFromLevel([], -1)); - self::assertNull(Arrays::getElementsFromLevel([], 0)); - self::assertNull(Arrays::getElementsFromLevel([], 1)); - } - - public function testGetElementsFromLevelIfThereIsNoGivenLevel(): void - { - self::assertSame([], Arrays::getElementsFromLevel([1, 2, 3], 9999)); - } - - public function testGetElementsFromLevelIfGivenLevelIsNotPositiveValue(): void - { - self::assertNull(Arrays::getElementsFromLevel([1, 2, 3], -1)); - self::assertNull(Arrays::getElementsFromLevel([1, 2, 3], 0)); - } - - public function testGetElementsFromLevelIfArrayHasOneLevelOnly(): void - { - $array = [ - // Level 1: - 'ab', - 'cd', - 'ef', - ]; - - self::assertSame($array, Arrays::getElementsFromLevel($array, 1)); - } - public function testGetElementsFromLevel(): void { $array = [ @@ -1645,6 +2727,25 @@ letsTest[2] = value_2;'; self::assertSame($expectedLevel3, Arrays::getElementsFromLevel($array, 3)); } + public function testGetElementsFromLevelIfArrayHasOneLevelOnly(): void + { + $array = [ + // Level 1: + 'ab', + 'cd', + 'ef', + ]; + + self::assertSame($array, Arrays::getElementsFromLevel($array, 1)); + } + + public function testGetElementsFromLevelIfArrayIsEmpty(): void + { + self::assertNull(Arrays::getElementsFromLevel([], -1)); + self::assertNull(Arrays::getElementsFromLevel([], 0)); + self::assertNull(Arrays::getElementsFromLevel([], 1)); + } + public function testGetElementsFromLevelIfGivenKeyDoesNotExist(): void { $array = [ @@ -1662,6 +2763,17 @@ letsTest[2] = value_2;'; self::assertSame([], Arrays::getElementsFromLevel($array, 2, 'X')); } + public function testGetElementsFromLevelIfGivenLevelIsNotPositiveValue(): void + { + self::assertNull(Arrays::getElementsFromLevel([1, 2, 3], -1)); + self::assertNull(Arrays::getElementsFromLevel([1, 2, 3], 0)); + } + + public function testGetElementsFromLevelIfThereIsNoGivenLevel(): void + { + self::assertSame([], Arrays::getElementsFromLevel([1, 2, 3], 9999)); + } + public function testGetElementsFromLevelWithGivenKey(): void { $array = [ @@ -1739,1367 +2851,515 @@ letsTest[2] = value_2;'; } /** - * Provides simple array to set/replace values with keys + * @param string $description + * @param $expected + * @param array $array + * @param null|bool $firstLevelOnly * - * @return \Generator + * @dataProvider provideFirstElement */ - public function provideSimpleArrayToSetKeysAsValues() + public function testGetFirstElement( + string $description, + $expected, + array $array, + ?bool $firstLevelOnly = null + ): void { + if (null === $firstLevelOnly) { + static::assertSame($expected, Arrays::getFirstElement($array), $description); + + return; + } + + static::assertSame($expected, Arrays::getFirstElement($array, $firstLevelOnly), $description); + } + + public function testGetFirstKey() { - yield[ - [ - 1, + // Negative cases + self::assertNull(Arrays::getFirstKey([])); + + // Positive cases + self::assertEquals(0, Arrays::getFirstKey($this->simpleArray)); + self::assertEquals('lorem', Arrays::getFirstKey($this->complexArray)); + } + + public function testGetIndexOf() + { + // Negative cases + self::assertFalse(Arrays::getIndexOf([], 'a')); + self::assertNull(Arrays::getIndexOf($this->simpleArray, 'loremmm')); + + // Positive cases + self::assertEquals(1, Arrays::getIndexOf($this->simpleArray, 'ipsum')); + self::assertEquals('dolor', Arrays::getIndexOf($this->simpleArrayWithKeys, 'sit')); + self::assertEquals('mollis', Arrays::getIndexOf($this->complexArray, 1234)); + } + + /** + * @param string $description + * @param $expected + * @param array $array + * @param null|bool $firstLevelOnly + * + * @dataProvider provideLastElement + */ + public function testGetLastElement( + string $description, + $expected, + array $array, + ?bool $firstLevelOnly = null + ): void { + if (null === $firstLevelOnly) { + static::assertSame($expected, Arrays::getLastElement($array), $description); + + return; + } + + static::assertSame($expected, Arrays::getLastElement($array, $firstLevelOnly), $description); + } + + public function testGetLastElementBreadCrumb() + { + self::assertNull(Arrays::getLastElementBreadCrumb([])); + self::assertEquals('4/amet', Arrays::getLastElementBreadCrumb($this->simpleArray)); + self::assertEquals('2/3/eleifend', Arrays::getLastElementBreadCrumb($this->twoDimensionsArray)); + self::assertEquals('amet/1/primis', Arrays::getLastElementBreadCrumb($this->complexArray)); + } + + public function testGetLastElementsPathsUsingCustomSeparator(): void + { + // Using custom separator + $separator = ' -> '; + $expected = [ + sprintf('lorem%sipsum%sdolor', $separator, $separator) => 'sit', + sprintf('lorem%sipsum%sdiam%snon', $separator, $separator, $separator) => 'egestas', + 'consectetur' => 'adipiscing', + 'mollis' => 1234, + 2 => [], + sprintf('sit%snullam', $separator) => 'donec', + sprintf('sit%saliquet%svitae%sligula', $separator, $separator, $separator) => 'quis', + sprintf('sit%s0', $separator) => 'elit', + sprintf('amet%s0', $separator) => 'iaculis', + sprintf('amet%s1', $separator) => 'primis', + ]; + + self::assertEquals($expected, Arrays::getLastElementsPaths($this->complexArray, $separator)); + } + + public function testGetLastElementsPathsUsingDefaults(): void + { + // Using default separator and other default arguments + $expected = [ + 'lorem.ipsum.dolor' => 'sit', + 'lorem.ipsum.diam.non' => 'egestas', + 'consectetur' => 'adipiscing', + 'mollis' => 1234, + 2 => [], + 'sit.nullam' => 'donec', + 'sit.aliquet.vitae.ligula' => 'quis', + 'sit.0' => 'elit', + 'amet.0' => 'iaculis', + 'amet.1' => 'primis', + ]; + + self::assertEquals($expected, Arrays::getLastElementsPaths($this->complexArray)); + } + + public function testGetLastElementsPathsUsingEmptyArray(): void + { + self::assertNull(Arrays::getLastElementsPaths([])); + } + + /** + * @param array $stopIfMatchedBy Patterns of keys or paths that matched will stop the process of path building and + * including children of those keys or paths (recursive will not be used for keys in + * lower level of given array) + * @param string $separator Separator used in resultant strings. Default: ".". + * @param array $expected Expected array + * + * @dataProvider provideStopIfMatchedByForGetLastElementsPaths + */ + public function testGetLastElementsPathsUsingStopIfMatchedBy( + array $stopIfMatchedBy, + string $separator, + array $expected + ): void { + $paths = Arrays::getLastElementsPaths($this->superComplexArray, $separator, '', $stopIfMatchedBy); + self::assertEquals($expected, $paths); + } + + public function testGetLastKey() + { + self::assertNull(Arrays::getLastKey([])); + self::assertEquals(4, Arrays::getLastKey($this->simpleArray)); + self::assertEquals('amet', Arrays::getLastKey($this->complexArray)); + } + + /** + * @param string $description + * @param null|array $expected + * @param array $array + * + * @dataProvider provideLastRow + */ + public function testGetLastRow(string $description, ?array $expected, array $array): void + { + static::assertSame($expected, Arrays::getLastRow($array), $description); + } + + public function testGetNextElement() + { + // Negative cases + self::assertNull(Arrays::getNextElement($this->simpleArray, 'amet')); + self::assertNull(Arrays::getNextElement($this->simpleArray, 'xyz')); + self::assertNull(Arrays::getNextElement($this->simpleArray, 0)); + self::assertNull(Arrays::getNextElement([], '')); + self::assertNull(Arrays::getNextElement([], null)); + + // Positive cases + self::assertEquals('ipsum', Arrays::getNextElement($this->simpleArray, 'Lorem')); + self::assertEquals('sit', Arrays::getNextElement($this->simpleArray, 'dolor')); + } + + public function testGetNonArrayElementsCount(): void + { + // Negative cases + self::assertNull(Arrays::getNonArrayElementsCount([])); + + // Positive cases + self::assertEquals(5, Arrays::getNonArrayElementsCount($this->simpleArray)); + self::assertEquals(3, Arrays::getNonArrayElementsCount($this->simpleArrayWithKeys)); + self::assertEquals(12, Arrays::getNonArrayElementsCount($this->twoDimensionsArray)); + } + + /** + * @param string $description Description of test case + * @param array $values The values to filter + * @param array $expected Expected non-empty values + * + * @dataProvider provideValuesToFilterNonEmpty + */ + public function testGetNonEmptyValues($description, array $values, array $expected) + { + self::assertSame($expected, Arrays::getNonEmptyValues($values), $description); + } + + /** + * @param string $description Description of test case + * @param array $values The values to filter + * @param string $separator Separator used to implode the values + * @param string $expected Expected non-empty values (as string) + * + * @dataProvider provideValuesToFilterNonEmptyAsString + */ + public function testGetNonEmptyValuesAsString($description, array $values, $separator, $expected) + { + self::assertSame($expected, Arrays::getNonEmptyValuesAsString($values, $separator), $description); + } + + /** + * @param string $description Description of test case + * @param array $values The values to filter + * @param string $expected Expected non-empty values (as string) + * + * @dataProvider provideValuesToFilterNonEmptyAsStringUsingDefaultSeparator + */ + public function testGetNonEmptyValuesAsStringUsingDefaultSeparator($description, array $values, $expected) + { + self::assertSame($expected, Arrays::getNonEmptyValuesAsString($values), $description); + } + + public function testGetNonEmptyValuesUsingEmptyArray() + { + self::assertNull(Arrays::getNonEmptyValues([])); + } + + public function testGetPreviousElement() + { + // Negative cases + self::assertNull(Arrays::getPreviousElement($this->simpleArray, 'Lorem')); + self::assertNull(Arrays::getPreviousElement($this->simpleArray, 'xyz')); + self::assertNull(Arrays::getPreviousElement($this->simpleArray, 0)); + self::assertNull(Arrays::getPreviousElement([], '')); + self::assertNull(Arrays::getPreviousElement([], null)); + + // Positive cases + self::assertEquals('ipsum', Arrays::getPreviousElement($this->simpleArray, 'dolor')); + self::assertEquals('sit', Arrays::getPreviousElement($this->simpleArray, 'amet')); + } + + public function testGetValueByKeysPath() + { + // Negative cases + self::assertNull(Arrays::getValueByKeysPath([], [])); + + // Positive cases + self::assertNull(Arrays::getValueByKeysPath($this->simpleArray, [])); + self::assertEquals('ipsum', Arrays::getValueByKeysPath($this->simpleArray, [1])); + self::assertEquals('sit', Arrays::getValueByKeysPath($this->simpleArray, [3])); + self::assertEquals('sit', Arrays::getValueByKeysPath($this->simpleArrayWithKeys, ['dolor'])); + + $keys = [ + 'twoDimensionsArray' => [ 2, + 2, + ], + 'complexArray' => [ + [ + 'lorem', + 'ipsum', + 'diam', + ], + [ + 'sit', + 'aliquet', + ], + ], + ]; + + $value = [ + [ + 'non' => 'egestas', + ], + [ + 'vitae' => [ + 'ligula' => 'quis', + ], + ], + ]; + + self::assertEquals('fringilla', Arrays::getValueByKeysPath($this->twoDimensionsArray, $keys['twoDimensionsArray'])); + self::assertEquals($value[0], Arrays::getValueByKeysPath($this->complexArray, $keys['complexArray'][0])); + self::assertEquals($value[1], Arrays::getValueByKeysPath($this->complexArray, $keys['complexArray'][1])); + } + + public function testImplodeSmart() + { + $separator = '/'; + + // Empty array + self::assertNull(Arrays::implodeSmart([], $separator)); + + // Simple, One-dimensional array + self::assertEquals(implode($separator, $this->simpleArray), Arrays::implodeSmart($this->simpleArray, $separator)); + + // An array with elements that contain separator + $array = [ + 'lorem'.$separator, + 'ipsum', + $separator.'dolor', + ]; + + self::assertEquals(implode($separator, [ + 'lorem', + 'ipsum', + 'dolor', + ]), Arrays::implodeSmart($array, $separator)); + + // Complex array + self::assertEquals(implode($separator, [ + 'donec', + 'quis', + 'elit', + ]), Arrays::implodeSmart($this->complexArray['sit'], $separator)); + } + + public function testIncrementIndexes() + { + // Negative cases + self::assertNull(Arrays::incrementIndexes([])); + + // Positive cases + $array = [ + 1 => 'Lorem', + 2 => 'ipsum', + 3 => 'dolor', + 4 => 'sit', + 5 => 'amet', + ]; + self::assertEquals($array, Arrays::incrementIndexes($this->simpleArray)); + + $array = [ + 0 => 'Lorem', + 2 => 'ipsum', + 3 => 'dolor', + 4 => 'sit', + 5 => 'amet', + ]; + self::assertEquals($array, Arrays::incrementIndexes($this->simpleArray, 1)); + + $array = [ + 0 => 'Lorem', + 1 => 'ipsum', + 3 => 'dolor', + 4 => 'sit', + 5 => 'amet', + ]; + self::assertEquals($array, Arrays::incrementIndexes($this->simpleArray, 2)); + } + + /** + * @param string $description Description of test case + * @param mixed $value The value to verify + * @param bool $expected Expected information + * + * @dataProvider provideValueToIsEmptyArray + */ + public function testIsEmptyArray(string $description, $value, bool $expected): void + { + self::assertSame($expected, Arrays::isEmptyArray($value), $description); + } + + /** + * @param string $description + * @param bool $expected + * @param array $array + * @param $element + * @param bool $firstLevelOnly + * + * @dataProvider provideIsFirstElement + */ + public function testIsFirstElement( + string $description, + bool $expected, + array $array, + $element, + ?bool $firstLevelOnly = null + ): void { + if (null === $firstLevelOnly) { + static::assertSame($expected, Arrays::isFirstElement($array, $element), $description); + + return; + } + + static::assertSame($expected, Arrays::isFirstElement($array, $element, $firstLevelOnly), $description); + } + + /** + * @param string $description + * @param bool $expected + * @param array $array + * @param $element + * @param null|bool $firstLevelOnly + * + * @dataProvider provideIsLastElement + */ + public function testIsLastElement( + string $description, + bool $expected, + array $array, + $element, + ?bool $firstLevelOnly = null + ): void { + if (null === $firstLevelOnly) { + static::assertSame($expected, Arrays::isLastElement($array, $element), $description); + + return; + } + + static::assertSame($expected, Arrays::isLastElement($array, $element, $firstLevelOnly), $description); + } + + public function testIsMultiDimensional() + { + // Negative cases + self::assertNull(Arrays::isMultiDimensional([])); + + // Positive cases + self::assertFalse(Arrays::isMultiDimensional($this->simpleArray)); + self::assertFalse(Arrays::isMultiDimensional($this->simpleArrayWithKeys)); + + self::assertTrue(Arrays::isMultiDimensional($this->twoDimensionsArray)); + self::assertTrue(Arrays::isMultiDimensional($this->complexArray)); + } + + /** + * @param string $description Description of test case + * @param mixed $value The value to verify + * @param bool $expected Expected information + * + * @dataProvider provideValueToIsNotEmptyArray + */ + public function testIsNotEmptyArray(string $description, $value, bool $expected): void + { + self::assertSame($expected, Arrays::isNotEmptyArray($value), $description); + } + + public function testIssetRecursive() + { + // Negative cases + self::assertFalse(Arrays::issetRecursive([], [])); + + // Positive cases + $unExistingKeys = [ + 'a', + 'b', + 3, + ]; + + $existingKeys = [ + 'simpleArray' => [ + 1, 3, 4, ], - [ - 1 => 0, - 2 => 1, - 3 => 2, - 4 => 3, - ], - ]; - - yield[ - [ - 'Lorem', - 'ipsum', + 'simpleArrayWithKeys' => [ 'dolor', - 'sit', 'amet', ], - [ - 'Lorem' => 0, - 'ipsum' => 1, - 'dolor' => 2, - 'sit' => 3, - 'amet' => 4, + 'twoDimensionsArray' => [ + 2, + 3, + ], + 'complexArray' => [ + 'sit', + 'aliquet', + 'vitae', ], ]; + + self::assertFalse(Arrays::issetRecursive($this->simpleArray, $unExistingKeys)); + self::assertTrue(Arrays::issetRecursive($this->simpleArray, $existingKeys['simpleArray'])); + + self::assertFalse(Arrays::issetRecursive($this->simpleArrayWithKeys, $unExistingKeys)); + self::assertTrue(Arrays::issetRecursive($this->simpleArrayWithKeys, $existingKeys['simpleArrayWithKeys'])); + + self::assertFalse(Arrays::issetRecursive($this->twoDimensionsArray, $unExistingKeys)); + self::assertTrue(Arrays::issetRecursive($this->twoDimensionsArray, $existingKeys['twoDimensionsArray'])); + + self::assertFalse(Arrays::issetRecursive($this->complexArray, $unExistingKeys)); + self::assertTrue(Arrays::issetRecursive($this->complexArray, $existingKeys['complexArray'])); } - /** - * Provides an array with duplicated values to set/replace values with keys - * - * @return \Generator - */ - public function provideArrayWithDuplicatedValuesToSetKeysAsValues() + public function testKsortRecursive() { - yield[ - [ - 'lorem' => 'ipsum', - 'dolor' => 'ipsum', - 'sit' => 'amet', - 'diam' => 'non', - 'elit' => 'non', - 'in' => 'non', - ], - [ - 'ipsum' => [ - 'lorem', - 'dolor', - ], - 'amet' => 'sit', - 'non' => [ - 'diam', - 'elit', - 'in', - ], - ], - ]; + // Negative cases + $array = []; + self::assertNull(Arrays::ksortRecursive($array)); - yield[ - [ - 'lorem' => [ - 'diam' => 'non', - 'elit' => 'non', - 'in' => 'non', - ], - 'dolor1' => 'ipsum', - 'dolor2' => 'ipsum', - 'sit' => 'amet', - ], - [ - 'lorem' => [ - 'non' => [ - 'diam', - 'elit', - 'in', - ], - ], - 'ipsum' => [ - 'dolor1', - 'dolor2', - ], - 'amet' => 'sit', - ], - ]; - } + // Positive cases + self::assertEquals($this->simpleArray, Arrays::ksortRecursive($this->simpleArray)); + self::assertEquals($this->simpleArray, Arrays::ksortRecursive($this->simpleArray, SORT_NUMERIC)); + self::assertEquals($this->twoDimensionsArray, Arrays::ksortRecursive($this->twoDimensionsArray)); - /** - * Provides patterns of keys or paths that matched will stop the process and the expected array for the - * getLastElementsPaths() method - * - * @return Generator - */ - public function provideStopIfMatchedByForGetLastElementsPaths(): ?Generator - { - // Special exception: do not use, stop recursive on the "diam" key - yield[ - ['diam'], - '.', - [ - 'ipsum.quis.vestibulum.porta-1.0' => 'turpis', - 'ipsum.quis.vestibulum.porta-1.1' => 'urna', - 'ipsum.quis.vestibulum.porta-2.tortor.in.0' => 'dui', - 'ipsum.quis.vestibulum.porta-2.tortor.in.dolor.0' => 'aliquam', - 'ipsum.quis.vestibulum.porta-3.0' => 1, - 'ipsum.quis.vestibulum.porta-3.1' => 2, - 'ipsum.quis.vestibulum.porta-3.2' => 3, - 'primis.0.0' => 'in', - 'primis.0.1' => 'faucibus', - 'primis.0.2' => 'orci', - 'primis.1.0' => 'luctus', - 'primis.1.1' => 'et', - 'primis.1.2' => 'ultrices', - ], - ]; - - /* - * Stop building of paths on these keys: - * - "tortor" - * - "primis" - */ - yield[ - [ - 'tortor', + // Positive case - multi-dimensions array + $effect = [ + 'amet' => [ + 'iaculis', 'primis', ], - ' . ', - [ - 'ipsum . quis . vestibulum . porta-1 . 0' => 'turpis', - 'ipsum . quis . vestibulum . porta-1 . 1' => 'urna', - 'ipsum . quis . vestibulum . porta-2 . tortor' => [ - 'in' => [ - 'dui', - 'dolor' => [ - 'aliquam', - ], - ], - ], - 'ipsum . quis . vestibulum . porta-3 . 0' => 1, - 'ipsum . quis . vestibulum . porta-3 . 1' => 2, - 'ipsum . quis . vestibulum . porta-3 . 2' => 3, - 'primis' => [ - [ - 'in', - 'faucibus', - 'orci', - ], - [ - 'luctus', - 'et', - 'ultrices', + 'consectetur' => 'adipiscing', + 'lorem' => [ + 'ipsum' => [ + 'dolor' => 'sit', + 'diam' => [ + 'non' => 'egestas', ], ], ], - ]; - - // Stop building of paths on more sophisticated keys - yield[ - [ - 'porta\-\d+', - '^\d+$', - ], - ' > ', - [ - 'ipsum > quis > vestibulum > porta-1' => [ - 'turpis', - 'urna', - ], - 'ipsum > quis > vestibulum > porta-2' => [ - 'tortor' => [ - 'in' => [ - 'dui', - 'dolor' => [ - 'aliquam', - ], - ], - ], - ], - 'ipsum > quis > vestibulum > porta-3' => [ - 1, - 2, - 3, - ], - 'primis > 0' => [ - 'in', - 'faucibus', - 'orci', - ], - 'primis > 1' => [ - 'luctus', - 'et', - 'ultrices', - ], - ], - ]; - - /* - * Stop building of paths on these: - * - keys - * and - * - paths (verify paths too) - */ - yield[ - [ - 'porta-1', - 'porta-2 > tortor > in', - ], - ' > ', - [ - 'ipsum > quis > vestibulum > porta-1' => [ - 'turpis', - 'urna', - ], - 'ipsum > quis > vestibulum > porta-2 > tortor > in' => [ - 'dui', - 'dolor' => [ - 'aliquam', - ], - ], - 'ipsum > quis > vestibulum > porta-3 > 0' => 1, - 'ipsum > quis > vestibulum > porta-3 > 1' => 2, - 'ipsum > quis > vestibulum > porta-3 > 2' => 3, - 'primis > 0 > 0' => 'in', - 'primis > 0 > 1' => 'faucibus', - 'primis > 0 > 2' => 'orci', - 'primis > 1 > 0' => 'luctus', - 'primis > 1 > 1' => 'et', - 'primis > 1 > 2' => 'ultrices', - ], - ]; - - // Stop building of paths on these paths (verify paths only) - yield[ - [ - 'ipsum > quis > vestibulum > porta-1', - 'ipsum > quis > vestibulum > porta-2 > tortor', - 'primis > 1', - ], - ' > ', - [ - 'ipsum > quis > vestibulum > porta-1' => [ - 'turpis', - 'urna', - ], - 'ipsum > quis > vestibulum > porta-2 > tortor' => [ - 'in' => [ - 'dui', - 'dolor' => [ - 'aliquam', - ], - ], - ], - 'ipsum > quis > vestibulum > porta-3 > 0' => 1, - 'ipsum > quis > vestibulum > porta-3 > 1' => 2, - 'ipsum > quis > vestibulum > porta-3 > 2' => 3, - 'primis > 0 > 0' => 'in', - 'primis > 0 > 1' => 'faucibus', - 'primis > 0 > 2' => 'orci', - 'primis > 1' => [ - 'luctus', - 'et', - 'ultrices', - ], - ], - ]; - - // Stop building of paths if path contains any of these part (verify part of paths only) - yield[ - [ - 'vestibulum > porta-1', - 'tortor > in', - '[a-z]+ > \d+', - ], - ' > ', - [ - 'ipsum > quis > vestibulum > porta-1' => [ - 'turpis', - 'urna', - ], - 'ipsum > quis > vestibulum > porta-2 > tortor > in' => [ - 'dui', - 'dolor' => [ - 'aliquam', - ], - ], - 'ipsum > quis > vestibulum > porta-3 > 0' => 1, - 'ipsum > quis > vestibulum > porta-3 > 1' => 2, - 'ipsum > quis > vestibulum > porta-3 > 2' => 3, - 'primis > 0' => [ - 'in', - 'faucibus', - 'orci', - ], - 'primis > 1' => [ - 'luctus', - 'et', - 'ultrices', - ], - ], - ]; - } - - /** - * Provide values to filter and get non-empty values - * - * @return Generator - */ - public function provideValuesToFilterNonEmpty(): ?Generator - { - $simpleObject = new SimpleToString('1234'); - - yield[ - 'All values are empty', - [ - '', - null, - [], - ], - [], - ]; - - yield[ - '5 values with 2 empty strings', - [ - 'test 1', - '', - 'test 2', - 'test 3', - '', - ], - [ - 0 => 'test 1', - 2 => 'test 2', - 3 => 'test 3', - ], - ]; - - yield[ - '"0" shouldn\'t be treated like an empty value', - [ - 123, - 0, - 456, - ], - [ - 123, - 0, - 456, - ], - ]; - - yield[ - 'Object shouldn\'t be treated like an empty value', - [ - 'test 1', - $simpleObject, - 'test 2', - null, - 'test 3', - ], - [ - 0 => 'test 1', - 1 => $simpleObject, - 2 => 'test 2', - 4 => 'test 3', - ], - ]; - - yield[ - 'Mixed values (non-empty, empty, strings, integers, objects)', - [ - 'test 1', - '', - 123, - null, - 'test 2', - 'test 3', - 0, - $simpleObject, - 456, - [], - $simpleObject, - ], - [ - 0 => 'test 1', - 2 => 123, - 4 => 'test 2', - 5 => 'test 3', - 6 => 0, - 7 => $simpleObject, - 8 => 456, - 10 => $simpleObject, - ], - ]; - } - - /** - * Provide values to filter and get non-empty values concatenated by default separator - * - * @return \Generator - */ - public function provideValuesToFilterNonEmptyAsStringUsingDefaultSeparator() - { - yield[ - 'An empty array (no values to filter)', - [], - null, - ]; - - yield[ - 'All values are empty', - [ - '', - null, - [], - ], - '', - ]; - - yield[ - '5 values with 2 empty strings', - [ - 'test 1', - '', - 'test 2', - 'test 3', - '', - ], - 'test 1, test 2, test 3', - ]; - - yield[ - 'Numbers with "0" that shouldn\'t be treated like an empty value', - [ - 123, - 0, - 456, - ], - '123, 0, 456', - ]; - - yield[ - 'Object shouldn\'t be treated like an empty value', - [ - 'test 1', - new SimpleToString('1234'), - 'test 2', - null, - 'test 3', - ], - 'test 1, Instance with ID: 1234, test 2, test 3', - ]; - - yield[ - 'Mixed values (non-empty, empty, strings, integers, objects)', - [ - 'test 1', - '', - 123, - null, - 'test 2', - 'test 3', - 0, - new SimpleToString('A1XC90Z'), - 456, - [], - new SimpleToString('FF-45-0Z'), - ], - 'test 1, 123, test 2, test 3, 0, Instance with ID: A1XC90Z, 456, Instance with ID: FF-45-0Z', - ]; - } - - /** - * Provide values to filter and get non-empty values concatenated by given separator - * - * @return \Generator - */ - public function provideValuesToFilterNonEmptyAsString() - { - yield[ - 'An empty array (no values to filter)', - [], - ' | ', - null, - ]; - - yield[ - 'All values are empty', - [ - '', - null, - [], - ], - ' | ', - '', - ]; - - yield[ - '5 values with 2 empty strings', - [ - 'test 1', - '', - 'test 2', - 'test 3', - '', - ], - ' | ', - 'test 1 | test 2 | test 3', - ]; - - yield[ - 'Numbers with "0" that shouldn\'t be treated like an empty value', - [ - 123, - 0, - 456, - ], - ' <-> ', - '123 <-> 0 <-> 456', - ]; - - yield[ - 'Object shouldn\'t be treated like an empty value', - [ - 'test 1', - new SimpleToString('1234'), - 'test 2', - null, - 'test 3', - ], - ' | ', - 'test 1 | Instance with ID: 1234 | test 2 | test 3', - ]; - - yield[ - 'Mixed values (non-empty, empty, strings, integers, objects)', - [ - 'test 1', - '', - 123, - null, - 'test 2', - 'test 3', - 0, - new SimpleToString('A1XC90Z'), - 456, - [], - new SimpleToString('FF-45-0Z'), - ], - ';', - 'test 1;123;test 2;test 3;0;Instance with ID: A1XC90Z;456;Instance with ID: FF-45-0Z', - ]; - } - - public function provideArrayValuesKeysConverted2string() - { - yield[ - 'An empty array', - null, - [], - ]; - - yield[ - 'Empty string and null as value', - 'test_1=,test_2=,test_3=3', - [ - 'test_1' => null, - 'test_2' => '', - 'test_3' => '3', - ], - ]; - - yield[ - 'Empty string and null as value (with custom separators)', - 'test_1="" test_2="" test_3="3"', - [ - 'test_1' => null, - 'test_2' => '', - 'test_3' => '3', - ], - ' ', - '=', - '"', - ]; - - yield[ - 'Empty string as key', - '1=test_1,=test_2,3=test_3', - [ - 1 => 'test_1', - '' => 'test_2', - '3' => 'test_3', - ], - ]; - - yield[ - 'Empty string as key (with custom separators)', - '1 => "test_1"; => "test_2"; 3 => "test_3"', - [ - 1 => 'test_1', - '' => 'test_2', - '3' => 'test_3', - ], - '; ', - ' => ', - '"', - ]; - - yield[ - 'Mixed types of keys and values', - 'test_1=test test,test_2=2,test_3=3.45', - [ - 'test_1' => 'test test', - 'test_2' => 2, - 'test_3' => 3.45, - ], - ]; - - yield[ - 'Mixed types of keys and values (with custom separators)', - 'test_1 --> *test test* | test_2 --> *2* | test_3 --> *3.45*', - [ - 'test_1' => 'test test', - 'test_2' => 2, - 'test_3' => 3.45, - ], - ' | ', - ' --> ', - '*', - ]; - } - - public function provideArrayValues2csv(): ?Generator - { - yield[ - 'An empty array', - null, - [], - ]; - - yield[ - 'Empty string, and empty array and null as row', - "1,2,3\n5,6,", - [ - 'test_1' => '', - 'test_2' => [], - 'test_3' => null, - 'test_4' => [ - 'aa' => 1, - 'bb' => 2, - 'cc' => 3, - ], - [ - 'dd' => 5, - 'ee' => 6, - 'ff' => '', - ], - ], - ]; - - yield[ - 'Empty string, and empty array and null as row (with custom separator)', - "1, 2, 3\n5, 6, ", - [ - 'test_1' => '', - 'test_2' => [], - 'test_3' => null, - 'test_4' => [ - 'aa' => 1, - 'bb' => 2, - 'cc' => 3, - ], - [ - 'dd' => 5, - 'ee' => 6, - 'ff' => '', - ], - ], - ', ', - ]; - - yield[ - 'Empty string as key, non-array as value', - "1,2,3\n5,6,", - [ - '' => 'test_1', - 1 => 'test_2', - '3' => [ - 'aa' => 1, - 'bb' => 2, - 'cc' => 3, - ], - [ - 'dd' => 5, - 'ee' => 6, - 'ff' => '', - ], - ], - ]; - - yield[ - 'Empty string as key, non-array as value (with custom separator)', - "1 | 2 | 3\n5 | 6 | ", - [ - '' => 'test_1', - 1 => 'test_2', - '3' => [ - 'aa' => 1, - 'bb' => 2, - 'cc' => 3, - ], - [ - 'dd' => 5, - 'ee' => 6, - 'ff' => '', - ], - ], - ' | ', - ]; - - yield[ - 'Invalid structure, not like database table', - "1,2,3\n5,6\n7,8,9,10", - [ - [ - 'aa' => 1, - 'bb' => 2, - 'cc' => 3, - ], - [ - 'dd' => 5, - 'ee' => 6, - ], - [ - 7, - 8, - 9, - 10, - ], - ], - ]; - - yield[ - 'Invalid structure, not like database table (with custom separator)', - "1 <-> 2 <-> 3\n5 <-> 6\n7 <-> 8 <-> 9 <-> 10", - [ - [ - 'aa' => 1, - 'bb' => 2, - 'cc' => 3, - ], - [ - 'dd' => 5, - 'ee' => 6, - ], - [ - 7, - 8, - 9, - 10, - ], - ], - ' <-> ', - ]; - - yield[ - 'Mixed types of keys and values', - "1,2,3.45\n5,6,\n7,8,9,,10", - [ - [ - 'aa' => 1, - 'bb' => 2, - 'cc' => 3.45, - ], - [ - 'dd' => 5, - 'ee' => 6, - null, - ], - [ - 7, - 8, - 'qq' => 9, - '', - 10, - ], - ], - ]; - - yield[ - 'Mixed types of keys and values (with custom separator)', - "1 // 2 // 3.45\n5 // 6 // \n7 // 8 // 9 // // 10", - [ - [ - 'aa' => 1, - 'bb' => 2, - 'cc' => 3.45, - ], - [ - 'dd' => 5, - 'ee' => 6, - null, - ], - [ - 7, - 8, - 'qq' => 9, - '', - 10, - ], - ], - ' // ', - ]; - - yield[ - 'With HTML code', - "
abc
,def,
ghi
\nc,d", - [ - [ - '<div>abc</div>', - 'def', - '<div>ghi</div>', - ], - [ - 'c', - 'd', - ], - ], - ]; - } - - public function provideArrayValues2string() - { - yield[ - 'An empty array', - null, - [], - ]; - - yield[ - 'Simple array', - 'Test 1,Test 2,Test 3', - [ - 1 => 'Test 1', - 2 => 'Test 2', - 3 => 'Test 3', - ], - ]; - - yield[ - 'Simple array (with custom separator)', - 'Test 1.Test 2.Test 3', - [ - 1 => 'Test 1', - 2 => 'Test 2', - 3 => 'Test 3', - ], - '', - '.', - ]; - - yield[ - 'Simple array (concrete column)', - 'Test 2', - [ - 1 => 'Test 1', - 2 => 'Test 2', - 3 => 'Test 3', - ], - 2, - ]; - - yield[ - 'Simple array (concrete column with custom separator)', - 'Test 2', - [ - 1 => 'Test 1', - 2 => 'Test 2', - 3 => 'Test 3', - ], - 2, - '.', - ]; - - yield[ - 'Complex array', - '1,2,3,test 1,test 2,test 3,,test 4,,bbb,3.45', - [ - [ - 1, - 2, - 3, - ], - [ - 'test 1', - 'test 2', - [ - 'test 3', - '', - 'test 4', - ], - ], - [], - [ - 'a' => '', - 'b' => 'bbb', - [], - 'c' => 3.45, - ], - ], - ]; - - yield[ - '1st complex array (concrete column)', - '2,test 2,', - [ - [ - 1, - 2, - 3, - ], - [ - 'test 1', - 'test 2', - [ - 'test 3', - '', - 'test 4', - ], - ], - [], - [ - 'a' => '', - 'b' => 'bbb', - [], - 'c' => 3.45, - ], - ], - 1, - ]; - - yield[ - '2nd complex array (concrete column)', - 'bb,1234,0xb', - [ - [ - 1, - 2, - 3, - ], - [ - 'a' => 'aa', - 'b' => 'bb', - 'c' => 'cc', - ], - [ - 'a', - 'b', - 'c', - ], - [ - 'a' => '', - 'b' => 1234, - ], - [ - 'c' => 5678, - 'b' => '0xb', - ], - ], - 'b', - ]; - - yield[ - '3rd complex array (concrete column with custom separator)', - 'bb - 1234 - 3xb - bbb', - [ - [ - 1, - 2, - 3, - ], - [ - 'a' => 'aa', - 'b' => 'bb', - 'c' => 'cc', - ], - [ - 'a', - 'b' => [], - 'c', - ], - [ - 'a' => '', - 'b' => 1234, - ], - [ - 'c' => 5678, - 'b' => [ - 'b1' => '0xb', - 'b2' => '1xb', - 'b' => '3xb', - ], - [ - 1, - 2, - 'a' => 'aaa', - 'b' => 'bbb', - ], - ], - ], - 'b', - ' - ', - ]; - } - - public function provideArrayToQuoteStrings() - { - yield[ - 'An empty array', - null, - [], - ]; - - yield[ - 'Simple array', - [ - 1, - 2, - 3, - '\'1\'', - '\'2\'', - ], - [ - 1, - 2, - 3, - '1', - '2', - ], - ]; - - yield[ - 'Complex array', - [ - 123, - '\'456\'', - [ - 'x' => [ - 0, - '\'0\'', - 1 => '\'1\'', - 2 => 2, - ], - '\'y\'', - ], - 444 => '\'\'', - [ - [ - [ - '\'test\'', - ], - ], - ], - ], - [ - 123, - '456', - [ - 'x' => [ - 0, - '0', - 1 => '1', - 2 => 2, - ], - 'y', - ], - 444 => '', - [ - [ - [ - 'test', - ], - ], - ], - ], - ]; - } - - public function provideValueToIsEmptyArray(): ?Generator - { - yield[ - 'An empty string', - '', - false, - ]; - - yield[ - 'Non-empty string', - 'test', - false, - ]; - - yield[ - 'Null', - null, - false, - ]; - - yield[ - 'An integer equals 0', - 1234, - false, - ]; - - yield[ - 'An integer greater than 0', - 1234, - false, - ]; - - yield[ - 'An empty array', - [], - true, - ]; - - yield[ - 'Non-empty array', - [ - 'test', - ], - false, - ]; - } - - public function provideValueToIsNotEmptyArray(): ?Generator - { - yield[ - 'An empty string', - '', - false, - ]; - - yield[ - 'Non-empty string', - 'test', - false, - ]; - - yield[ - 'Null', - null, - false, - ]; - - yield[ - 'An integer equals 0', - 1234, - false, - ]; - - yield[ - 'An integer greater than 0', - 1234, - false, - ]; - - yield[ - 'An empty array', - [], - false, - ]; - - yield[ - 'Non-empty array', - [ - 'test', - ], - true, - ]; - } - - public function provideArrayToRemoveMarginalElement(): Generator - { - yield[ - 'An empty array - remove last element', - [], - true, - null, - ]; - - yield[ - 'An empty array - remove first element', - [], - false, - null, - ]; - - yield[ - 'One-dimensional array - remove last element', - [ - 'Lorem', - 'ipsum', - 'dolor', - 'sit', - 'amet', - ], - true, - [ - 0 => 'Lorem', - 1 => 'ipsum', - 2 => 'dolor', - 3 => 'sit', - ], - ]; - - yield[ - 'One-dimensional array - remove first element', - [ - 'Lorem', - 'ipsum', - 'dolor', - 'sit', - 'amet', - ], - false, - [ - 1 => 'ipsum', - 2 => 'dolor', - 3 => 'sit', - 4 => 'amet', - ], - ]; - - yield[ - 'Multi-dimensional array - remove last element', - [ - 'lorem' => [ - 'ipsum' => [ - 'dolor' => 'sit', - 'diam' => [ - 'non' => 'egestas', - ], - ], - ], - 'consectetur' => 'adipiscing', - 'mollis' => 1234, - 2 => [], - 'sit' => [ - 'nullam' => 'donec', - 'aliquet' => [ - 'vitae' => [ - 'ligula' => 'quis', - ], - ], - 'elit', - ], - 'amet' => [ - 'iaculis', - 'primis', - ], - ], - true, - [ - 'lorem' => [ - 'ipsum' => [ - 'dolor' => 'sit', - 'diam' => [ - 'non' => 'egestas', - ], - ], - ], - 'consectetur' => 'adipiscing', - 'mollis' => 1234, - 2 => [], - 'sit' => [ - 'nullam' => 'donec', - 'aliquet' => [ - 'vitae' => [ - 'ligula' => 'quis', - ], - ], - 'elit', - ], - ], - ]; - - yield[ - 'Multi-dimensional array - remove first element', - [ - 'lorem' => [ - 'ipsum' => [ - 'dolor' => 'sit', - 'diam' => [ - 'non' => 'egestas', - ], - ], - ], - 'consectetur' => 'adipiscing', - 'mollis' => 1234, - 2 => [], - 'sit' => [ - 'nullam' => 'donec', - 'aliquet' => [ - 'vitae' => [ - 'ligula' => 'quis', - ], - ], - 'elit', - ], - 'amet' => [ - 'iaculis', - 'primis', - ], - ], - false, - [ - 'consectetur' => 'adipiscing', - 'mollis' => 1234, - 2 => [], - 'sit' => [ - 'nullam' => 'donec', - 'aliquet' => [ - 'vitae' => [ - 'ligula' => 'quis', - ], - ], - 'elit', - ], - 'amet' => [ - 'iaculis', - 'primis', - ], - ], - ]; - } - - public function provideArrayToReplaceKeys(): Generator - { - yield[ - 'An empty array', - [], - '', - '', - null, - ]; - - yield[ - '1st case', - [ - 'nullam' => 'donec', + 'mollis' => 1234, + 'sit' => [ + 'nullam' => 'donec', 'aliquet' => [ 'vitae' => [ 'ligula' => 'quis', @@ -3107,795 +3367,535 @@ letsTest[2] = value_2;'; ], 'elit', ], - '|.*li.*|', - 'x', - [ + 2 => [], + ]; + + self::assertEquals($effect, Arrays::ksortRecursive($this->complexArray)); + + // Positive case - multi-dimensions array - with options of ksort() function + $effect = [ + 2 => [], + 'amet' => [ + 'iaculis', + 'primis', + ], + 'consectetur' => 'adipiscing', + 'lorem' => [ + 'ipsum' => [ + 'dolor' => 'sit', + 'diam' => [ + 'non' => 'egestas', + ], + ], + ], + 'mollis' => 1234, + 'sit' => [ 'nullam' => 'donec', - 'x' => [ + 'aliquet' => [ 'vitae' => [ - 'x' => 'quis', + 'ligula' => 'quis', ], ], 'elit', ], ]; - yield[ - '2nd case', + self::assertEquals($effect, Arrays::ksortRecursive($this->complexArray, SORT_STRING & SORT_NATURAL)); + } + + public function testMakeArray(): void + { + self::assertSame($this->simpleArray, Arrays::makeArray($this->simpleArray)); + self::assertSame(['test'], Arrays::makeArray('test')); + } + + /** + * @param string $description Description of test case + * @param null|array $expected Expected new array (with quoted elements) + * @param array $array The array to check for string values + * + * @dataProvider provideArrayToQuoteStrings + */ + public function testQuoteStrings(string $description, ?array $expected, array $array): void + { + self::assertSame($expected, Arrays::quoteStrings($array), $description); + } + + public function testRemoveElement() + { + self::assertFalse(Arrays::removeElement($this->simpleArray, 'eeee')); + self::assertTrue(is_array(Arrays::removeElement($this->simpleArray, 'Lorem'))); + + Arrays::removeElement($this->simpleArray, 'amet'); + self::assertFalse(isset($this->simpleArray['amet'])); + } + + public function testRemoveElements(): void + { + $array1 = $this->simpleArray; + $array2 = $this->simpleArray; + + Arrays::removeElements($array1, 'ipsum'); + self::assertSame([ + 1 => 'ipsum', + 2 => 'dolor', + 3 => 'sit', + 4 => 'amet', + ], $array1); + + Arrays::removeElements($array2, 'sit', false); + self::assertSame([ + 0 => 'Lorem', + 1 => 'ipsum', + 2 => 'dolor', + 3 => 'sit', + ], $array2); + + Arrays::removeElements($this->complexArray['lorem'], 'sit', false); + self::assertSame(['ipsum' => ['dolor' => 'sit']], $this->complexArray['lorem']); + } + + /** + * @param string $description Description of test case + * @param array $array The array which should be shortened + * @param bool $last If is set to true, last element is removed (default behaviour). Otherwise - first. + * @param null|array $expected Expected result + * + * @dataProvider provideArrayToRemoveMarginalElement + */ + public function testRemoveMarginalElement(string $description, array $array, bool $last, ?array $expected): void + { + self::assertSame($expected, Arrays::removeMarginalElement($array, $last), $description); + } + + /** + * @param string $description Description of test case + * @param array $array Array which keys should be replaced + * @param string $oldKeyPattern Regular expression of the old key + * @param string $newKey Name of the new key + * @param array $expected Expected result + * + * @dataProvider provideArrayToReplaceKeys + */ + public function testReplaceKeys( + string $description, + array $array, + string $oldKeyPattern, + string $newKey, + ?array $expected + ): void { + self::assertSame($expected, Arrays::replaceKeys($array, $oldKeyPattern, $newKey), $description); + } + + /** + * @param array $array The array to change values with keys + * @param array $replaced The array with replaced values with keys + * + * @dataProvider provideArrayWithDuplicatedValuesToSetKeysAsValues + */ + public function testSetKeysAsValuesDuplicatedValues($array, $replaced) + { + self::assertEquals($replaced, Arrays::setKeysAsValues($array, false)); + } + + public function testSetKeysAsValuesEmptyArray() + { + self::assertNull(Arrays::setKeysAsValues([])); + } + + public function testSetKeysAsValuesSameKeysValues() + { + $array = [ + 0, + 1, + 2, + 3, + ]; + + self::assertEquals($array, Arrays::setKeysAsValues($array)); + } + + /** + * @param array $array The array to change values with keys + * @param array $replaced The array with replaced values with keys + * + * @dataProvider provideSimpleArrayToSetKeysAsValues + */ + public function testSetKeysAsValuesSimpleArray($array, $replaced) + { + self::assertEquals($replaced, Arrays::setKeysAsValues($array)); + } + + public function testSetKeysAsValuesTwoDimensionsArray() + { + $replaced = [ [ - 'Lorem', - 'ipsum', + 'lorem' => 0, + 'ipsum' => 1, + 'dolor' => 2, + 'sit' => 3, + 'amet' => 4, + ], + [ + 'consectetur' => 0, + 'adipiscing' => 1, + 'elit' => 2, + ], + [ + 'donec' => 0, + 'sagittis' => 1, + 'fringilla' => 2, + 'eleifend' => 3, + ], + ]; + + self::assertEquals($replaced, Arrays::setKeysAsValues($this->twoDimensionsArray)); + } + + public function testSetPositions() + { + // Negative cases + self::assertNull(Arrays::setPositions([])); + + // Positive case - 1-dimension array + $array = [ + 'abc', + ]; + + self::assertEquals($array, Arrays::setPositions($array)); + + // Positive case - 2-dimensions array + $effect = $this->twoDimensionsArray; + $effect[0][Arrays::POSITION_KEY_NAME] = 1; + $effect[1][Arrays::POSITION_KEY_NAME] = 2; + $effect[2][Arrays::POSITION_KEY_NAME] = 3; + + self::assertEquals($effect, Arrays::setPositions($this->twoDimensionsArray)); + + // Positive case - multidimensional array + $array = [ + 'lorem', + 'ipsum' => [ 'dolor', 'sit', - 'amet', ], - '|[0-3]+|', - 'x', - [ - 'x' => 'sit', - 4 => 'amet', + 'amet' => [ + 'consectetur', + 'adipiscing' => [ + 'elit' => [ + 'cras', + 'quis', + 'ligula', + ], + ], ], ]; + + $effect = [ + 'lorem', + 'ipsum' => [ + 'dolor', + 'sit', + Arrays::POSITION_KEY_NAME => 1, + ], + 'amet' => [ + 'consectetur', + 'adipiscing' => [ + 'elit' => [ + 'cras', + 'quis', + 'ligula', + Arrays::POSITION_KEY_NAME => 1, + ], + Arrays::POSITION_KEY_NAME => 1, + ], + Arrays::POSITION_KEY_NAME => 2, + ], + ]; + + self::assertEquals($effect, Arrays::setPositions($array)); + + // Positive case - non-default name of key with position value & 2-dimensions array + $keyName = 'level'; + $effect = $this->twoDimensionsArray; + + $effect[0][$keyName] = 1; + $effect[1][$keyName] = 2; + $effect[2][$keyName] = 3; + + self::assertEquals($effect, Arrays::setPositions($this->twoDimensionsArray, $keyName)); + + // Positive case - non-default start value of position & 2-dimensions array + $startPosition = 5; + $effect = $this->twoDimensionsArray; + + $effect[Arrays::POSITION_KEY_NAME] = $startPosition; + $effect[0][Arrays::POSITION_KEY_NAME] = 1; + $effect[1][Arrays::POSITION_KEY_NAME] = 2; + $effect[2][Arrays::POSITION_KEY_NAME] = 3; + + self::assertEquals($effect, Arrays::setPositions($this->twoDimensionsArray, Arrays::POSITION_KEY_NAME, $startPosition)); } - public function provideArrayToVerifyIfContainsEmptyStringsOnly(): ?Generator + public function testSortByCustomKeysOrder() { - yield[ - [], - false, + // Negative cases + self::assertNull(Arrays::sortByCustomKeysOrder([], [])); + + // Positive cases + self::assertEquals([0], Arrays::sortByCustomKeysOrder([0], [])); + self::assertEquals($this->simpleArray, Arrays::sortByCustomKeysOrder($this->simpleArray, [])); + + $keysOrder = [ + 'amet', + 'dolor', + 'Lorem', ]; - yield[ - [ - '', - 1, - ], - false, + $sorted = [ + 'dolor' => 'sit', + 'amet' => 'consectetur', + 'Lorem' => 'ipsum', ]; - yield[ - [ - '', - null, - 1, - ], - false, + self::assertEquals($sorted, Arrays::sortByCustomKeysOrder($this->simpleArrayWithKeys, $keysOrder)); + + $array = [ + 'Lorem', + 'ipsum', + 'dolor', + 'sit', + 'amet', ]; - yield[ - [ - '', - null, - ], - true, + $keysOrder = [ + 0, + 3, + 1, + 2, ]; - yield[ - [ - '', - null, - '', - ], - true, + $sorted = [ + 0 => 'Lorem', + 3 => 'sit', + 1 => 'ipsum', + 2 => 'dolor', + 4 => 'amet', ]; + + self::assertEquals($sorted, Arrays::sortByCustomKeysOrder($array, $keysOrder)); + + $array = [ + 'Lorem', + 'ipsum', + 'dolor', + 'sit', + 'amet', + ]; + + $keysOrder = [ + 0, + 3, + ]; + + $sorted = [ + 0 => 'Lorem', + 3 => 'sit', + 1 => 'ipsum', + 2 => 'dolor', + 4 => 'amet', + ]; + + self::assertEquals($sorted, Arrays::sortByCustomKeysOrder($array, $keysOrder)); } - public function provideIsFirstElement(): ?Generator + public function testString2array(): void { - yield[ - 'An empty array (first level only)', - false, - [], - '', + // Negative cases + self::assertNull(Arrays::string2array('')); + + // Positive cases + $array = [ + 'light' => '#fff', + 'dark' => '#000', ]; - yield[ - 'An empty array', - false, - [], - '', - false, + self::assertEquals($array, Arrays::string2array('light:#fff|dark:#000')); + self::assertEquals($array, Arrays::string2array('light: #fff | dark: #000')); + + $array = [ + 'red' => '#f00', + 'green' => '#0f0', + 'blue' => '#00f', ]; - yield[ - 'Non-existing integer in array with integers (first level only)', - false, - [ - 1, - 2, - 3, - ], - 4, - ]; - - yield[ - 'Existing integer in array with integers (first level only)', - true, - [ - 1, - 2, - 3, - ], - 1, - ]; - - yield[ - 'Existing integer in array with integers', - true, - [ - 1, - 2, - 3, - ], - 1, - false, - ]; - - yield[ - 'Non-existing integer in multidimensional array with integers (first level only)', - false, - [ - [ - [ - 1, - 2, - 3, - ], - 4, - ], - 5, - [ - 6, - 7, - [ - 8, - 9, - 10, - ], - ], - ], - 9, - ]; - - yield[ - 'Non-existing integer in multidimensional array with integers', - false, - [ - [ - [ - 1, - 2, - 3, - ], - 4, - ], - 5, - [ - 6, - 7, - [ - 8, - 9, - 10, - ], - ], - ], - 9, - false, - ]; - - yield[ - 'Existing integer in multidimensional array with integers, but first level only checked', - false, - [ - [ - [ - 1, - 2, - 3, - ], - 4, - ], - 5, - [ - 6, - 7, - [ - 8, - 9, - 10, - ], - ], - ], - 1, - ]; - - yield[ - 'Existing integer in multidimensional array with integers', - true, - [ - [ - [ - 1, - 2, - 3, - ], - 4, - ], - 5, - [ - 6, - 7, - [ - 8, - 9, - 10, - ], - ], - ], - 1, - false, - ]; - - yield[ - 'Non-existing element in multidimensional array (first level only)', - false, - [ - [ - [ - 'abc', - 2, - 'def', - ], - 4, - ], - '---', - [ - 'ghi', - 7, - [ - 'jkl', - '...', - 10, - ], - ], - ], - 9, - ]; - - yield[ - 'Existing element in multidimensional array, but first level only checked', - false, - [ - [ - [ - 'abc', - 2, - 'def', - ], - 4, - ], - '---', - [ - 'ghi', - 7, - [ - 'jkl', - '...', - 10, - ], - ], - ], - 'abc', - ]; - - yield[ - 'Existing element in multidimensional array', - true, - [ - [ - [ - 'abc', - 2, - 'def', - ], - 4, - ], - '---', - [ - 'ghi', - 7, - [ - 'jkl', - '...', - 10, - ], - ], - ], - 'abc', - false, - ]; + self::assertEquals($array, Arrays::string2array('red:#f00|green:#0f0|blue:#00f')); + self::assertEquals($array, Arrays::string2array('red: #f00 | green: #0f0 | blue: #00f')); + self::assertEquals($array, Arrays::string2array('red : #f00 | green : #0f0 | blue : #00f')); } - public function provideFirstElement(): ?Generator + public function testTrimRecursive() { - yield[ - 'An empty array (first level only)', - null, - [], - ]; + // Negative cases + self::assertSame([], Arrays::trimRecursive([])); - yield[ - 'An empty array', - null, - [], - false, - ]; + // Positive cases + self::assertEquals(['a'], Arrays::trimRecursive([' a '])); + self::assertEquals([ + 'a', + 'b', + ], Arrays::trimRecursive([ + ' a ', + 'b ', + ])); - yield[ - 'Multidimensional array (first level only)', + $array = [ + 'abc ', [ - [ - 'abc', - 2, - 'def', - ], - 4, - ], - [ - [ - [ - 'abc', - 2, - 'def', - ], - 4, - ], - '---', - [ - 'ghi', - 7, - [ - 'jkl', - '...', - 10, - ], - ], + 'def', + 'ghi ', ], ]; - yield[ - 'Multidimensional array', + $result = [ 'abc', [ - [ - [ - 'abc', - 2, - 'def', - ], - 4, - ], - '---', - [ - 'ghi', - 7, - [ - 'jkl', - '...', - 10, - ], - ], - ], - false, - ]; - } - - public function provideIsLastElement(): ?Generator - { - yield[ - 'An empty array (first level only)', - false, - [], - '', - ]; - - yield[ - 'An empty array', - false, - [], - '', - false, - ]; - - yield[ - 'Non-existing integer in array with integers (first level only)', - false, - [ - 1, - 2, - 3, - ], - 4, - ]; - - yield[ - 'Existing integer in array with integers (first level only)', - true, - [ - 1, - 2, - 3, - ], - 3, - ]; - - yield[ - 'Existing integer in array with integers', - true, - [ - 1, - 2, - 3, - ], - 3, - false, - ]; - - yield[ - 'Non-existing integer in multidimensional array with integers (first level only)', - false, - [ - [ - [ - 1, - 2, - 3, - ], - 4, - ], - 5, - [ - 6, - 7, - [ - 8, - 9, - 10, - ], - ], - ], - 11, - ]; - - yield[ - 'Non-existing integer in multidimensional array with integers', - false, - [ - [ - [ - 1, - 2, - 3, - ], - 4, - ], - 5, - [ - 6, - 7, - [ - 8, - 9, - 10, - ], - ], - ], - 11, - false, - ]; - - yield[ - 'Existing integer in multidimensional array with integers, but first level only checked', - false, - [ - [ - [ - 1, - 2, - 3, - ], - 4, - ], - 5, - [ - 6, - 7, - [ - 8, - 9, - 10, - ], - ], - ], - 10, - ]; - - yield[ - 'Existing integer in multidimensional array with integers', - true, - [ - [ - [ - 1, - 2, - 3, - ], - 4, - ], - 5, - [ - 6, - 7, - [ - 8, - 9, - 10, - ], - ], - ], - 10, - false, - ]; - - yield[ - 'Non-existing element in multidimensional array (first level only)', - false, - [ - [ - [ - 'abc', - 2, - 'def', - ], - 4, - ], - '---', - [ - 'ghi', - 7, - [ - 'jkl', - '...', - 10, - ], - ], - ], - 9, - ]; - - yield[ - 'Existing element in multidimensional array, but first level only checked', - false, - [ - [ - [ - 'abc', - 2, - 'def', - ], - 4, - ], - '---', - [ - 'ghi', - 7, - [ - 10, - '...', - 'jkl', - ], - ], - ], - 'jkl', - ]; - - yield[ - 'Existing element in multidimensional array', - true, - [ - [ - [ - 'abc', - 2, - 'def', - ], - 4, - ], - '---', - [ - 'ghi', - 7, - [ - 10, - '...', - 'jkl', - ], - ], - ], - 'jkl', - false, - ]; - } - - public function provideLastElement(): ?Generator - { - yield[ - 'An empty array (first level only)', - null, - [], - ]; - - yield[ - 'An empty array', - null, - [], - false, - ]; - - yield[ - 'One-dimensional array (first level only)', - 3, - [ - 1, - 2, - 3, - ], - ]; - - yield[ - 'One-dimensional array (first level only)', - 3, - [ - 1, - 2, - 3, - ], - false, - ]; - - yield[ - 'Multidimensional array (first level only)', - [ + 'def', 'ghi', - 7, - [ - 'jkl', - '...', - 10, - ], ], + ]; + + self::assertEquals($result, Arrays::trimRecursive($array)); + + $array = [ + 'abc ', [ - [ - [ - 'abc', - 2, - 'def', - ], - 4, - ], - '---', - [ - 'ghi', - 7, - [ - 'jkl', - '...', - 10, - ], + ' def ', + 'ghi ', + 'oo' => [ + ' ee ', + 'g' => 'h hhh ', ], ], ]; - yield[ - 'Multidimensional array', - 10, + $result = [ + 'abc', [ - [ - [ - 'abc', - 2, - 'def', - ], - 4, - ], - '---', - [ - 'ghi', - 7, - [ - 'jkl', - '...', - 10, - ], + 'def', + 'ghi', + 'oo' => [ + 'ee', + 'g' => 'h hhh', ], ], - false, ]; + + self::assertEquals($result, Arrays::trimRecursive($array)); } - public function provideLastRow(): ?Generator + /** + * @param string $description Description of test + * @param string $expected Expected array converted to csv string + * @param array $array Data to be converted. It have to be an array that represents database table. + * @param string $separator (optional) Separator used between values. Default: ",". + * + * @dataProvider provideArrayValues2csv + */ + public function testValues2csv(string $description, ?string $expected, array $array, string $separator = ','): void { - yield[ - 'An empty array', - null, - [], - ]; + // Required to avoid failure: + // + // Failed asserting that two strings are identical + // 1,2,3.45 - expected + // 1,2,3,45 - actual + Locale::setLocale(LC_ALL, 'en', 'US'); - yield[ - 'One-dimensional array', - [], - [ - 'a', - 'b', - 1, - 2, - ], - ]; + static::assertSame($expected, Arrays::values2csv($array, $separator), $description); + } - yield[ - 'Multidimensional array with scalar as last element', - [], - [ - 'a', - [ - 'b', - 'c', - ], - [ - 'e', - 'f', - ], - 1, - 2, - ], - ]; + /** + * @param string $description Description of test + * @param string $expected Expected array converted to string + * @param array $array Data to be converted + * @param string $arrayColumnKey (optional) Column name. Default: "". + * @param string $separator (optional) Separator used between values. Default: ",". + * + * @dataProvider provideArrayValues2string + */ + public function testValues2string($description, $expected, array $array, $arrayColumnKey = '', $separator = ',') + { + // Required to avoid failure: + // + // Failed asserting that two strings are identical + // 1,2,3,test 1,test 2,test 3,,test 4,,bbb,3.45 - expected + // 1,2,3,test 1,test 2,test 3,,test 4,,bbb,3,45 - actual + Locale::setLocale(LC_ALL, 'en', 'US'); - yield[ - 'Multidimensional array with an empty array as last element', - [], - [ - 'a', - [ - 'b', - 'c', - ], - 1, - 2, - [], - ], - ]; + self::assertSame($expected, Arrays::values2string($array, $arrayColumnKey, $separator), $description); + } - yield[ - 'Multidimensional array', - [ - 'e', - 'f', - ], - [ - 'a', - [ - 'b', - 'c', - ], - 1, - 2, - [ - 'e', - 'f', - ], - ], - ]; + /** + * @param string $description Description of test + * @param string $expected Expected array converted to string + * @param array $array Data to be converted + * @param string $separator (optional) Separator used between name-value pairs. Default: ",". + * @param string $valuesKeysSeparator (optional) Separator used between name and value. Default: "=". + * @param string $valuesWrapper (optional) Wrapper used to wrap values, e.g. double-quote: key="value". + * Default: "". + * + * @dataProvider provideArrayValuesKeysConverted2string + */ + public function testValuesKeys2string( + $description, + $expected, + array $array, + $separator = ',', + $valuesKeysSeparator = '=', + $valuesWrapper = '' + ) { + // Required to avoid failure: + // + // Failed asserting that two strings are identical + // test_1=test test,test_2=2,test_3=3.45 - expected + // test_1=test test,test_2=2,test_3=3,45 - actual + Locale::setLocale(LC_ALL, 'en', 'US'); + + self::assertSame( + $expected, + Arrays::valuesKeys2string($array, $separator, $valuesKeysSeparator, $valuesWrapper), + $description + ); + + self::assertSame( + '0=Lorem,1=ipsum,2=dolor,3=sit,4=amet', + Arrays::valuesKeys2string($this->simpleArray), + 'Simple array' + ); + + self::assertSame( + '0=Lorem;1=ipsum;2=dolor;3=sit;4=amet', + Arrays::valuesKeys2string($this->simpleArray, ';'), + 'Simple array (with custom separator)' + ); + + self::assertSame( + '0=Lorem 1=ipsum 2=dolor 3=sit 4=amet', + Arrays::valuesKeys2string($this->simpleArray, ' '), + 'Simple array (with custom separator)' + ); + + self::assertSame( + '0="Lorem" 1="ipsum" 2="dolor" 3="sit" 4="amet"', + Arrays::valuesKeys2string($this->simpleArray, ' ', '=', '"'), + 'Simple array (with custom separators)' + ); + + self::assertSame( + '0="Lorem", 1="ipsum", 2="dolor", 3="sit", 4="amet"', + Arrays::valuesKeys2string($this->simpleArray, ', ', '=', '"'), + 'Simple array (with custom separators)' + ); } /** @@ -3916,7 +3916,7 @@ letsTest[2] = value_2;'; $this->simpleArrayWithKeys = [ 'Lorem' => 'ipsum', 'dolor' => 'sit', - 'amet' => 'consectetur', + 'amet' => 'consectetur', ]; $this->twoDimensionsArray = [ @@ -3941,19 +3941,19 @@ letsTest[2] = value_2;'; ]; $this->complexArray = [ - 'lorem' => [ + 'lorem' => [ 'ipsum' => [ 'dolor' => 'sit', - 'diam' => [ + 'diam' => [ 'non' => 'egestas', ], ], ], 'consectetur' => 'adipiscing', - 'mollis' => 1234, - 2 => [], - 'sit' => [ - 'nullam' => 'donec', + 'mollis' => 1234, + 2 => [], + 'sit' => [ + 'nullam' => 'donec', 'aliquet' => [ 'vitae' => [ 'ligula' => 'quis', @@ -3961,14 +3961,14 @@ letsTest[2] = value_2;'; ], 'elit', ], - 'amet' => [ + 'amet' => [ 'iaculis', 'primis', ], ]; $this->superComplexArray = [ - 'ipsum' => [ + 'ipsum' => [ 'quis' => [ 'vestibulum' => [ 'porta-1' => [ diff --git a/tests/Utilities/Bootstrap4CssSelectorTest.php b/tests/Utilities/Bootstrap4CssSelectorTest.php index bda9bc4..98fe708 100644 --- a/tests/Utilities/Bootstrap4CssSelectorTest.php +++ b/tests/Utilities/Bootstrap4CssSelectorTest.php @@ -8,6 +8,7 @@ namespace Meritoo\Test\Common\Utilities; +use Generator; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Utilities\Bootstrap4CssSelector; @@ -18,28 +19,145 @@ use Meritoo\Common\Utilities\Bootstrap4CssSelector; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Utilities\Bootstrap4CssSelector + * @covers \Meritoo\Common\Utilities\Bootstrap4CssSelector */ class Bootstrap4CssSelectorTest extends BaseTestCase { + /** + * Provides name of form and expected selector + * + * @return Generator + */ + public function provideFormNameAndSelector() + { + yield [ + 'test', + 'form[name="test"] .form-group', + ]; + + yield [ + 'test-123-test-456', + 'form[name="test-123-test-456"] .form-group', + ]; + + yield [ + 'test_something_098_different', + 'form[name="test_something_098_different"] .form-group', + ]; + } + + /** + * Provides name of form, name of field and expected selector + * + * @return Generator + */ + public function provideFormNameFieldNameAndSelector() + { + yield [ + 'test', + 'test', + 'form[name="test"] label[for="test"] .invalid-feedback .form-error-message', + ]; + + yield [ + 'test-123-test-456', + 'great-000-field', + 'form[name="test-123-test-456"] label[for="great-000-field"] .invalid-feedback .form-error-message', + ]; + + yield [ + 'test_something_098_different', + 'this-is-the-123789-field', + 'form[name="test_something_098_different"] label[for="this-is-the-123789-field"] .invalid-feedback .form-error-message', + ]; + } + + /** + * Provides name of form, index/position of the field-set and expected selector + * + * @return Generator + */ + public function provideFormNameFieldSetIndexAndSelector() + { + yield [ + 'test', + 0, + 'form[name="test"] fieldset:nth-of-type(0) legend.col-form-label .invalid-feedback .form-error-message', + ]; + + yield [ + 'test-123-test-456', + 1, + 'form[name="test-123-test-456"] fieldset:nth-of-type(1) legend.col-form-label .invalid-feedback .form-error-message', + ]; + + yield [ + 'test_something_098_different', + 1245, + 'form[name="test_something_098_different"] fieldset:nth-of-type(1245) legend.col-form-label .invalid-feedback .form-error-message', + ]; + } + public function testConstructor() { static::assertHasNoConstructor(Bootstrap4CssSelector::class); } + public function testGetFieldErrorContainerSelector() + { + static::assertSame('.invalid-feedback .form-error-message', Bootstrap4CssSelector::getFieldErrorContainerSelector()); + } + + /** + * @param string $formName Name of form (value of the "name" attribute) + * @param string $fieldName Name of field (value of the "name" attribute) + * @param string $expected Expected selector + * + * @dataProvider provideFormNameFieldNameAndSelector + */ + public function testGetFieldErrorSelector($formName, $fieldName, $expected) + { + static::assertSame($expected, Bootstrap4CssSelector::getFieldErrorSelector($formName, $fieldName)); + } + + /** + * @param string $emptyValue Name of field (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetFieldErrorSelectorUsingEmptyFieldName($emptyValue) + { + $formName = 'test'; + static::assertSame('', Bootstrap4CssSelector::getFieldErrorSelector($formName, $emptyValue)); + } + /** * @param string $emptyValue Name of form (value of the "name" attribute) * @dataProvider provideEmptyScalarValue */ - public function testGetRadioButtonErrorSelectorUsingEmptyFormName($emptyValue) + public function testGetFieldErrorSelectorUsingEmptyFormName($emptyValue) { - $fieldSetIndex = 1; - static::assertSame('', Bootstrap4CssSelector::getRadioButtonErrorSelector($emptyValue, $fieldSetIndex)); + $fieldName = 'test'; + static::assertSame('', Bootstrap4CssSelector::getFieldErrorSelector($emptyValue, $fieldName)); } - public function testGetRadioButtonErrorSelectorUsingNegativeFieldSetIndex() + /** + * @param string $formName Name of form (value of the "name" attribute) + * @param string $expected Expected selector + * + * @dataProvider provideFormNameAndSelector + */ + public function testGetFieldGroupSelector($formName, $expected) { - static::assertSame('', Bootstrap4CssSelector::getRadioButtonErrorSelector('test-test', -1)); + static::assertSame($expected, Bootstrap4CssSelector::getFieldGroupSelector($formName)); + } + + /** + * @param string $emptyValue Name of form (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetFieldGroupSelectorUsingEmptyFormName($emptyValue) + { + static::assertSame('', Bootstrap4CssSelector::getFieldGroupSelector($emptyValue)); } /** @@ -58,131 +176,14 @@ class Bootstrap4CssSelectorTest extends BaseTestCase * @param string $emptyValue Name of form (value of the "name" attribute) * @dataProvider provideEmptyScalarValue */ - public function testGetFieldErrorSelectorUsingEmptyFormName($emptyValue) + public function testGetRadioButtonErrorSelectorUsingEmptyFormName($emptyValue) { - $fieldName = 'test'; - static::assertSame('', Bootstrap4CssSelector::getFieldErrorSelector($emptyValue, $fieldName)); + $fieldSetIndex = 1; + static::assertSame('', Bootstrap4CssSelector::getRadioButtonErrorSelector($emptyValue, $fieldSetIndex)); } - /** - * @param string $emptyValue Name of field (value of the "name" attribute) - * @dataProvider provideEmptyScalarValue - */ - public function testGetFieldErrorSelectorUsingEmptyFieldName($emptyValue) + public function testGetRadioButtonErrorSelectorUsingNegativeFieldSetIndex() { - $formName = 'test'; - static::assertSame('', Bootstrap4CssSelector::getFieldErrorSelector($formName, $emptyValue)); - } - - /** - * @param string $formName Name of form (value of the "name" attribute) - * @param string $fieldName Name of field (value of the "name" attribute) - * @param string $expected Expected selector - * - * @dataProvider provideFormNameFieldNameAndSelector - */ - public function testGetFieldErrorSelector($formName, $fieldName, $expected) - { - static::assertSame($expected, Bootstrap4CssSelector::getFieldErrorSelector($formName, $fieldName)); - } - - /** - * @param string $emptyValue Name of form (value of the "name" attribute) - * @dataProvider provideEmptyScalarValue - */ - public function testGetFieldGroupSelectorUsingEmptyFormName($emptyValue) - { - static::assertSame('', Bootstrap4CssSelector::getFieldGroupSelector($emptyValue)); - } - - /** - * @param string $formName Name of form (value of the "name" attribute) - * @param string $expected Expected selector - * - * @dataProvider provideFormNameAndSelector - */ - public function testGetFieldGroupSelector($formName, $expected) - { - static::assertSame($expected, Bootstrap4CssSelector::getFieldGroupSelector($formName)); - } - - public function testGetFieldErrorContainerSelector() - { - static::assertSame('.invalid-feedback .form-error-message', Bootstrap4CssSelector::getFieldErrorContainerSelector()); - } - - /** - * Provides name of form, index/position of the field-set and expected selector - * - * @return \Generator - */ - public function provideFormNameFieldSetIndexAndSelector() - { - yield[ - 'test', - 0, - 'form[name="test"] fieldset:nth-of-type(0) legend.col-form-label .invalid-feedback .form-error-message', - ]; - - yield[ - 'test-123-test-456', - 1, - 'form[name="test-123-test-456"] fieldset:nth-of-type(1) legend.col-form-label .invalid-feedback .form-error-message', - ]; - - yield[ - 'test_something_098_different', - 1245, - 'form[name="test_something_098_different"] fieldset:nth-of-type(1245) legend.col-form-label .invalid-feedback .form-error-message', - ]; - } - - /** - * Provides name of form, name of field and expected selector - * - * @return \Generator - */ - public function provideFormNameFieldNameAndSelector() - { - yield[ - 'test', - 'test', - 'form[name="test"] label[for="test"] .invalid-feedback .form-error-message', - ]; - - yield[ - 'test-123-test-456', - 'great-000-field', - 'form[name="test-123-test-456"] label[for="great-000-field"] .invalid-feedback .form-error-message', - ]; - - yield[ - 'test_something_098_different', - 'this-is-the-123789-field', - 'form[name="test_something_098_different"] label[for="this-is-the-123789-field"] .invalid-feedback .form-error-message', - ]; - } - - /** - * Provides name of form and expected selector - * - * @return \Generator - */ - public function provideFormNameAndSelector() - { - yield[ - 'test', - 'form[name="test"] .form-group', - ]; - - yield[ - 'test-123-test-456', - 'form[name="test-123-test-456"] .form-group', - ]; - - yield[ - 'test_something_098_different', - 'form[name="test_something_098_different"] .form-group', - ]; + static::assertSame('', Bootstrap4CssSelector::getRadioButtonErrorSelector('test-test', -1)); } } diff --git a/tests/Utilities/BundleTest.php b/tests/Utilities/BundleTest.php index 9e665dc..13a74ac 100644 --- a/tests/Utilities/BundleTest.php +++ b/tests/Utilities/BundleTest.php @@ -20,15 +20,174 @@ use Meritoo\Common\Utilities\Bundle; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Utilities\Bundle + * @covers \Meritoo\Common\Utilities\Bundle */ class BundleTest extends BaseTestCase { + /** + * Provides empty path of the view / template and/or name of bundle + * + * @return Generator + */ + public function provideEmptyViewPathAndBundle() + { + yield [ + '', + '', + ]; + + yield [ + 'test', + '', + ]; + + yield [ + '', + 'test', + ]; + } + + /** + * Provides full and short name of bundle + * + * @return Generator + */ + public function provideFullAndShortBundleName() + { + yield [ + 'MyExtraBundle', + 'MyExtra', + ]; + + yield [ + 'MySuperExtraGorgeousBundle', + 'MySuperExtraGorgeous', + ]; + } + + /** + * Provides incorrect name of bundle + * + * @return Generator + */ + public function provideIncorrectBundleName() + { + yield [ + 'myExtra', + ]; + + yield [ + 'MyExtra', + ]; + + yield [ + 'MySuperExtraGorgeous', + ]; + } + + /** + * Provides path of the view / template and name of bundle + * + * @return Generator + */ + public function provideViewPathAndBundle() + { + yield [ + 'User', + 'MyExtraBundle', + '@MyExtra/User.html.twig', + ]; + + yield [ + 'User:Active', + 'MyExtraBundle', + '@MyExtra/User/Active.html.twig', + ]; + + yield [ + 'User:Active', + 'MySuperExtraGorgeousBundle', + '@MySuperExtraGorgeous/User/Active.html.twig', + ]; + } + + /** + * Provides path of the view / template, name of bundle and extension of the view / template + * + * @return Generator + */ + public function provideViewPathAndBundleAndExtension() + { + yield [ + 'User:Active', + 'MyExtraBundle', + '', + null, + ]; + + yield [ + 'User:Active', + 'MyExtraBundle', + 'js.twig', + '@MyExtra/User/Active.js.twig', + ]; + } + + /** + * Provides path of the view / template and incorrect name of bundle + * + * @return Generator + */ + public function provideViewPathAndIncorrectBundleName() + { + yield [ + 'User:Active', + 'myExtra', + ]; + + yield [ + 'User:Active', + 'MyExtra', + ]; + + yield [ + 'User:Active', + 'MySuperExtraGorgeous', + ]; + } + public function testConstructor() { static::assertHasNoConstructor(Bundle::class); } + /** + * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" + * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" + * @param string $extension (optional) Extension of the view / template + * @param string $expected Expected path to view / template + * + * @throws IncorrectBundleNameException + * @dataProvider provideViewPathAndBundleAndExtension + */ + public function testGetBundleViewPathUsingCustomExtension($viewPath, $bundleName, $extension, $expected) + { + self::assertEquals($expected, Bundle::getBundleViewPath($viewPath, $bundleName, $extension)); + } + + /** + * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" + * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" + * @param string $expected Expected path to view / template + * + * @throws IncorrectBundleNameException + * @dataProvider provideViewPathAndBundle + */ + public function testGetBundleViewPathUsingDefaultExtension($viewPath, $bundleName, $expected) + { + self::assertEquals($expected, Bundle::getBundleViewPath($viewPath, $bundleName)); + } + /** * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" @@ -50,7 +209,7 @@ class BundleTest extends BaseTestCase public function testGetBundleViewPathUsingIncorrectBundleName($viewPath, $bundleName) { $template = 'Name of bundle \'%s\' is incorrect. It should start with big letter and end with "Bundle". Is' - . ' there everything ok?'; + .' there everything ok?'; $this->expectException(IncorrectBundleNameException::class); $this->expectExceptionMessage(sprintf($template, $bundleName)); @@ -59,30 +218,15 @@ class BundleTest extends BaseTestCase } /** - * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" - * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" - * @param string $expected Expected path to view / template + * @param string $fullBundleName Full name of the bundle, e.g. "MyExtraBundle" + * @param string $shortBundleName Short name of bundle (without "Bundle") * * @throws IncorrectBundleNameException - * @dataProvider provideViewPathAndBundle + * @dataProvider provideFullAndShortBundleName */ - public function testGetBundleViewPathUsingDefaultExtension($viewPath, $bundleName, $expected) + public function testGetShortBundleName($fullBundleName, $shortBundleName) { - self::assertEquals($expected, Bundle::getBundleViewPath($viewPath, $bundleName)); - } - - /** - * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" - * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" - * @param string $extension (optional) Extension of the view / template - * @param string $expected Expected path to view / template - * - * @throws IncorrectBundleNameException - * @dataProvider provideViewPathAndBundleAndExtension - */ - public function testGetBundleViewPathUsingCustomExtension($viewPath, $bundleName, $extension, $expected) - { - self::assertEquals($expected, Bundle::getBundleViewPath($viewPath, $bundleName, $extension)); + self::assertEquals($shortBundleName, Bundle::getShortBundleName($fullBundleName)); } public function testGetShortBundleNameUsingEmptyValue(): void @@ -102,148 +246,4 @@ class BundleTest extends BaseTestCase $this->expectException(IncorrectBundleNameException::class); Bundle::getShortBundleName($bundleName); } - - /** - * @param string $fullBundleName Full name of the bundle, e.g. "MyExtraBundle" - * @param string $shortBundleName Short name of bundle (without "Bundle") - * - * @throws IncorrectBundleNameException - * @dataProvider provideFullAndShortBundleName - */ - public function testGetShortBundleName($fullBundleName, $shortBundleName) - { - self::assertEquals($shortBundleName, Bundle::getShortBundleName($fullBundleName)); - } - - /** - * Provides empty path of the view / template and/or name of bundle - * - * @return Generator - */ - public function provideEmptyViewPathAndBundle() - { - yield[ - '', - '', - ]; - - yield[ - 'test', - '', - ]; - - yield[ - '', - 'test', - ]; - } - - /** - * Provides path of the view / template and incorrect name of bundle - * - * @return Generator - */ - public function provideViewPathAndIncorrectBundleName() - { - yield[ - 'User:Active', - 'myExtra', - ]; - - yield[ - 'User:Active', - 'MyExtra', - ]; - - yield[ - 'User:Active', - 'MySuperExtraGorgeous', - ]; - } - - /** - * Provides path of the view / template and name of bundle - * - * @return Generator - */ - public function provideViewPathAndBundle() - { - yield[ - 'User', - 'MyExtraBundle', - '@MyExtra/User.html.twig', - ]; - - yield[ - 'User:Active', - 'MyExtraBundle', - '@MyExtra/User/Active.html.twig', - ]; - - yield[ - 'User:Active', - 'MySuperExtraGorgeousBundle', - '@MySuperExtraGorgeous/User/Active.html.twig', - ]; - } - - /** - * Provides path of the view / template, name of bundle and extension of the view / template - * - * @return Generator - */ - public function provideViewPathAndBundleAndExtension() - { - yield[ - 'User:Active', - 'MyExtraBundle', - '', - null, - ]; - - yield[ - 'User:Active', - 'MyExtraBundle', - 'js.twig', - '@MyExtra/User/Active.js.twig', - ]; - } - - /** - * Provides incorrect name of bundle - * - * @return Generator - */ - public function provideIncorrectBundleName() - { - yield[ - 'myExtra', - ]; - - yield[ - 'MyExtra', - ]; - - yield[ - 'MySuperExtraGorgeous', - ]; - } - - /** - * Provides full and short name of bundle - * - * @return Generator - */ - public function provideFullAndShortBundleName() - { - yield[ - 'MyExtraBundle', - 'MyExtra', - ]; - - yield[ - 'MySuperExtraGorgeousBundle', - 'MySuperExtraGorgeous', - ]; - } } diff --git a/tests/Utilities/ComposerTest.php b/tests/Utilities/ComposerTest.php index c4a9252..e1bc69f 100644 --- a/tests/Utilities/ComposerTest.php +++ b/tests/Utilities/ComposerTest.php @@ -19,7 +19,7 @@ use Meritoo\Common\Utilities\Composer; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Utilities\Composer + * @covers \Meritoo\Common\Utilities\Composer */ class ComposerTest extends BaseTestCase { @@ -30,11 +30,40 @@ class ComposerTest extends BaseTestCase */ private $composerJsonPath; + /** + * Provides names and values of existing nodes + * + * @return Generator + */ + public function getExistingNode(): Generator + { + yield [ + 'name', + 'test/test', + ]; + + yield [ + 'version', + '1.0.2', + ]; + } + public function testConstructor() { static::assertHasNoConstructor(Composer::class); } + /** + * @param string $nodeName Name of existing node + * @param string $nodeValue Value of existing node + * + * @dataProvider getExistingNode + */ + public function testGetValueExistingNode(string $nodeName, string $nodeValue): void + { + self::assertEquals($nodeValue, Composer::getValue($this->composerJsonPath, $nodeName)); + } + public function testGetValueNotExistingComposerJson(): void { self::assertNull(Composer::getValue('', '')); @@ -47,35 +76,6 @@ class ComposerTest extends BaseTestCase self::assertNull(Composer::getValue($this->composerJsonPath, 'not_existing_node')); } - /** - * @param string $nodeName Name of existing node - * @param string $nodeValue Value of existing node - * - * @dataProvider getExistingNode - */ - public function testGetValueExistingNode(string $nodeName, string $nodeValue): void - { - self::assertEquals($nodeValue, Composer::getValue($this->composerJsonPath, $nodeName)); - } - - /** - * Provides names and values of existing nodes - * - * @return Generator - */ - public function getExistingNode(): Generator - { - yield[ - 'name', - 'test/test', - ]; - - yield[ - 'version', - '1.0.2', - ]; - } - /** * {@inheritdoc} */ diff --git a/tests/Utilities/CssSelectorTest.php b/tests/Utilities/CssSelectorTest.php index b406891..6f4e3f3 100644 --- a/tests/Utilities/CssSelectorTest.php +++ b/tests/Utilities/CssSelectorTest.php @@ -8,6 +8,7 @@ namespace Meritoo\Test\Common\Utilities; +use Generator; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Utilities\CssSelector; @@ -18,129 +19,152 @@ use Meritoo\Common\Utilities\CssSelector; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Utilities\CssSelector + * @covers \Meritoo\Common\Utilities\CssSelector */ class CssSelectorTest extends BaseTestCase { + /** + * Provides name of form and selector of the form + * + * @return Generator + */ + public function provideFormNameAndSelector() + { + yield [ + 'test', + 'form[name="test"]', + ]; + + yield [ + 'test-123-test-456', + 'form[name="test-123-test-456"]', + ]; + + yield [ + 'test_something_098_different', + 'form[name="test_something_098_different"]', + ]; + } + + /** + * Provides name of form, ID of field and expected selector of label + * + * @return Generator + */ + public function provideFormNameFieldIdAndLabelSelector() + { + yield [ + 'test', + 'test', + 'form[name="test"] label[for="test"]', + ]; + + yield [ + 'test-123-test-456', + 'great-000-field', + 'form[name="test-123-test-456"] label[for="great-000-field"]', + ]; + + yield [ + 'test_something_098_different', + 'this-is-the-123789-field', + 'form[name="test_something_098_different"] label[for="this-is-the-123789-field"]', + ]; + } + + /** + * Provides name of form, ID of field and expected selector + * + * @return Generator + */ + public function provideFormNameFieldIdAndSelector() + { + yield [ + 'test', + 'test', + 'form[name="test"] input#test', + ]; + + yield [ + 'test-123-test-456', + 'great-000-field', + 'form[name="test-123-test-456"] input#great-000-field', + ]; + + yield [ + 'test_something_098_different', + 'this-is-the-123789-field', + 'form[name="test_something_098_different"] input#this-is-the-123789-field', + ]; + } + + /** + * Provides name of form, name of field and expected selector + * + * @return Generator + */ + public function provideFormNameFieldNameAndSelector() + { + yield [ + 'test', + 'test', + 'form[name="test"] input[name="test"]', + ]; + + yield [ + 'test-123-test-456', + 'great-000-field', + 'form[name="test-123-test-456"] input[name="great-000-field"]', + ]; + + yield [ + 'test_something_098_different', + 'this-is-the-123789-field', + 'form[name="test_something_098_different"] input[name="this-is-the-123789-field"]', + ]; + } + + /** + * Provides name of form, index/position of the field-set and expected selector + * + * @return Generator + */ + public function provideFormNameFieldSetIndexAndSelector() + { + yield [ + 'test', + 0, + 'form[name="test"] fieldset:nth-of-type(0)', + ]; + + yield [ + 'test-123-test-456', + 1, + 'form[name="test-123-test-456"] fieldset:nth-of-type(1)', + ]; + + yield [ + 'test_something_098_different', + 1245, + 'form[name="test_something_098_different"] fieldset:nth-of-type(1245)', + ]; + } + public function testConstructor() { static::assertHasNoConstructor(CssSelector::class); } /** - * @param string $emptyValue Name of form (value of the "name" attribute) - * @dataProvider provideEmptyScalarValue - */ - public function testGetFormByNameSelectorUsingEmptyName($emptyValue) - { - static::assertSame('', CssSelector::getFormByNameSelector($emptyValue)); - } - - /** - * @param string $formName Name of form (value of the "name" attribute) - * @param string $expected Expected selector + * @param string $formName Name of form (value of the "name" attribute) + * @param int $fieldSetIndex Index/Position of the field-set + * @param string $expected Expected selector * - * @dataProvider provideFormNameAndSelector + * @dataProvider provideFormNameFieldSetIndexAndSelector */ - public function testGetFormByNameSelector($formName, $expected) + public function testGetFieldSetByIndexSelector($formName, $fieldSetIndex, $expected) { - static::assertSame($expected, CssSelector::getFormByNameSelector($formName)); - } - - /** - * @param string $emptyValue Name of form (value of the "name" attribute) - * @dataProvider provideEmptyScalarValue - */ - public function testGetInputByNameSelectorUsingEmptyFormName($emptyValue) - { - $fieldName = 'test-test'; - static::assertSame('', CssSelector::getInputByNameSelector($emptyValue, $fieldName)); - } - - /** - * @param string $emptyValue Name of field (value of the "name" attribute) - * @dataProvider provideEmptyScalarValue - */ - public function testGetInputByNameSelectorUsingEmptyFieldName($emptyValue) - { - $formName = 'test-test'; - static::assertSame('', CssSelector::getInputByNameSelector($formName, $emptyValue)); - } - - /** - * @param string $formName Name of form (value of the "name" attribute) - * @param string $fieldName Name of field (value of the "name" attribute) - * @param string $expected Expected selector - * - * @dataProvider provideFormNameFieldNameAndSelector - */ - public function testGetInputByNameSelector($formName, $fieldName, $expected) - { - static::assertSame($expected, CssSelector::getInputByNameSelector($formName, $fieldName)); - } - - /** - * @param string $emptyValue Name of form (value of the "name" attribute) - * @dataProvider provideEmptyScalarValue - */ - public function testGetInputByIdSelectorUsingEmptyFormName($emptyValue) - { - $fieldId = 'test-test'; - static::assertSame('', CssSelector::getInputByIdSelector($emptyValue, $fieldId)); - } - - /** - * @param string $emptyValue ID of field (value of the "id" attribute) - * @dataProvider provideEmptyScalarValue - */ - public function testGetInputByIdSelectorUsingEmptyFieldName($emptyValue) - { - $formName = 'test-test'; - static::assertSame('', CssSelector::getInputByIdSelector($formName, $emptyValue)); - } - - /** - * @param string $formName Name of form (value of the "name" attribute) - * @param string $fieldId ID of field (value of the "id" attribute) - * @param string $expected Expected selector - * - * @dataProvider provideFormNameFieldIdAndSelector - */ - public function testGetInputByIdSelector($formName, $fieldId, $expected) - { - static::assertSame($expected, CssSelector::getInputByIdSelector($formName, $fieldId)); - } - - /** - * @param string $emptyValue Name of form (value of the "name" attribute) - * @dataProvider provideEmptyScalarValue - */ - public function testGetLabelSelectorUsingEmptyFormName($emptyValue) - { - $fieldId = 'test-test'; - static::assertSame('', CssSelector::getLabelSelector($emptyValue, $fieldId)); - } - - /** - * @param string $emptyValue ID of field (value of the "id" attribute) - * @dataProvider provideEmptyScalarValue - */ - public function testGetLabelSelectorUsingEmptyFieldId($emptyValue) - { - $formName = 'test-test'; - static::assertSame('', CssSelector::getLabelSelector($formName, $emptyValue)); - } - - /** - * @param string $formName Name of form (value of the "name" attribute) - * @param string $fieldId ID of field (value of the "id" attribute) - * @param string $expected Expected selector - * - * @dataProvider provideFormNameFieldIdAndLabelSelector - */ - public function testGetLabelSelector($formName, $fieldId, $expected) - { - static::assertSame($expected, CssSelector::getLabelSelector($formName, $fieldId)); + static::assertSame($expected, CssSelector::getFieldSetByIndexSelector($formName, $fieldSetIndex)); } /** @@ -159,141 +183,118 @@ class CssSelectorTest extends BaseTestCase } /** - * @param string $formName Name of form (value of the "name" attribute) - * @param int $fieldSetIndex Index/Position of the field-set - * @param string $expected Expected selector + * @param string $formName Name of form (value of the "name" attribute) + * @param string $expected Expected selector * - * @dataProvider provideFormNameFieldSetIndexAndSelector + * @dataProvider provideFormNameAndSelector */ - public function testGetFieldSetByIndexSelector($formName, $fieldSetIndex, $expected) + public function testGetFormByNameSelector($formName, $expected) { - static::assertSame($expected, CssSelector::getFieldSetByIndexSelector($formName, $fieldSetIndex)); + static::assertSame($expected, CssSelector::getFormByNameSelector($formName)); } /** - * Provides name of form and selector of the form - * - * @return \Generator + * @param string $emptyValue Name of form (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue */ - public function provideFormNameAndSelector() + public function testGetFormByNameSelectorUsingEmptyName($emptyValue) { - yield[ - 'test', - 'form[name="test"]', - ]; - - yield[ - 'test-123-test-456', - 'form[name="test-123-test-456"]', - ]; - - yield[ - 'test_something_098_different', - 'form[name="test_something_098_different"]', - ]; + static::assertSame('', CssSelector::getFormByNameSelector($emptyValue)); } /** - * Provides name of form, name of field and expected selector + * @param string $formName Name of form (value of the "name" attribute) + * @param string $fieldId ID of field (value of the "id" attribute) + * @param string $expected Expected selector * - * @return \Generator + * @dataProvider provideFormNameFieldIdAndSelector */ - public function provideFormNameFieldNameAndSelector() + public function testGetInputByIdSelector($formName, $fieldId, $expected) { - yield[ - 'test', - 'test', - 'form[name="test"] input[name="test"]', - ]; - - yield[ - 'test-123-test-456', - 'great-000-field', - 'form[name="test-123-test-456"] input[name="great-000-field"]', - ]; - - yield[ - 'test_something_098_different', - 'this-is-the-123789-field', - 'form[name="test_something_098_different"] input[name="this-is-the-123789-field"]', - ]; + static::assertSame($expected, CssSelector::getInputByIdSelector($formName, $fieldId)); } /** - * Provides name of form, ID of field and expected selector of label - * - * @return \Generator + * @param string $emptyValue ID of field (value of the "id" attribute) + * @dataProvider provideEmptyScalarValue */ - public function provideFormNameFieldIdAndLabelSelector() + public function testGetInputByIdSelectorUsingEmptyFieldName($emptyValue) { - yield[ - 'test', - 'test', - 'form[name="test"] label[for="test"]', - ]; - - yield[ - 'test-123-test-456', - 'great-000-field', - 'form[name="test-123-test-456"] label[for="great-000-field"]', - ]; - - yield[ - 'test_something_098_different', - 'this-is-the-123789-field', - 'form[name="test_something_098_different"] label[for="this-is-the-123789-field"]', - ]; + $formName = 'test-test'; + static::assertSame('', CssSelector::getInputByIdSelector($formName, $emptyValue)); } /** - * Provides name of form, index/position of the field-set and expected selector - * - * @return \Generator + * @param string $emptyValue Name of form (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue */ - public function provideFormNameFieldSetIndexAndSelector() + public function testGetInputByIdSelectorUsingEmptyFormName($emptyValue) { - yield[ - 'test', - 0, - 'form[name="test"] fieldset:nth-of-type(0)', - ]; - - yield[ - 'test-123-test-456', - 1, - 'form[name="test-123-test-456"] fieldset:nth-of-type(1)', - ]; - - yield[ - 'test_something_098_different', - 1245, - 'form[name="test_something_098_different"] fieldset:nth-of-type(1245)', - ]; + $fieldId = 'test-test'; + static::assertSame('', CssSelector::getInputByIdSelector($emptyValue, $fieldId)); } /** - * Provides name of form, ID of field and expected selector + * @param string $formName Name of form (value of the "name" attribute) + * @param string $fieldName Name of field (value of the "name" attribute) + * @param string $expected Expected selector * - * @return \Generator + * @dataProvider provideFormNameFieldNameAndSelector */ - public function provideFormNameFieldIdAndSelector() + public function testGetInputByNameSelector($formName, $fieldName, $expected) { - yield[ - 'test', - 'test', - 'form[name="test"] input#test', - ]; + static::assertSame($expected, CssSelector::getInputByNameSelector($formName, $fieldName)); + } - yield[ - 'test-123-test-456', - 'great-000-field', - 'form[name="test-123-test-456"] input#great-000-field', - ]; + /** + * @param string $emptyValue Name of field (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetInputByNameSelectorUsingEmptyFieldName($emptyValue) + { + $formName = 'test-test'; + static::assertSame('', CssSelector::getInputByNameSelector($formName, $emptyValue)); + } - yield[ - 'test_something_098_different', - 'this-is-the-123789-field', - 'form[name="test_something_098_different"] input#this-is-the-123789-field', - ]; + /** + * @param string $emptyValue Name of form (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetInputByNameSelectorUsingEmptyFormName($emptyValue) + { + $fieldName = 'test-test'; + static::assertSame('', CssSelector::getInputByNameSelector($emptyValue, $fieldName)); + } + + /** + * @param string $formName Name of form (value of the "name" attribute) + * @param string $fieldId ID of field (value of the "id" attribute) + * @param string $expected Expected selector + * + * @dataProvider provideFormNameFieldIdAndLabelSelector + */ + public function testGetLabelSelector($formName, $fieldId, $expected) + { + static::assertSame($expected, CssSelector::getLabelSelector($formName, $fieldId)); + } + + /** + * @param string $emptyValue ID of field (value of the "id" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetLabelSelectorUsingEmptyFieldId($emptyValue) + { + $formName = 'test-test'; + static::assertSame('', CssSelector::getLabelSelector($formName, $emptyValue)); + } + + /** + * @param string $emptyValue Name of form (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetLabelSelectorUsingEmptyFormName($emptyValue) + { + $fieldId = 'test-test'; + static::assertSame('', CssSelector::getLabelSelector($emptyValue, $fieldId)); } } diff --git a/tests/Utilities/DateTest.php b/tests/Utilities/DateTest.php index a827eb0..8bd70d0 100644 --- a/tests/Utilities/DateTest.php +++ b/tests/Utilities/DateTest.php @@ -24,141 +24,369 @@ use Meritoo\Common\Utilities\Locale; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Utilities\Date + * @covers \Meritoo\Common\Utilities\Date */ class DateTest extends BaseTestCase { + /** + * Provides correct period + * + * @return Generator + */ + public function provideCorrectPeriod() + { + yield [ + DatePeriod::LAST_WEEK, + new DatePeriod( + (new DateTime('this week'))->sub(new DateInterval('P7D'))->setTime(0, 0, 0), + (new DateTime('this week'))->sub(new DateInterval('P1D'))->setTime(23, 59, 59) + ), + ]; + + yield [ + DatePeriod::THIS_WEEK, + new DatePeriod( + (new DateTime('this week'))->setTime(0, 0, 0), + (new DateTime('this week'))->add(new DateInterval('P6D'))->setTime(23, 59, 59) + ), + ]; + + yield [ + DatePeriod::NEXT_WEEK, + new DatePeriod( + (new DateTime('this week'))->add(new DateInterval('P7D'))->setTime(0, 0, 0), + (new DateTime('this week'))->add(new DateInterval('P7D')) + ->add(new DateInterval('P6D')) + ->setTime(23, 59, 59) + ), + ]; + + yield [ + DatePeriod::LAST_MONTH, + new DatePeriod( + (new DateTime('first day of last month'))->setTime(0, 0, 0), + (new DateTime('last day of last month'))->setTime(23, 59, 59) + ), + ]; + + yield [ + DatePeriod::THIS_MONTH, + new DatePeriod( + Date::getDatesForPeriod(DatePeriod::LAST_MONTH) + ->getEndDate() + ->add(new DateInterval('P1D')) + ->setTime(0, 0, 0), + Date::getDatesForPeriod(DatePeriod::NEXT_MONTH) + ->getStartDate() + ->sub(new DateInterval('P1D')) + ->setTime(23, 59, 59) + ), + ]; + + yield [ + DatePeriod::NEXT_MONTH, + new DatePeriod( + (new DateTime('first day of next month'))->setTime(0, 0, 0), + (new DateTime('last day of next month'))->setTime(23, 59, 59) + ), + ]; + + $lastYearStart = (new DateTime())->modify('-1 year'); + $lastYearEnd = (new DateTime())->modify('-1 year'); + $year = $lastYearStart->format('Y'); + + yield [ + DatePeriod::LAST_YEAR, + new DatePeriod( + $lastYearStart->setDate($year, 1, 1)->setTime(0, 0, 0), + $lastYearEnd->setDate($year, 12, 31)->setTime(23, 59, 59) + ), + ]; + + $year = (new DateTime())->format('Y'); + + yield [ + DatePeriod::THIS_YEAR, + new DatePeriod( + (new DateTime())->setDate($year, 1, 1)->setTime(0, 0, 0), + (new DateTime())->setDate($year, 12, 31)->setTime(23, 59, 59) + ), + ]; + + $nextYearStart = (new DateTime())->modify('1 year'); + $nextYearEnd = (new DateTime())->modify('1 year'); + $year = $nextYearStart->format('Y'); + + yield [ + DatePeriod::NEXT_YEAR, + new DatePeriod( + $nextYearStart->setDate($year, 1, 1)->setTime(0, 0, 0), + $nextYearEnd->setDate($year, 12, 31)->setTime(23, 59, 59) + ), + ]; + } + + /** + * Provides data for the random date + * + * @return Generator + */ + public function provideDataOfRandomDate() + { + yield [ + new DateTime('2000-01-01'), + 1, + 100, + ]; + + yield [ + new DateTime('2000-12-01'), + 1, + 100, + ]; + yield [ + new DateTime('2000-01-01'), + '1', + '100', + ]; + + yield [ + new DateTime('2000-12-01'), + '1', + '100', + ]; + + yield [ + new DateTime('2000-01-01'), + 10, + 50, + ]; + + yield [ + new DateTime('2000-12-01'), + 10, + 50, + ]; + } + + /** + * Provides data for the random date with incorrect end of random partition + * + * @return Generator + */ + public function provideDataOfRandomDateIncorrectEnd() + { + yield [ + new DateTime('2000-01-01'), + 100, + 1, + ]; + } + + /** + * Provide empty dates for date difference + * + * @return Generator + */ + public function provideEmptyDatesForDateDifference() + { + yield [ + null, + null, + ]; + + yield [ + '', + '', + ]; + + yield [ + null, + new DateTime(), + ]; + + yield [ + new DateTime(), + null, + ]; + } + + /** + * Provides incorrect invalidCount of DateTime + * + * @return Generator + */ + public function provideIncorrectDateTimeValue() + { + // Incorrect one-character values + yield ['a']; + yield ['m']; + + // Incorrect strings + yield ['ss']; + yield ['sss']; + yield ['mm']; + yield ['yy']; + yield ['yyyy']; + + // Incorrect integer values + yield [1]; + yield [10]; + yield [15]; + yield [100]; + yield [1000]; + + // Incorrect string / numeric values + yield ['1']; + yield ['10']; + yield ['15']; + yield ['100']; + yield ['1000']; + + // Incorrect dates + yield ['0-0-0']; + yield ['20-01-01']; + yield ['2015-0-0']; + yield ['2015-00-00']; + yield ['2015-16-01']; + } + + /** + * Provides incorrect period + * + * @return Generator + */ + public function provideIncorrectPeriod() + { + yield [-1]; + yield [0]; + yield [10]; + } + + /** + * Provides incorrect values of year, month and day + * + * @return Generator + */ + public function provideIncorrectYearMonthDay(): Generator + { + yield [ + 0, + 0, + 0, + ]; + + yield [ + -1, + -1, + -1, + ]; + + yield [ + 5000, + 50, + 50, + ]; + + yield [ + 2000, + 13, + 01, + ]; + + yield [ + 2000, + 01, + 40, + ]; + } + + /** + * Provides invalid format of date + * + * @return Generator + */ + public function provideInvalidDateFormats() + { + yield [0]; + yield [9]; + yield ['[]']; + yield ['invalid']; + yield ['Q']; + yield [',']; + yield ['.']; + yield ['aa###']; + yield ['Y/m/d H:i:invalid']; + } + + /** + * Provides values of year, month and day + * + * @return Generator + */ + public function provideYearMonthDay() + { + yield [ + 2000, + 01, + 01, + ]; + + yield [ + 2000, + 1, + 1, + ]; + + yield [ + 2000, + 2, + 2, + ]; + + yield [ + 2000, + 6, + 1, + ]; + + yield [ + 2000, + 12, + 01, + ]; + + yield [ + 2000, + 12, + 1, + ]; + + yield [ + 2000, + 12, + 31, + ]; + } + public function testConstructor(): void { static::assertHasNoConstructor(Date::class); } - /** - * @param mixed $value Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testGetDateTimeEmptyValue($value): void + public function testGenerateRandomTimeCustomFormat(): void { - self::assertFalse(Date::getDateTime($value)); + self::assertRegExp('/^0[1-9]{1}|1[0-2]{1}$/', Date::generateRandomTime('h')); // 01 through 12 + self::assertRegExp('/^[0-5]?[0-9]$/', Date::generateRandomTime('i')); // 00 through 59 + self::assertRegExp('/^[0-5]?[0-9]$/', Date::generateRandomTime('s')); // 00 through 59 + + self::assertRegExp('/^\d{2}:\d{2}$/', Date::generateRandomTime('H:i')); + self::assertRegExp('/^[1-9]|1[0-2]:\d{2}$/', Date::generateRandomTime('g:i')); } - /** - * @param mixed $value Incorrect source of DateTime - * @dataProvider provideIncorrectDateTimeValue - */ - public function testGetDateTimeIncorrectValue($value): void + public function testGenerateRandomTimeDefaultFormat(): void { - self::assertFalse(Date::getDateTime($value)); - } - - /** - * @param bool $value The value which maybe is a date - * @dataProvider provideBooleanValue - */ - public function testGetDateTimeBoolean($value): void - { - self::assertFalse(Date::getDateTime($value)); - } - - /** - * @param string $relativeFormat Relative / compound format of DateTime - * @dataProvider provideDateTimeRelativeFormat - */ - public function testGetDateTimeRelativeFormats($relativeFormat): void - { - /* - * Values based on relative / compound formats, but... without explicitly declaring them as compound - * (2nd argument set to false by default) - * - * http://php.net/manual/en/datetime.formats.compound.php - */ - self::assertFalse(Date::getDateTime($relativeFormat)); - - /* - * Values based on relative / compound formats - * http://php.net/manual/en/datetime.formats.compound.php - */ - self::assertInstanceOf(DateTime::class, Date::getDateTime($relativeFormat, true)); - } - - /** - * @param DateTime $dateTime Instance of DateTime class - * @dataProvider provideDateTimeInstance - */ - public function testGetDateTimeInstanceDateTime(DateTime $dateTime): void - { - self::assertInstanceOf(DateTime::class, Date::getDateTime($dateTime)); - } - - public function testGetDateTimeConcreteDates(): void - { - // Using the standard date format provided by the tested method - self::assertInstanceOf(DateTime::class, Date::getDateTime('2015-03-20')); - - // Using custom date format - self::assertInstanceOf(DateTime::class, Date::getDateTime('2015-03-20 11:30', false, 'Y-m-d H:i')); - self::assertInstanceOf(DateTime::class, Date::getDateTime('20.03.2015', false, 'd.m.Y')); - } - - /** - * @param mixed $value Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testIsValidDateEmptyDates($value): void - { - self::assertFalse(Date::isValidDate($value)); - } - - /** - * @param mixed $value Incorrect source of DateTime - * @dataProvider provideIncorrectDateTimeValue - */ - public function testIsValidDateIncorrectDates($value): void - { - self::assertFalse(Date::isValidDate($value)); - } - - public function testIsValidDateValidDates(): void - { - self::assertTrue(Date::isValidDate('2017-01-01')); - self::assertTrue(Date::isValidDate('2017-01-01 10:30', true)); - self::assertTrue(Date::isValidDate('2017-01-01 14:00', true)); - - self::assertTrue(Date::isValidDate(new DateTime())); - self::assertTrue(Date::isValidDate(new DateTime('now'))); - self::assertTrue(Date::isValidDate(new DateTime('tomorrow'))); - self::assertTrue(Date::isValidDate(new DateTime('m'))); - } - - /** - * @param mixed $value Empty source of date format - * @dataProvider provideEmptyValue - */ - public function testIsValidDateFormatEmptyFormats($value): void - { - self::assertFalse(Date::isValidDateFormat($value)); - } - - /** - * @param mixed $format Invalid format of date - * @dataProvider provideInvalidDateFormats - */ - public function testIsValidDateFormatInvalidFormats($format): void - { - self::assertFalse(Date::isValidDateFormat($format)); - } - - public function testIsValidDateFormatValidFormats(): void - { - self::assertTrue(Date::isValidDateFormat('Y')); - self::assertTrue(Date::isValidDateFormat('yy')); - self::assertTrue(Date::isValidDateFormat('M')); - self::assertTrue(Date::isValidDateFormat('i')); - self::assertTrue(Date::isValidDateFormat('l')); - self::assertTrue(Date::isValidDateFormat('l, d F')); - self::assertTrue(Date::isValidDateFormat('Y-m-d')); - self::assertTrue(Date::isValidDateFormat('H:i:s')); - self::assertTrue(Date::isValidDateFormat('Y/m/d H:i:s')); + self::assertRegExp('/\d{2}:\d{2}:\d{2}/', Date::generateRandomTime()); } /** @@ -178,24 +406,9 @@ class DateTest extends BaseTestCase self::assertNull(Date::generateRandomTime('?')); } - public function testGenerateRandomTimeDefaultFormat(): void - { - self::assertRegExp('/\d{2}:\d{2}:\d{2}/', Date::generateRandomTime()); - } - - public function testGenerateRandomTimeCustomFormat(): void - { - self::assertRegExp('/^0[1-9]{1}|1[0-2]{1}$/', Date::generateRandomTime('h')); // 01 through 12 - self::assertRegExp('/^[0-5]?[0-9]$/', Date::generateRandomTime('i')); // 00 through 59 - self::assertRegExp('/^[0-5]?[0-9]$/', Date::generateRandomTime('s')); // 00 through 59 - - self::assertRegExp('/^\d{2}:\d{2}$/', Date::generateRandomTime('H:i')); - self::assertRegExp('/^[1-9]|1[0-2]:\d{2}$/', Date::generateRandomTime('g:i')); - } - public function testGetCurrentDayOfWeek(): void { - self::assertRegExp('/^[0-6]{1}$/', (string)Date::getCurrentDayOfWeek()); + self::assertRegExp('/^[0-6]{1}$/', (string) Date::getCurrentDayOfWeek()); } public function testGetCurrentDayOfWeekName(): void @@ -221,31 +434,6 @@ class DateTest extends BaseTestCase self::assertRegExp($pattern, Date::getCurrentDayOfWeekName()); } - /** - * @param int $year The year value - * @param int $month The month value - * @param int $day The day value - * - * @dataProvider provideIncorrectYearMonthDay - */ - public function testGetDayOfWeekIncorrectValues(int $year, int $month, int $day): void - { - $this->expectException(UnknownDatePartTypeException::class); - self::assertEmpty(Date::getDayOfWeek($year, $month, $day)); - } - - /** - * @param int $year The year value - * @param int $month The month value - * @param int $day The day value - * - * @dataProvider provideYearMonthDay - */ - public function testGetDayOfWeek(int $year, int $month, int $day): void - { - self::assertRegExp('/^[0-6]{1}$/', (string)Date::getDayOfWeek($year, $month, $day)); - } - /** * @param DateTime|string $dateStart The start date * @param DateTime|string $dateEnd The end date @@ -257,12 +445,173 @@ class DateTest extends BaseTestCase self::assertNull(Date::getDateDifference($dateStart, $dateEnd)); } + public function testGetDateDifferenceEqual24Hours(): void + { + $dateStart = '2017-01-01 00:00'; + $dateEnd = '2017-01-02 00:00'; + + $effect = [ + Date::DATE_DIFFERENCE_UNIT_YEARS => 0, + Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, + Date::DATE_DIFFERENCE_UNIT_DAYS => 1, + Date::DATE_DIFFERENCE_UNIT_HOURS => 0, + Date::DATE_DIFFERENCE_UNIT_MINUTES => 0, + ]; + + self::assertEquals($effect, Date::getDateDifference($dateStart, $dateEnd)); + self::assertEquals($effect, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd))); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_YEARS)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_YEARS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MONTHS)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MONTHS)); + + self::assertEquals(1, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_DAYS)); + self::assertEquals(1, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_DAYS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_HOURS)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_HOURS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MINUTES)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); + } + public function testGetDateDifferenceInvalidDates(): void { self::assertNull(Date::getDateDifference('2017-01-40', '2017-13-01')); self::assertNull(Date::getDateDifference('xyz', 'lorem')); } + public function testGetDateDifferenceInvertedDates(): void + { + $dateStart = '2017-01-02 10:00'; + $dateEnd = '2017-01-01 16:00'; + + $effect = [ + Date::DATE_DIFFERENCE_UNIT_YEARS => 0, + Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, + Date::DATE_DIFFERENCE_UNIT_DAYS => -1, + Date::DATE_DIFFERENCE_UNIT_HOURS => 6, + Date::DATE_DIFFERENCE_UNIT_MINUTES => 0, + ]; + + self::assertEquals($effect, Date::getDateDifference($dateStart, $dateEnd)); + self::assertEquals($effect, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd))); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_YEARS)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_YEARS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MONTHS)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MONTHS)); + + self::assertEquals(-1, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_DAYS)); + self::assertEquals(-1, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_DAYS)); + + self::assertEquals(6, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_HOURS)); + self::assertEquals(6, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_HOURS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MINUTES)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); + } + + public function testGetDateDifferenceLessThan24Hours(): void + { + $dateStart = '2017-01-01 16:00'; + $dateEnd = '2017-01-02 10:00'; + + $effect = [ + Date::DATE_DIFFERENCE_UNIT_YEARS => 0, + Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, + Date::DATE_DIFFERENCE_UNIT_DAYS => 0, + Date::DATE_DIFFERENCE_UNIT_HOURS => 18, + Date::DATE_DIFFERENCE_UNIT_MINUTES => 0, + ]; + + self::assertEquals($effect, Date::getDateDifference($dateStart, $dateEnd)); + self::assertEquals($effect, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd))); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_YEARS)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_YEARS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MONTHS)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MONTHS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_DAYS)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_DAYS)); + + self::assertEquals(18, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_HOURS)); + self::assertEquals(18, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_HOURS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MINUTES)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); + } + + public function testGetDateDifferenceNewYear(): void + { + $dateStart = '2017-12-31 23:59'; + $dateEnd = '2018-01-01 00:00'; + + $effect = [ + Date::DATE_DIFFERENCE_UNIT_YEARS => 0, + Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, + Date::DATE_DIFFERENCE_UNIT_DAYS => 0, + Date::DATE_DIFFERENCE_UNIT_HOURS => 0, + Date::DATE_DIFFERENCE_UNIT_MINUTES => 1, + ]; + + self::assertEquals($effect, Date::getDateDifference($dateStart, $dateEnd)); + self::assertEquals($effect, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd))); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_YEARS)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_YEARS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MONTHS)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MONTHS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_DAYS)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_DAYS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_HOURS)); + self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_HOURS)); + + self::assertEquals(1, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MINUTES)); + self::assertEquals(1, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); + } + + public function testGetDateDifferenceNoDifference(): void + { + // No difference + $dateStart = '2017-01-01 12:00'; + $dateEnd = $dateStart; + + $effect = [ + Date::DATE_DIFFERENCE_UNIT_YEARS => 0, + Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, + Date::DATE_DIFFERENCE_UNIT_DAYS => 0, + Date::DATE_DIFFERENCE_UNIT_HOURS => 0, + Date::DATE_DIFFERENCE_UNIT_MINUTES => 0, + ]; + + self::assertEquals($effect, Date::getDateDifference($dateStart, $dateEnd)); + self::assertEquals($effect, Date::getDateDifference(new DateTime(), new DateTime())); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_YEARS)); + self::assertEquals(0, Date::getDateDifference(new DateTime(), new DateTime(), Date::DATE_DIFFERENCE_UNIT_YEARS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MONTHS)); + self::assertEquals(0, Date::getDateDifference(new DateTime(), new DateTime(), Date::DATE_DIFFERENCE_UNIT_MONTHS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_DAYS)); + self::assertEquals(0, Date::getDateDifference(new DateTime(), new DateTime(), Date::DATE_DIFFERENCE_UNIT_DAYS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_HOURS)); + self::assertEquals(0, Date::getDateDifference(new DateTime(), new DateTime(), Date::DATE_DIFFERENCE_UNIT_HOURS)); + + self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MINUTES)); + self::assertEquals(0, Date::getDateDifference(new DateTime(), new DateTime(), Date::DATE_DIFFERENCE_UNIT_MINUTES)); + } + public function testGetDateDifferenceOneDay(): void { // Difference of 1 day @@ -270,10 +619,10 @@ class DateTest extends BaseTestCase $dateEnd = '2017-01-02'; $effect = [ - Date::DATE_DIFFERENCE_UNIT_YEARS => 0, - Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, - Date::DATE_DIFFERENCE_UNIT_DAYS => 1, - Date::DATE_DIFFERENCE_UNIT_HOURS => 0, + Date::DATE_DIFFERENCE_UNIT_YEARS => 0, + Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, + Date::DATE_DIFFERENCE_UNIT_DAYS => 1, + Date::DATE_DIFFERENCE_UNIT_HOURS => 0, Date::DATE_DIFFERENCE_UNIT_MINUTES => 0, ]; @@ -297,10 +646,10 @@ class DateTest extends BaseTestCase // Difference of 1 day (using the relative date format) $effect = [ - Date::DATE_DIFFERENCE_UNIT_YEARS => 0, - Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, - Date::DATE_DIFFERENCE_UNIT_DAYS => 1, - Date::DATE_DIFFERENCE_UNIT_HOURS => 0, + Date::DATE_DIFFERENCE_UNIT_YEARS => 0, + Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, + Date::DATE_DIFFERENCE_UNIT_DAYS => 1, + Date::DATE_DIFFERENCE_UNIT_HOURS => 0, Date::DATE_DIFFERENCE_UNIT_MINUTES => 0, ]; @@ -318,10 +667,10 @@ class DateTest extends BaseTestCase $dateEnd = '2017-01-02 14:15'; $effect = [ - Date::DATE_DIFFERENCE_UNIT_YEARS => 0, - Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, - Date::DATE_DIFFERENCE_UNIT_DAYS => 1, - Date::DATE_DIFFERENCE_UNIT_HOURS => 2, + Date::DATE_DIFFERENCE_UNIT_YEARS => 0, + Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, + Date::DATE_DIFFERENCE_UNIT_DAYS => 1, + Date::DATE_DIFFERENCE_UNIT_HOURS => 2, Date::DATE_DIFFERENCE_UNIT_MINUTES => 15, ]; @@ -351,10 +700,10 @@ class DateTest extends BaseTestCase $dateEnd = '2017-02-11 16:30'; $effect = [ - Date::DATE_DIFFERENCE_UNIT_YEARS => 0, - Date::DATE_DIFFERENCE_UNIT_MONTHS => 1, - Date::DATE_DIFFERENCE_UNIT_DAYS => 41, - Date::DATE_DIFFERENCE_UNIT_HOURS => 4, + Date::DATE_DIFFERENCE_UNIT_YEARS => 0, + Date::DATE_DIFFERENCE_UNIT_MONTHS => 1, + Date::DATE_DIFFERENCE_UNIT_DAYS => 41, + Date::DATE_DIFFERENCE_UNIT_HOURS => 4, Date::DATE_DIFFERENCE_UNIT_MINUTES => 30, ]; @@ -377,186 +726,71 @@ class DateTest extends BaseTestCase self::assertEquals(30, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); } - public function testGetDateDifferenceNewYear(): void + /** + * @param bool $value The value which maybe is a date + * @dataProvider provideBooleanValue + */ + public function testGetDateTimeBoolean($value): void { - $dateStart = '2017-12-31 23:59'; - $dateEnd = '2018-01-01 00:00'; - - $effect = [ - Date::DATE_DIFFERENCE_UNIT_YEARS => 0, - Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, - Date::DATE_DIFFERENCE_UNIT_DAYS => 0, - Date::DATE_DIFFERENCE_UNIT_HOURS => 0, - Date::DATE_DIFFERENCE_UNIT_MINUTES => 1, - ]; - - self::assertEquals($effect, Date::getDateDifference($dateStart, $dateEnd)); - self::assertEquals($effect, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd))); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_YEARS)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_YEARS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MONTHS)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MONTHS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_DAYS)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_DAYS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_HOURS)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_HOURS)); - - self::assertEquals(1, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MINUTES)); - self::assertEquals(1, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); + self::assertFalse(Date::getDateTime($value)); } - public function testGetDateDifferenceLessThan24Hours(): void + public function testGetDateTimeConcreteDates(): void { - $dateStart = '2017-01-01 16:00'; - $dateEnd = '2017-01-02 10:00'; + // Using the standard date format provided by the tested method + self::assertInstanceOf(DateTime::class, Date::getDateTime('2015-03-20')); - $effect = [ - Date::DATE_DIFFERENCE_UNIT_YEARS => 0, - Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, - Date::DATE_DIFFERENCE_UNIT_DAYS => 0, - Date::DATE_DIFFERENCE_UNIT_HOURS => 18, - Date::DATE_DIFFERENCE_UNIT_MINUTES => 0, - ]; - - self::assertEquals($effect, Date::getDateDifference($dateStart, $dateEnd)); - self::assertEquals($effect, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd))); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_YEARS)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_YEARS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MONTHS)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MONTHS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_DAYS)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_DAYS)); - - self::assertEquals(18, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_HOURS)); - self::assertEquals(18, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_HOURS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MINUTES)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); - } - - public function testGetDateDifferenceEqual24Hours(): void - { - $dateStart = '2017-01-01 00:00'; - $dateEnd = '2017-01-02 00:00'; - - $effect = [ - Date::DATE_DIFFERENCE_UNIT_YEARS => 0, - Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, - Date::DATE_DIFFERENCE_UNIT_DAYS => 1, - Date::DATE_DIFFERENCE_UNIT_HOURS => 0, - Date::DATE_DIFFERENCE_UNIT_MINUTES => 0, - ]; - - self::assertEquals($effect, Date::getDateDifference($dateStart, $dateEnd)); - self::assertEquals($effect, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd))); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_YEARS)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_YEARS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MONTHS)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MONTHS)); - - self::assertEquals(1, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_DAYS)); - self::assertEquals(1, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_DAYS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_HOURS)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_HOURS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MINUTES)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); - } - - public function testGetDateDifferenceInvertedDates(): void - { - $dateStart = '2017-01-02 10:00'; - $dateEnd = '2017-01-01 16:00'; - - $effect = [ - Date::DATE_DIFFERENCE_UNIT_YEARS => 0, - Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, - Date::DATE_DIFFERENCE_UNIT_DAYS => -1, - Date::DATE_DIFFERENCE_UNIT_HOURS => 6, - Date::DATE_DIFFERENCE_UNIT_MINUTES => 0, - ]; - - self::assertEquals($effect, Date::getDateDifference($dateStart, $dateEnd)); - self::assertEquals($effect, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd))); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_YEARS)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_YEARS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MONTHS)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MONTHS)); - - self::assertEquals(-1, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_DAYS)); - self::assertEquals(-1, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_DAYS)); - - self::assertEquals(6, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_HOURS)); - self::assertEquals(6, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_HOURS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MINUTES)); - self::assertEquals(0, Date::getDateDifference(new DateTime($dateStart), new DateTime($dateEnd), Date::DATE_DIFFERENCE_UNIT_MINUTES)); - } - - public function testGetDateDifferenceNoDifference(): void - { - // No difference - $dateStart = '2017-01-01 12:00'; - $dateEnd = $dateStart; - - $effect = [ - Date::DATE_DIFFERENCE_UNIT_YEARS => 0, - Date::DATE_DIFFERENCE_UNIT_MONTHS => 0, - Date::DATE_DIFFERENCE_UNIT_DAYS => 0, - Date::DATE_DIFFERENCE_UNIT_HOURS => 0, - Date::DATE_DIFFERENCE_UNIT_MINUTES => 0, - ]; - - self::assertEquals($effect, Date::getDateDifference($dateStart, $dateEnd)); - self::assertEquals($effect, Date::getDateDifference(new DateTime(), new DateTime())); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_YEARS)); - self::assertEquals(0, Date::getDateDifference(new DateTime(), new DateTime(), Date::DATE_DIFFERENCE_UNIT_YEARS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MONTHS)); - self::assertEquals(0, Date::getDateDifference(new DateTime(), new DateTime(), Date::DATE_DIFFERENCE_UNIT_MONTHS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_DAYS)); - self::assertEquals(0, Date::getDateDifference(new DateTime(), new DateTime(), Date::DATE_DIFFERENCE_UNIT_DAYS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_HOURS)); - self::assertEquals(0, Date::getDateDifference(new DateTime(), new DateTime(), Date::DATE_DIFFERENCE_UNIT_HOURS)); - - self::assertEquals(0, Date::getDateDifference($dateStart, $dateEnd, Date::DATE_DIFFERENCE_UNIT_MINUTES)); - self::assertEquals(0, Date::getDateDifference(new DateTime(), new DateTime(), Date::DATE_DIFFERENCE_UNIT_MINUTES)); + // Using custom date format + self::assertInstanceOf(DateTime::class, Date::getDateTime('2015-03-20 11:30', false, 'Y-m-d H:i')); + self::assertInstanceOf(DateTime::class, Date::getDateTime('20.03.2015', false, 'd.m.Y')); } /** - * @param mixed $invalidCount Empty value, e.g. "" + * @param mixed $value Empty value, e.g. "" * @dataProvider provideEmptyValue */ - public function testGetDatesCollectionInvalidCount($invalidCount): void + public function testGetDateTimeEmptyValue($value): void { - self::assertEquals([], Date::getDatesCollection(new DateTime(), $invalidCount)); - self::assertEquals([], Date::getDatesCollection(new DateTime(), -1)); + self::assertFalse(Date::getDateTime($value)); } /** - * @param mixed $invalidInterval Empty value, e.g. "" - * @dataProvider provideEmptyValue + * @param mixed $value Incorrect source of DateTime + * @dataProvider provideIncorrectDateTimeValue */ - public function testGetDatesCollectionInvalidInterval($invalidInterval): void + public function testGetDateTimeIncorrectValue($value): void { - self::assertEquals([], Date::getDatesCollection(new DateTime(), 2, $invalidInterval)); - self::assertEquals([], Date::getDatesCollection(new DateTime(), 2, 'lorem')); - self::assertEquals([], Date::getDatesCollection(new DateTime(), 2, '%d')); + self::assertFalse(Date::getDateTime($value)); + } + + /** + * @param DateTime $dateTime Instance of DateTime class + * @dataProvider provideDateTimeInstance + */ + public function testGetDateTimeInstanceDateTime(DateTime $dateTime): void + { + self::assertInstanceOf(DateTime::class, Date::getDateTime($dateTime)); + } + + /** + * @param string $relativeFormat Relative / compound format of DateTime + * @dataProvider provideDateTimeRelativeFormat + */ + public function testGetDateTimeRelativeFormats($relativeFormat): void + { + /* + * Values based on relative / compound formats, but... without explicitly declaring them as compound + * (2nd argument set to false by default) + * + * http://php.net/manual/en/datetime.formats.compound.php + */ + self::assertFalse(Date::getDateTime($relativeFormat)); + + /* + * Values based on relative / compound formats + * http://php.net/manual/en/datetime.formats.compound.php + */ + self::assertInstanceOf(DateTime::class, Date::getDateTime($relativeFormat, true)); } public function testGetDatesCollection(): void @@ -596,37 +830,76 @@ class DateTest extends BaseTestCase self::assertEquals($effect, Date::getDatesCollection(new DateTime('2017-01-01'), 3, 'P%dM')); } - public function testGetRandomDateUsingDefaults(): void + /** + * @param mixed $invalidCount Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testGetDatesCollectionInvalidCount($invalidCount): void { - $startDate = new DateTime(); - $start = 1; - $end = 100; - - $minDate = clone $startDate; - $maxDate = clone $startDate; - - $intervalMinDate = $minDate->add(new DateInterval(sprintf('P%dD', $start))); - $intervalMaxDate = $maxDate->add(new DateInterval(sprintf('P%dD', $end))); - - $randomDate = Date::getRandomDate(); - self::assertTrue($randomDate >= $intervalMinDate && $randomDate <= $intervalMaxDate); + self::assertEquals([], Date::getDatesCollection(new DateTime(), $invalidCount)); + self::assertEquals([], Date::getDatesCollection(new DateTime(), -1)); } /** - * @param DateTime $startDate The start date. Start of the random date. - * @param int $start Start of random partition - * @param int $end End of random partition - * - * @dataProvider provideDataOfRandomDateIncorrectEnd + * @param mixed $invalidInterval Empty value, e.g. "" + * @dataProvider provideEmptyValue */ - public function testGetRandomDateIncorrectEnd(DateTime $startDate, $start, $end): void + public function testGetDatesCollectionInvalidInterval($invalidInterval): void { - $randomDate = Date::getRandomDate($startDate, $start, $end); + self::assertEquals([], Date::getDatesCollection(new DateTime(), 2, $invalidInterval)); + self::assertEquals([], Date::getDatesCollection(new DateTime(), 2, 'lorem')); + self::assertEquals([], Date::getDatesCollection(new DateTime(), 2, '%d')); + } - $cloned = clone $startDate; - $intervalDate = $cloned->add(new DateInterval(sprintf('P%dD', $start))); + /** + * @param int $period The period, type of period. One of DatePeriod class constants, e.g. + * DatePeriod::LAST_WEEK. + * @param DatePeriod $expected Expected start and end date for given period + * + * @dataProvider provideCorrectPeriod + */ + public function testGetDatesForPeriod($period, DatePeriod $expected): void + { + self::assertEquals($expected, Date::getDatesForPeriod($period)); + } - self::assertTrue($randomDate >= $intervalDate && $randomDate <= $intervalDate); + public function testGetDatesForPeriodUsingEmptyString(): void + { + self::assertNull(Date::getDatesForPeriod('')); + } + + /** + * @param int $period Incorrect period to verify + * @dataProvider provideIncorrectPeriod + */ + public function testGetDatesForPeriodUsingIncorrectPeriod($period): void + { + self::assertNull(Date::getDatesForPeriod($period)); + } + + /** + * @param int $year The year value + * @param int $month The month value + * @param int $day The day value + * + * @dataProvider provideYearMonthDay + */ + public function testGetDayOfWeek(int $year, int $month, int $day): void + { + self::assertRegExp('/^[0-6]{1}$/', (string) Date::getDayOfWeek($year, $month, $day)); + } + + /** + * @param int $year The year value + * @param int $month The month value + * @param int $day The day value + * + * @dataProvider provideIncorrectYearMonthDay + */ + public function testGetDayOfWeekIncorrectValues(int $year, int $month, int $day): void + { + $this->expectException(UnknownDatePartTypeException::class); + self::assertEmpty(Date::getDayOfWeek($year, $month, $day)); } /** @@ -649,370 +922,97 @@ class DateTest extends BaseTestCase self::assertTrue($randomDate >= $intervalMinDate && $randomDate <= $intervalMaxDate); } - public function testGetDatesForPeriodUsingEmptyString(): void - { - self::assertNull(Date::getDatesForPeriod('')); - } - /** - * @param int $period Incorrect period to verify - * @dataProvider provideIncorrectPeriod - */ - public function testGetDatesForPeriodUsingIncorrectPeriod($period): void - { - self::assertNull(Date::getDatesForPeriod($period)); - } - - /** - * @param int $period The period, type of period. One of DatePeriod class constants, e.g. - * DatePeriod::LAST_WEEK. - * @param DatePeriod $expected Expected start and end date for given period + * @param DateTime $startDate The start date. Start of the random date. + * @param int $start Start of random partition + * @param int $end End of random partition * - * @dataProvider provideCorrectPeriod + * @dataProvider provideDataOfRandomDateIncorrectEnd */ - public function testGetDatesForPeriod($period, DatePeriod $expected): void + public function testGetRandomDateIncorrectEnd(DateTime $startDate, $start, $end): void { - self::assertEquals($expected, Date::getDatesForPeriod($period)); + $randomDate = Date::getRandomDate($startDate, $start, $end); + + $cloned = clone $startDate; + $intervalDate = $cloned->add(new DateInterval(sprintf('P%dD', $start))); + + self::assertTrue($randomDate >= $intervalDate && $randomDate <= $intervalDate); + } + + public function testGetRandomDateUsingDefaults(): void + { + $startDate = new DateTime(); + $start = 1; + $end = 100; + + $minDate = clone $startDate; + $maxDate = clone $startDate; + + $intervalMinDate = $minDate->add(new DateInterval(sprintf('P%dD', $start))); + $intervalMaxDate = $maxDate->add(new DateInterval(sprintf('P%dD', $end))); + + $randomDate = Date::getRandomDate(); + self::assertTrue($randomDate >= $intervalMinDate && $randomDate <= $intervalMaxDate); } /** - * Provides incorrect invalidCount of DateTime - * - * @return Generator + * @param mixed $value Empty value, e.g. "" + * @dataProvider provideEmptyValue */ - public function provideIncorrectDateTimeValue() + public function testIsValidDateEmptyDates($value): void { - // Incorrect one-character values - yield['a']; - yield['m']; - - // Incorrect strings - yield['ss']; - yield['sss']; - yield['mm']; - yield['yy']; - yield['yyyy']; - - // Incorrect integer values - yield[1]; - yield[10]; - yield[15]; - yield[100]; - yield[1000]; - - // Incorrect string / numeric values - yield['1']; - yield['10']; - yield['15']; - yield['100']; - yield['1000']; - - // Incorrect dates - yield['0-0-0']; - yield['20-01-01']; - yield['2015-0-0']; - yield['2015-00-00']; - yield['2015-16-01']; + self::assertFalse(Date::isValidDate($value)); } /** - * Provides invalid format of date - * - * @return Generator + * @param mixed $value Empty source of date format + * @dataProvider provideEmptyValue */ - public function provideInvalidDateFormats() + public function testIsValidDateFormatEmptyFormats($value): void { - yield[0]; - yield[9]; - yield['[]']; - yield['invalid']; - yield['Q']; - yield[',']; - yield['.']; - yield['aa###']; - yield['Y/m/d H:i:invalid']; + self::assertFalse(Date::isValidDateFormat($value)); } /** - * Provide empty dates for date difference - * - * @return Generator + * @param mixed $format Invalid format of date + * @dataProvider provideInvalidDateFormats */ - public function provideEmptyDatesForDateDifference() + public function testIsValidDateFormatInvalidFormats($format): void { - yield[ - null, - null, - ]; + self::assertFalse(Date::isValidDateFormat($format)); + } - yield[ - '', - '', - ]; - - yield[ - null, - new DateTime(), - ]; - - yield[ - new DateTime(), - null, - ]; + public function testIsValidDateFormatValidFormats(): void + { + self::assertTrue(Date::isValidDateFormat('Y')); + self::assertTrue(Date::isValidDateFormat('yy')); + self::assertTrue(Date::isValidDateFormat('M')); + self::assertTrue(Date::isValidDateFormat('i')); + self::assertTrue(Date::isValidDateFormat('l')); + self::assertTrue(Date::isValidDateFormat('l, d F')); + self::assertTrue(Date::isValidDateFormat('Y-m-d')); + self::assertTrue(Date::isValidDateFormat('H:i:s')); + self::assertTrue(Date::isValidDateFormat('Y/m/d H:i:s')); } /** - * Provides incorrect values of year, month and day - * - * @return Generator + * @param mixed $value Incorrect source of DateTime + * @dataProvider provideIncorrectDateTimeValue */ - public function provideIncorrectYearMonthDay(): Generator + public function testIsValidDateIncorrectDates($value): void { - yield[ - 0, - 0, - 0, - ]; - - yield[ - -1, - -1, - -1, - ]; - - yield[ - 5000, - 50, - 50, - ]; - - yield[ - 2000, - 13, - 01, - ]; - - yield[ - 2000, - 01, - 40, - ]; + self::assertFalse(Date::isValidDate($value)); } - /** - * Provides values of year, month and day - * - * @return Generator - */ - public function provideYearMonthDay() + public function testIsValidDateValidDates(): void { - yield[ - 2000, - 01, - 01, - ]; + self::assertTrue(Date::isValidDate('2017-01-01')); + self::assertTrue(Date::isValidDate('2017-01-01 10:30', true)); + self::assertTrue(Date::isValidDate('2017-01-01 14:00', true)); - yield[ - 2000, - 1, - 1, - ]; - - yield[ - 2000, - 2, - 2, - ]; - - yield[ - 2000, - 6, - 1, - ]; - - yield[ - 2000, - 12, - 01, - ]; - - yield[ - 2000, - 12, - 1, - ]; - - yield[ - 2000, - 12, - 31, - ]; - } - - /** - * Provides data for the random date with incorrect end of random partition - * - * @return Generator - */ - public function provideDataOfRandomDateIncorrectEnd() - { - yield[ - new DateTime('2000-01-01'), - 100, - 1, - ]; - } - - /** - * Provides data for the random date - * - * @return Generator - */ - public function provideDataOfRandomDate() - { - yield[ - new DateTime('2000-01-01'), - 1, - 100, - ]; - - yield[ - new DateTime('2000-12-01'), - 1, - 100, - ]; - yield[ - new DateTime('2000-01-01'), - '1', - '100', - ]; - - yield[ - new DateTime('2000-12-01'), - '1', - '100', - ]; - - yield[ - new DateTime('2000-01-01'), - 10, - 50, - ]; - - yield[ - new DateTime('2000-12-01'), - 10, - 50, - ]; - } - - /** - * Provides incorrect period - * - * @return Generator - */ - public function provideIncorrectPeriod() - { - yield[-1]; - yield[0]; - yield[10]; - } - - /** - * Provides correct period - * - * @return Generator - */ - public function provideCorrectPeriod() - { - yield[ - DatePeriod::LAST_WEEK, - new DatePeriod( - (new DateTime('this week'))->sub(new DateInterval('P7D'))->setTime(0, 0, 0), - (new DateTime('this week'))->sub(new DateInterval('P1D'))->setTime(23, 59, 59) - ), - ]; - - yield[ - DatePeriod::THIS_WEEK, - new DatePeriod( - (new DateTime('this week'))->setTime(0, 0, 0), - (new DateTime('this week'))->add(new DateInterval('P6D'))->setTime(23, 59, 59) - ), - ]; - - yield[ - DatePeriod::NEXT_WEEK, - new DatePeriod( - (new DateTime('this week'))->add(new DateInterval('P7D'))->setTime(0, 0, 0), - (new DateTime('this week'))->add(new DateInterval('P7D')) - ->add(new DateInterval('P6D')) - ->setTime(23, 59, 59) - ), - ]; - - yield[ - DatePeriod::LAST_MONTH, - new DatePeriod( - (new DateTime('first day of last month'))->setTime(0, 0, 0), - (new DateTime('last day of last month'))->setTime(23, 59, 59) - ), - ]; - - yield[ - DatePeriod::THIS_MONTH, - new DatePeriod( - Date::getDatesForPeriod(DatePeriod::LAST_MONTH) - ->getEndDate() - ->add(new DateInterval('P1D')) - ->setTime(0, 0, 0), - Date::getDatesForPeriod(DatePeriod::NEXT_MONTH) - ->getStartDate() - ->sub(new DateInterval('P1D')) - ->setTime(23, 59, 59) - ), - ]; - - yield[ - DatePeriod::NEXT_MONTH, - new DatePeriod( - (new DateTime('first day of next month'))->setTime(0, 0, 0), - (new DateTime('last day of next month'))->setTime(23, 59, 59) - ), - ]; - - $lastYearStart = (new DateTime())->modify('-1 year'); - $lastYearEnd = (new DateTime())->modify('-1 year'); - $year = $lastYearStart->format('Y'); - - yield[ - DatePeriod::LAST_YEAR, - new DatePeriod( - $lastYearStart->setDate($year, 1, 1)->setTime(0, 0, 0), - $lastYearEnd->setDate($year, 12, 31)->setTime(23, 59, 59) - ), - ]; - - $year = (new DateTime())->format('Y'); - - yield[ - DatePeriod::THIS_YEAR, - new DatePeriod( - (new DateTime())->setDate($year, 1, 1)->setTime(0, 0, 0), - (new DateTime())->setDate($year, 12, 31)->setTime(23, 59, 59) - ), - ]; - - $nextYearStart = (new DateTime())->modify('1 year'); - $nextYearEnd = (new DateTime())->modify('1 year'); - $year = $nextYearStart->format('Y'); - - yield[ - DatePeriod::NEXT_YEAR, - new DatePeriod( - $nextYearStart->setDate($year, 1, 1)->setTime(0, 0, 0), - $nextYearEnd->setDate($year, 12, 31)->setTime(23, 59, 59) - ), - ]; + self::assertTrue(Date::isValidDate(new DateTime())); + self::assertTrue(Date::isValidDate(new DateTime('now'))); + self::assertTrue(Date::isValidDate(new DateTime('tomorrow'))); + self::assertTrue(Date::isValidDate(new DateTime('m'))); } } diff --git a/tests/Utilities/GeneratorUtilityTest.php b/tests/Utilities/GeneratorUtilityTest.php index 1877597..18eb8a0 100644 --- a/tests/Utilities/GeneratorUtilityTest.php +++ b/tests/Utilities/GeneratorUtilityTest.php @@ -18,7 +18,7 @@ use Meritoo\Common\Utilities\GeneratorUtility; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Utilities\GeneratorUtility + * @covers \Meritoo\Common\Utilities\GeneratorUtility */ class GeneratorUtilityTest extends BaseTestCase { diff --git a/tests/Utilities/LocaleTest.php b/tests/Utilities/LocaleTest.php index 9a21384..0f0d16e 100644 --- a/tests/Utilities/LocaleTest.php +++ b/tests/Utilities/LocaleTest.php @@ -20,10 +20,138 @@ use ReflectionException; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Utilities\Locale + * @covers \Meritoo\Common\Utilities\Locale */ class LocaleTest extends BaseTestCase { + /** + * Provides category + * + * @return Generator + */ + public function provideCategoryLanguageCodeAndExpectedLocale() + { + yield [ + LC_ALL, + 'fr', + '', + 'fr_FR.UTF-8', + ]; + + yield [ + LC_COLLATE, + 'fr', + 'FR', + 'fr_FR.UTF-8', + ]; + + yield [ + LC_CTYPE, + 'en', + 'US', + 'en_US.UTF-8', + ]; + + yield [ + LC_NUMERIC, + 'en', + 'GB', + 'en_GB.UTF-8', + ]; + + yield [ + LC_MONETARY, + 'es', + '', + 'es_ES.UTF-8', + ]; + + yield [ + LC_MONETARY, + 'es', + 'ES', + 'es_ES.UTF-8', + ]; + + yield [ + LC_TIME, + 'it', + '', + 'it_IT.UTF-8', + ]; + + yield [ + LC_TIME, + 'it', + 'IT', + 'it_IT.UTF-8', + ]; + + yield [ + LC_TIME, + 'it', + 'it', + 'it_IT.UTF-8', + ]; + } + + /** + * Provides language, encoding and country code + * + * @return Generator + */ + public function provideLanguageEncodingAndCountryCode() + { + yield [ + 'fr', + '', + '', + 'fr_FR', + ]; + + yield [ + 'fr', + '', + 'UTF-8', + 'fr_FR.UTF-8', + ]; + + yield [ + 'fr', + 'FR', + '', + 'fr_FR', + ]; + + yield [ + 'fr', + 'FR', + 'UTF-8', + 'fr_FR.UTF-8', + ]; + + yield [ + 'en', + 'US', + '', + 'en_US', + ]; + + yield [ + 'en', + 'US', + 'UTF-8', + 'en_US.UTF-8', + ]; + + yield [ + 'en', + 'US', + 'ISO-8859-1', + 'en_US.ISO-8859-1', + ]; + } + /** * @throws ReflectionException */ @@ -32,56 +160,6 @@ class LocaleTest extends BaseTestCase static::assertHasNoConstructor(Locale::class); } - /** - * @param mixed $languageCode Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testGetLongFormEmptyLanguageCode($languageCode) - { - self::assertEquals('', Locale::getLongForm($languageCode)); - } - - /** - * @param string $languageCode Language code, in ISO 639-1 format. Short form of the locale, e.g. "fr". - * @param string $countryCode Country code, in ISO 3166-1 alpha-2 format, e.g. "FR" - * @param string $encoding Encoding of the final locale - * @param string $expected Expected long form of the locale - * - * @dataProvider provideLanguageEncodingAndCountryCode - */ - public function testGetLongForm($languageCode, $countryCode, $encoding, $expected) - { - self::assertEquals($expected, Locale::getLongForm($languageCode, $countryCode, $encoding)); - } - - /** - * @param mixed $emptyValue Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testSetLocaleEmptyCategoryAndLanguageCode($emptyValue) - { - self::assertFalse(Locale::setLocale($emptyValue, $emptyValue)); - } - - public function testSetLocaleIncorrectCategory() - { - self::assertFalse(Locale::setLocale(-1, 'en')); - } - - /** - * @param int $category Named constant specifying the category of the functions affected by the locale - * setting. It's the same constant as required by setlocale() function. - * @param string $languageCode Language code, in ISO 639-1 format. Short form of the locale, e.g. "fr". - * @param string $countryCode Country code, in ISO 3166-1 alpha-2 format, e.g. "FR" - * @param string $expectedLocale Expected locale - * - * @dataProvider provideCategoryLanguageCodeAndExpectedLocale - */ - public function testSetLocale($category, $languageCode, $countryCode, $expectedLocale) - { - self::assertEquals($expectedLocale, Locale::setLocale($category, $languageCode, $countryCode)); - } - /** * @param int $category Named constant specifying the category of the functions affected by the locale * setting. It's the same constant as required by setlocale() function. @@ -98,130 +176,52 @@ class LocaleTest extends BaseTestCase } /** - * Provides language, encoding and country code + * @param string $languageCode Language code, in ISO 639-1 format. Short form of the locale, e.g. "fr". + * @param string $countryCode Country code, in ISO 3166-1 alpha-2 format, e.g. "FR" + * @param string $encoding Encoding of the final locale + * @param string $expected Expected long form of the locale * - * @return Generator + * @dataProvider provideLanguageEncodingAndCountryCode */ - public function provideLanguageEncodingAndCountryCode() + public function testGetLongForm($languageCode, $countryCode, $encoding, $expected) { - yield[ - 'fr', - '', - '', - 'fr_FR', - ]; - - yield[ - 'fr', - '', - 'UTF-8', - 'fr_FR.UTF-8', - ]; - - yield[ - 'fr', - 'FR', - '', - 'fr_FR', - ]; - - yield[ - 'fr', - 'FR', - 'UTF-8', - 'fr_FR.UTF-8', - ]; - - yield[ - 'en', - 'US', - '', - 'en_US', - ]; - - yield[ - 'en', - 'US', - 'UTF-8', - 'en_US.UTF-8', - ]; - - yield[ - 'en', - 'US', - 'ISO-8859-1', - 'en_US.ISO-8859-1', - ]; + self::assertEquals($expected, Locale::getLongForm($languageCode, $countryCode, $encoding)); } /** - * Provides category - * - * @return Generator + * @param mixed $languageCode Empty value, e.g. "" + * @dataProvider provideEmptyValue */ - public function provideCategoryLanguageCodeAndExpectedLocale() + public function testGetLongFormEmptyLanguageCode($languageCode) { - yield[ - LC_ALL, - 'fr', - '', - 'fr_FR.UTF-8', - ]; + self::assertEquals('', Locale::getLongForm($languageCode)); + } - yield[ - LC_COLLATE, - 'fr', - 'FR', - 'fr_FR.UTF-8', - ]; + /** + * @param int $category Named constant specifying the category of the functions affected by the locale + * setting. It's the same constant as required by setlocale() function. + * @param string $languageCode Language code, in ISO 639-1 format. Short form of the locale, e.g. "fr". + * @param string $countryCode Country code, in ISO 3166-1 alpha-2 format, e.g. "FR" + * @param string $expectedLocale Expected locale + * + * @dataProvider provideCategoryLanguageCodeAndExpectedLocale + */ + public function testSetLocale($category, $languageCode, $countryCode, $expectedLocale) + { + self::assertEquals($expectedLocale, Locale::setLocale($category, $languageCode, $countryCode)); + } - yield[ - LC_CTYPE, - 'en', - 'US', - 'en_US.UTF-8', - ]; + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testSetLocaleEmptyCategoryAndLanguageCode($emptyValue) + { + self::assertFalse(Locale::setLocale($emptyValue, $emptyValue)); + } - yield[ - LC_NUMERIC, - 'en', - 'GB', - 'en_GB.UTF-8', - ]; - - yield[ - LC_MONETARY, - 'es', - '', - 'es_ES.UTF-8', - ]; - - yield[ - LC_MONETARY, - 'es', - 'ES', - 'es_ES.UTF-8', - ]; - - yield[ - LC_TIME, - 'it', - '', - 'it_IT.UTF-8', - ]; - - yield[ - LC_TIME, - 'it', - 'IT', - 'it_IT.UTF-8', - ]; - - yield[ - LC_TIME, - 'it', - 'it', - 'it_IT.UTF-8', - ]; + public function testSetLocaleIncorrectCategory() + { + self::assertFalse(Locale::setLocale(-1, 'en')); } } diff --git a/tests/Utilities/MimeTypesTest.php b/tests/Utilities/MimeTypesTest.php index 904c63f..829495f 100644 --- a/tests/Utilities/MimeTypesTest.php +++ b/tests/Utilities/MimeTypesTest.php @@ -19,15 +19,309 @@ use Meritoo\Common\Utilities\MimeTypes; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Utilities\MimeTypes + * @covers \Meritoo\Common\Utilities\MimeTypes */ class MimeTypesTest extends BaseTestCase { + /** + * Provides real file path to get information if the file is an image + * + * @return Generator + */ + public function provideExistingFilePathToCheckIsImagePath() + { + yield [ + $this->getFilePathForTesting('minion.jpg'), + true, + ]; + + yield [ + $this->getFilePathForTesting('lorem-ipsum.txt'), + false, + ]; + } + + /** + * Provides real file path to get mime type + * + * @return Generator + */ + public function provideFilePathToGetMimeTypeOfRealFile() + { + yield [ + $this->getFilePathForTesting('minion.jpg'), + 'image/jpeg', + ]; + + yield [ + $this->getFilePathForTesting('lorem-ipsum.txt'), + 'text/plain', + ]; + } + + /** + * Provides mime type of image + * + * @return Generator + */ + public function provideImageMimeType() + { + yield ['image/bmp']; + yield ['image/jpeg']; + yield ['image/png']; + yield ['image/tiff']; + yield ['image/vnd.microsoft.icon']; + yield ['image/x-rgb']; + } + + /** + * Provides existing mime type used to get multiple, more than one extension + * + * @return Generator + */ + public function provideMimeTypeToGetMultipleExtension() + { + yield [ + 'application/postscript', + [ + 'ai', + 'eps', + 'ps', + ], + ]; + + yield [ + 'audio/midi', + [ + 'mid', + 'midi', + 'kar', + 'rmi', + ], + ]; + + yield [ + 'image/jpeg', + [ + 'jpeg', + 'jpe', + 'jpg', + ], + ]; + + yield [ + 'text/html', + [ + 'html', + 'htm', + ], + ]; + + yield [ + 'text/plain', + [ + 'txt', + 'text', + 'conf', + 'def', + 'list', + 'log', + 'in', + ], + ]; + + yield [ + 'video/mp4', + [ + 'mp4', + 'mp4v', + 'mpg4', + 'm4v', + ], + ]; + } + + /** + * Provides existing mime type used to get single, one extension + * + * @return Generator + */ + public function provideMimeTypeToGetSingleExtension() + { + yield [ + 'application/x-7z-compressed', + '7z', + ]; + + yield [ + 'application/json', + 'json', + ]; + + yield [ + 'application/zip', + 'zip', + ]; + } + + /** + * Provides mime types used to get extensions + * + * @return Generator + */ + public function provideMimesTypesToGetExtensions() + { + yield [ + [ + 'application/x-7z-compressed', + 'application/json', + ], + [ + 'application/x-7z-compressed' => '7z', + 'application/json' => 'json', + ], + ]; + + yield [ + [ + 'application/mathematica', + 'application/xml', + 'audio/mp4', + 'video/mp4', + ], + [ + 'application/mathematica' => [ + 'ma', + 'nb', + 'mb', + ], + 'application/xml' => [ + 'xml', + 'xsl', + ], + 'audio/mp4' => 'mp4a', + 'video/mp4' => [ + 'mp4', + 'mp4v', + 'mpg4', + 'm4v', + ], + ], + ]; + } + + /** + * Provides mime types used to get extensions as upper case + * + * @return Generator + */ + public function provideMimesTypesToGetExtensionsUpperCase() + { + yield [ + [ + 'application/x-7z-compressed', + 'application/json', + ], + [ + 'application/x-7z-compressed' => '7Z', + 'application/json' => 'JSON', + ], + ]; + + yield [ + [ + 'application/xml', + 'audio/mp4', + 'text/html', + 'video/mp4', + ], + [ + 'application/xml' => [ + 'XML', + 'XSL', + ], + 'audio/mp4' => 'MP4A', + 'text/html' => [ + 'HTML', + 'HTM', + ], + 'video/mp4' => [ + 'MP4', + 'MP4V', + 'MPG4', + 'M4V', + ], + ], + ]; + } + + /** + * Provides mime type of non-image + * + * @return Generator + */ + public function provideNonImageMimeType() + { + yield ['application/rtf']; + yield ['audio/mp4']; + yield ['text/plain']; + yield ['text/html']; + } + + /** + * Provides not existing mime type + * + * @return Generator + */ + public function provideNotExistingMimeType() + { + yield ['lorem/ipsum']; + yield ['dolor']; + yield ['x/y/z']; + } + + /** + * Provides not existing mime types + * + * @return Generator + */ + public function provideNotExistingMimeTypes() + { + yield [ + [], + ]; + + yield [ + [ + '', + null, + false, + 0, + ], + ]; + + yield [ + [ + 'lorem/ipsum', + 'dolor/sit', + ], + ]; + } + public function testConstructor() { static::assertHasNoConstructor(MimeTypes::class); } + /** + * @param bool $mimeType The mime type, e.g. "video/mpeg" + * @dataProvider provideBooleanValue + */ + public function testGetExtensionBooleanMimeType($mimeType) + { + self::assertEquals('', MimeTypes::getExtension($mimeType)); + } + /** * @param mixed $mimeType Empty value, e.g. "" * @dataProvider provideEmptyValue @@ -38,12 +332,14 @@ class MimeTypesTest extends BaseTestCase } /** - * @param bool $mimeType The mime type, e.g. "video/mpeg" - * @dataProvider provideBooleanValue + * @param string $mimeType The mime type, e.g. "video/mpeg" + * @param array $extensions Expected extensions + * + * @dataProvider provideMimeTypeToGetMultipleExtension */ - public function testGetExtensionBooleanMimeType($mimeType) + public function testGetExtensionMultiple($mimeType, $extensions) { - self::assertEquals('', MimeTypes::getExtension($mimeType)); + self::assertEquals($extensions, MimeTypes::getExtension($mimeType)); } /** @@ -67,14 +363,14 @@ class MimeTypesTest extends BaseTestCase } /** - * @param string $mimeType The mime type, e.g. "video/mpeg" - * @param array $extensions Expected extensions + * @param array $mimesTypes The mimes types, e.g. ['video/mpeg', 'image/jpeg'] + * @param array $extensions Expected extensions * - * @dataProvider provideMimeTypeToGetMultipleExtension + * @dataProvider provideMimesTypesToGetExtensions */ - public function testGetExtensionMultiple($mimeType, $extensions) + public function testGetExtensions($mimesTypes, $extensions) { - self::assertEquals($extensions, MimeTypes::getExtension($mimeType)); + self::assertEquals($extensions, MimeTypes::getExtensions($mimesTypes)); } /** @@ -86,17 +382,6 @@ class MimeTypesTest extends BaseTestCase self::assertEquals([], MimeTypes::getExtensions($mimesTypes)); } - /** - * @param array $mimesTypes The mimes types, e.g. ['video/mpeg', 'image/jpeg'] - * @param array $extensions Expected extensions - * - * @dataProvider provideMimesTypesToGetExtensions - */ - public function testGetExtensions($mimesTypes, $extensions) - { - self::assertEquals($extensions, MimeTypes::getExtensions($mimesTypes)); - } - /** * @param array $mimesTypes The mimes types, e.g. ['video/mpeg', 'image/jpeg'] * @param array $extensions Expected extensions @@ -138,12 +423,12 @@ class MimeTypesTest extends BaseTestCase } /** - * @param string $mimeType Not existing mime type, e.g. "lorem/ipsum" - * @dataProvider provideNotExistingMimeType + * @param string $mimeType Mime type of image, e.g. "image/jpeg" + * @dataProvider provideImageMimeType */ - public function testIsImageNotExistingMimeType($mimeType) + public function testIsImageImageMimeType($mimeType) { - self::assertFalse(MimeTypes::isImage($mimeType)); + self::assertTrue(MimeTypes::isImage($mimeType)); } /** @@ -155,6 +440,15 @@ class MimeTypesTest extends BaseTestCase self::assertFalse(MimeTypes::isImage($mimeType)); } + /** + * @param string $mimeType Not existing mime type, e.g. "lorem/ipsum" + * @dataProvider provideNotExistingMimeType + */ + public function testIsImageNotExistingMimeType($mimeType) + { + self::assertFalse(MimeTypes::isImage($mimeType)); + } + /** * @param mixed $path Empty value, e.g. "" * @dataProvider provideEmptyValue @@ -164,15 +458,6 @@ class MimeTypesTest extends BaseTestCase self::assertFalse(MimeTypes::isImagePath($path)); } - /** - * @param mixed $path Path of not existing file, e.g. "lorem/ipsum.jpg" - * @dataProvider provideNotExistingFilePath - */ - public function testIsImagePathNotExistingPath($path) - { - self::assertFalse(MimeTypes::isImagePath($path)); - } - /** * @param string $path Path of the file to check * @param bool $isImage Expected information if the file is an image @@ -185,296 +470,11 @@ class MimeTypesTest extends BaseTestCase } /** - * @param string $mimeType Mime type of image, e.g. "image/jpeg" - * @dataProvider provideImageMimeType + * @param mixed $path Path of not existing file, e.g. "lorem/ipsum.jpg" + * @dataProvider provideNotExistingFilePath */ - public function testIsImageImageMimeType($mimeType) + public function testIsImagePathNotExistingPath($path) { - self::assertTrue(MimeTypes::isImage($mimeType)); - } - - /** - * Provides not existing mime type - * - * @return Generator - */ - public function provideNotExistingMimeType() - { - yield['lorem/ipsum']; - yield['dolor']; - yield['x/y/z']; - } - - /** - * Provides mime type of non-image - * - * @return Generator - */ - public function provideNonImageMimeType() - { - yield['application/rtf']; - yield['audio/mp4']; - yield['text/plain']; - yield['text/html']; - } - - /** - * Provides mime type of image - * - * @return Generator - */ - public function provideImageMimeType() - { - yield['image/bmp']; - yield['image/jpeg']; - yield['image/png']; - yield['image/tiff']; - yield['image/vnd.microsoft.icon']; - yield['image/x-rgb']; - } - - /** - * Provides existing mime type used to get single, one extension - * - * @return Generator - */ - public function provideMimeTypeToGetSingleExtension() - { - yield[ - 'application/x-7z-compressed', - '7z', - ]; - - yield[ - 'application/json', - 'json', - ]; - - yield[ - 'application/zip', - 'zip', - ]; - } - - /** - * Provides existing mime type used to get multiple, more than one extension - * - * @return Generator - */ - public function provideMimeTypeToGetMultipleExtension() - { - yield[ - 'application/postscript', - [ - 'ai', - 'eps', - 'ps', - ], - ]; - - yield[ - 'audio/midi', - [ - 'mid', - 'midi', - 'kar', - 'rmi', - ], - ]; - - yield[ - 'image/jpeg', - [ - 'jpeg', - 'jpe', - 'jpg', - ], - ]; - - yield[ - 'text/html', - [ - 'html', - 'htm', - ], - ]; - - yield[ - 'text/plain', - [ - 'txt', - 'text', - 'conf', - 'def', - 'list', - 'log', - 'in', - ], - ]; - - yield[ - 'video/mp4', - [ - 'mp4', - 'mp4v', - 'mpg4', - 'm4v', - ], - ]; - } - - /** - * Provides not existing mime types - * - * @return Generator - */ - public function provideNotExistingMimeTypes() - { - yield[ - [], - ]; - - yield[ - [ - '', - null, - false, - 0, - ], - ]; - - yield[ - [ - 'lorem/ipsum', - 'dolor/sit', - ], - ]; - } - - /** - * Provides mime types used to get extensions - * - * @return Generator - */ - public function provideMimesTypesToGetExtensions() - { - yield[ - [ - 'application/x-7z-compressed', - 'application/json', - ], - [ - 'application/x-7z-compressed' => '7z', - 'application/json' => 'json', - ], - ]; - - yield[ - [ - 'application/mathematica', - 'application/xml', - 'audio/mp4', - 'video/mp4', - ], - [ - 'application/mathematica' => [ - 'ma', - 'nb', - 'mb', - ], - 'application/xml' => [ - 'xml', - 'xsl', - ], - 'audio/mp4' => 'mp4a', - 'video/mp4' => [ - 'mp4', - 'mp4v', - 'mpg4', - 'm4v', - ], - ], - ]; - } - - /** - * Provides mime types used to get extensions as upper case - * - * @return Generator - */ - public function provideMimesTypesToGetExtensionsUpperCase() - { - yield[ - [ - 'application/x-7z-compressed', - 'application/json', - ], - [ - 'application/x-7z-compressed' => '7Z', - 'application/json' => 'JSON', - ], - ]; - - yield[ - [ - 'application/xml', - 'audio/mp4', - 'text/html', - 'video/mp4', - ], - [ - 'application/xml' => [ - 'XML', - 'XSL', - ], - 'audio/mp4' => 'MP4A', - 'text/html' => [ - 'HTML', - 'HTM', - ], - 'video/mp4' => [ - 'MP4', - 'MP4V', - 'MPG4', - 'M4V', - ], - ], - ]; - } - - /** - * Provides real file path to get mime type - * - * @return Generator - */ - public function provideFilePathToGetMimeTypeOfRealFile() - { - yield[ - $this->getFilePathForTesting('minion.jpg'), - 'image/jpeg', - ]; - - yield[ - $this->getFilePathForTesting('lorem-ipsum.txt'), - 'text/plain', - ]; - } - - /** - * Provides real file path to get information if the file is an image - * - * @return Generator - */ - public function provideExistingFilePathToCheckIsImagePath() - { - yield[ - $this->getFilePathForTesting('minion.jpg'), - true, - ]; - - yield[ - $this->getFilePathForTesting('lorem-ipsum.txt'), - false, - ]; + self::assertFalse(MimeTypes::isImagePath($path)); } } diff --git a/tests/Utilities/MiscellaneousTest.php b/tests/Utilities/MiscellaneousTest.php index a95f30a..7705cb0 100644 --- a/tests/Utilities/MiscellaneousTest.php +++ b/tests/Utilities/MiscellaneousTest.php @@ -32,25 +32,978 @@ class MiscellaneousTest extends BaseTestCase private $stringDotSeparated; private $stringWithoutSpaces; - public function testConstructor() + public function provideDataToReplaceWithQuoteStrings() { - static::assertHasNoConstructor(Miscellaneous::class); + yield [ + 'An empty string as subject', + '', + 'test', + 'another test', + '', + ]; + + yield [ + 'An empty string to search', + 'test', + '', + 'another test', + 'test', + ]; + + yield [ + 'An empty string as replacement', + 'test', + 'another test', + '', + 'test', + ]; + + yield [ + 'Replace 1 not existing word in 1 sentence (nothing to replace)', + 'Lorem ipsum dolor sit amet', + 'plum', + 'commodo', + 'Lorem ipsum dolor sit amet', + ]; + + yield [ + 'Replace 1 word in 1 sentence', + 'Lorem ipsum dolor sit amet', + 'ipsum', + 'commodo', + 'Lorem \'commodo\' dolor sit amet', + ]; + + yield [ + 'Replace 1 word in 2 sentences', + [ + 'Lorem ipsum dolor sit amet', + 'Maecenas sed diam eget risus varius blandit sit amet', + ], + 'amet', + 'commodo', + [ + 'Lorem ipsum dolor sit \'commodo\'', + 'Maecenas sed diam eget risus varius blandit sit \'commodo\'', + ], + ]; + + yield [ + '1 pattern (word -> "")', + 'Lorem ipsum dolor sit amet', + '|ipsum|', + '', + 'Lorem \'\' dolor sit amet', + ]; + + yield [ + '1 pattern (word -> word)', + 'Lorem ipsum dolor sit amet', + '|ipsum|', + 'commodo', + 'Lorem \'commodo\' dolor sit amet', + ]; + + yield [ + '2 patterns (word -> word)', + 'Lorem ipsum dolor sit amet', + [ + '|ipsum|', + '|amet|', + ], + [ + 'commodo', + 'egestas', + ], + 'Lorem \'commodo\' dolor sit \'egestas\'', + ]; } - public function testGetDirectoryContent() + /** + * Provides empty value used to fill missing zeros + * + * @return Generator + */ + public function provideEmptyValueToFillMissingZeros() { - $directoryPath = __DIR__ . '/../'; - $filePath = __FILE__; + yield ['']; + yield [' ']; + yield [null]; + yield [false]; + yield [[]]; + } - self::assertNull(Miscellaneous::getDirectoryContent(null)); - self::assertNull(Miscellaneous::getDirectoryContent('')); + public function provideEmptyValuesToReplace() + { + yield [ + 'An empty string as subject', + '', + 'test', + 'another test', + '', + ]; - self::assertGreaterThanOrEqual(0, count(Miscellaneous::getDirectoryContent($directoryPath))); - self::assertGreaterThanOrEqual(0, count(Miscellaneous::getDirectoryContent($directoryPath, true))); - self::assertGreaterThanOrEqual(0, count(Miscellaneous::getDirectoryContent($directoryPath, true, 5))); + yield [ + 'An empty array as subject', + [], + 'test', + 'another test', + [], + ]; - self::assertGreaterThanOrEqual(0, count(Miscellaneous::getDirectoryContent($filePath))); - self::assertGreaterThanOrEqual(0, count(Miscellaneous::getDirectoryContent($filePath, true))); + yield [ + 'Null as subject', + null, + 'test', + 'another test', + null, + ]; + + yield [ + 'An empty string to search', + 'test', + '', + 'another test', + 'test', + ]; + + yield [ + 'An empty array to search', + 'test', + [], + 'another test', + 'test', + ]; + + yield [ + 'Null to search', + 'test', + null, + 'another test', + 'test', + ]; + + yield [ + 'An empty string as replacement', + 'test', + 'another test', + '', + 'test', + ]; + + yield [ + 'An empty array as replacement', + 'test', + 'another test', + [], + 'test', + ]; + + yield [ + 'Null as replacement', + 'test', + 'another test', + null, + 'test', + ]; + } + + /** + * Provides names of files + * + * @return Generator + */ + public function provideFileNames() + { + yield [ + 'Lorem.ipsum-dolor.sit.JPG', + 'Lorem.ipsum-dolor.sit', + ]; + + yield [ + 'lets-test.doc', + 'lets-test', + ]; + + yield [ + 'something/else.txt', + 'something/else', + ]; + + yield [ + 'public/js/user.js', + 'public/js/user', + ]; + } + + public function provideFilePath(): ?Generator + { + yield [ + 'Path with file', + 'lorem/ipsum-dolor/sit.amet.JPG', + 'sit.amet.JPG', + ]; + + yield [ + 'Path with complicated name of file', + 'lorem/ipsum-dolor/this-1_2 3 & my! 4+file.jpg', + 'this-1_2 3 & my! 4+file.jpg', + ]; + + yield [ + 'Path without file', + 'lorem/ipsum-dolor/sit-amet', + '', + ]; + + yield [ + 'Path with a dot "." in name of directory', + 'lorem/ipsum.dolor/sit.amet.JPG', + 'sit.amet.JPG', + ]; + + yield [ + 'Relative path', + 'lorem/ipsum/../dolor/sit.amet.JPG', + 'sit.amet.JPG', + ]; + } + + public function provideGreatestCommonDivisor(): ?Generator + { + yield [ + 0, + 0, + 0, + ]; + + yield [ + 1, + 1, + 1, + ]; + + yield [ + 5, + 3, + 1, + ]; + + yield [ + 6, + 3, + 3, + ]; + + yield [ + 12, + 9, + 3, + ]; + + yield [ + 20, + 12, + 4, + ]; + + yield [ + 120, + 80, + 40, + ]; + } + + public function provideLastElementOfString(): ?Generator + { + yield [ + 'An empty string', + '', + '', + null, + ]; + + yield [ + 'One-character string', + 'a', + ',', + null, + ]; + + yield [ + 'String without given separator', + 'abc', + ',', + null, + ]; + + yield [ + 'Simple, short string', + 'a, b, c', + ',', + ' c', + ]; + + yield [ + 'A sentence', + 'Lorem ipsum - dolor sit - amet, consectetur adipiscing - elit.', + '-', + ' elit.', + ]; + + yield [ + 'A class namespace', + 'This\\Is\\My\\Class\\For\\Testing', + '\\', + 'Testing', + ]; + } + + /** + * Provides number used to fill missing zeros + * + * @return Generator + */ + public function provideNumberToFillMissingZeros() + { + yield [ + 0, + 0, + true, + '0', + ]; + + yield [ + 0, + 0, + false, + '0', + ]; + + yield [ + 1, + 0, + true, + '1', + ]; + + yield [ + 1, + 0, + false, + '1', + ]; + + yield [ + 1, + 1, + true, + '1', + ]; + + yield [ + 1, + 1, + false, + '1', + ]; + + yield [ + 123, + 5, + true, + '00123', + ]; + + yield [ + 123, + 5, + false, + '12300', + ]; + } + + /** + * Provides path used to remove the ending directory's separator + * + * @return Generator + */ + public function providePathsToRemoveEndingDirectorySeparator() + { + yield [ + 'lorem/ipsum/dolor/', + '/', + 'lorem/ipsum/dolor', + ]; + + yield [ + 'lorem/ipsum/dolor', + '/', + 'lorem/ipsum/dolor', + ]; + + yield [ + 'lorem\ipsum\dolor\\', + '\\', + 'lorem\ipsum\dolor', + ]; + + yield [ + 'lorem\ipsum\dolor', + '\\', + 'lorem\ipsum\dolor', + ]; + + yield [ + 'lorem;ipsum;dolor;', + ';', + 'lorem;ipsum;dolor', + ]; + + yield [ + 'lorem;ipsum;dolor', + ';', + 'lorem;ipsum;dolor', + ]; + } + + /** + * Provides path used to remove the starting / beginning directory's separator + * + * @return Generator + */ + public function providePathsToRemoveStartingDirectorySeparator() + { + yield [ + '/lorem/ipsum/dolor', + '/', + 'lorem/ipsum/dolor', + ]; + + yield [ + 'lorem/ipsum/dolor', + '/', + 'lorem/ipsum/dolor', + ]; + + yield [ + '\\lorem\ipsum\dolor', + '\\', + 'lorem\ipsum\dolor', + ]; + + yield [ + 'lorem\ipsum\dolor', + '\\', + 'lorem\ipsum\dolor', + ]; + + yield [ + ';lorem;ipsum;dolor', + ';', + 'lorem;ipsum;dolor', + ]; + + yield [ + 'lorem;ipsum;dolor', + ';', + 'lorem;ipsum;dolor', + ]; + } + + public function provideRegexToReplace() + { + yield [ + 'Different count of strings to search and replace - 1st part', + 'Lorem ipsum dolor sit amet', + [ + '|ipsum|', + ], + 'commodo', + 'Lorem ipsum dolor sit amet', + ]; + + yield [ + 'Different count of strings to search and replace - 2nd part', + 'Lorem ipsum dolor sit amet', + '|ipsum|', + [ + 'commodo', + ], + 'Lorem ipsum dolor sit amet', + ]; + + yield [ + '1 pattern (word -> "")', + 'Lorem ipsum dolor sit amet', + '|ipsum|', + '', + 'Lorem dolor sit amet', + ]; + + yield [ + '1 pattern (word -> word)', + 'Lorem ipsum dolor sit amet', + '|ipsum|', + 'commodo', + 'Lorem commodo dolor sit amet', + ]; + + yield [ + '2 patterns (word -> word)', + 'Lorem ipsum dolor sit amet', + [ + '|ipsum|', + '|amet|', + ], + [ + 'commodo', + 'egestas', + ], + 'Lorem commodo dolor sit egestas', + ]; + + yield [ + '1 word in 2 sentences', + [ + 'Lorem ipsum dolor sit amet', + 'Maecenas sed diam eget risus varius blandit sit amet', + ], + '|amet|', + 'commodo', + [ + 'Lorem ipsum dolor sit commodo', + 'Maecenas sed diam eget risus varius blandit sit commodo', + ], + ]; + + yield [ + '2 words in 2 sentences', + [ + 'Lorem ipsum dolor sit amet', + 'Maecenas sed diam eget risus varius blandit sit amet', + ], + [ + '|ipsum|', + '|amet|', + ], + [ + 'commodo', + 'egestas', + ], + [ + 'Lorem commodo dolor sit egestas', + 'Maecenas sed diam eget risus varius blandit sit egestas', + ], + ]; + } + + public function provideStringElements(): ?Generator + { + yield [ + 'An empty string', + '', + '', + [], + ]; + + yield [ + 'One-character string', + 'a', + ',', + [], + ]; + + yield [ + 'String without given separator', + 'abc', + ',', + [], + ]; + + yield [ + 'Simple, short string', + 'a, b, c', + ',', + [ + 'a', + ' b', + ' c', + ], + ]; + + yield [ + 'A sentence', + 'Lorem ipsum - dolor sit - amet, consectetur adipiscing - elit.', + '-', + [ + 'Lorem ipsum ', + ' dolor sit ', + ' amet, consectetur adipiscing ', + ' elit.', + ], + ]; + + yield [ + 'A class namespace', + 'This\\Is\\My\\Class\\For\\Testing', + '\\', + [ + 'This', + 'Is', + 'My', + 'Class', + 'For', + 'Testing', + ], + ]; + } + + /** + * Provides string to convert to camel case + * + * @return Generator + */ + public function provideStringToCamelCase() + { + yield [ + 'lorem ipsum', + ' ', + 'loremIpsum', + ]; + + yield [ + 'Lorem ipSum Dolor', + ' ', + 'loremIpsumDolor', + ]; + + yield [ + 'abc;def;ghi', + ';', + 'abcDefGhi', + ]; + } + + /** + * Provides string to convert characters to latin characters and lower cased and human-readable + * + * @return Generator + */ + public function provideStringToLatinLowerCaseHuman() + { + yield [ + 'asuo', + 'ąśüö', + ]; + + yield [ + 'eoaslzzcn', + 'ęóąśłżźćń', + ]; + + yield [ + 'loremipsum', + 'loremipsum', + ]; + + yield [ + 'lorem-ipsum', + 'lorem ipsum', + ]; + + yield [ + 'lorem-ipsum', + 'lorem;ipsum', + ]; + + yield [ + 'lorem1ipsum2', + 'lorem1ipsum2', + ]; + + yield [ + 'lorem_ipsum', + 'lorem ipsum', + '_', + ]; + + yield [ + 'lorem-ipsum', + 'lorem-ipsum', + ]; + + yield [ + 'lorem ipsum', + 'Lorem!Ipsum', + ' ', + ]; + + yield [ + 'lorem ipsum', + 'Lorem.Ipsum', + ' ', + ]; + + yield [ + 'lorem|ipsum', + 'Lorem.Ipsum', + '|', + ]; + + yield [ + 'lorem-ipsum', + 'LoremIpsum', + ]; + + yield [ + 'lorem.ipsum', + 'Lorem Ipsum', + '.', + ]; + + yield [ + 'lorem.ipsum', + 'Lorem=Ipsum', + '.', + ]; + + yield [ + 'lorem-ipsum-d', + 'LoremIpsumD', + ]; + + yield [ + 'lorem.ipsum.d', + 'LoremIpsumD', + '.', + ]; + } + + /** + * Provides string to convert characters to latin characters and not lower cased and not human-readable + * + * @return Generator + */ + public function provideStringToLatinNotLowerCaseHuman(): ?Generator + { + yield [ + 'asuo', + 'ąśüö', + ]; + + yield [ + 'eoaslzzcn', + 'ęóąśłżźćń', + ]; + + yield [ + 'loremipsum', + 'loremipsum', + ]; + + yield [ + 'LoremIpsum', + 'LoremIpsum', + ]; + + yield [ + 'Lorem.Ipsum', + 'Lorem Ipsum', + '.', + ]; + + yield [ + 'Lorem.Ipsum', + 'Lorem=Ipsum', + '.', + ]; + + yield [ + 'LoremIpsumD', + 'LoremIpsumD', + ]; + + yield [ + 'LoremIpsumD', + 'LoremIpsumD', + '.', + ]; + + yield [ + 'lorem-ipsum', + 'lorem ipsum', + ]; + + yield [ + 'lorem-ipsum', + 'lorem;ipsum', + ]; + + yield [ + 'lorem1ipsum2', + 'lorem1ipsum2', + ]; + + yield [ + 'lorem_ipsum', + 'lorem ipsum', + '_', + ]; + + yield [ + 'LoremIpsum', + 'LoremIpsum', + ]; + + yield [ + 'Lorem Ipsum', + 'Lorem!Ipsum', + ' ', + ]; + + yield [ + 'Lorem Ipsum', + 'Lorem.Ipsum', + ' ', + ]; + + yield [ + 'Lorem|Ipsum', + 'Lorem.Ipsum', + '|', + ]; + } + + public function provideStringToRemoveMarginalCharacter(): ?Generator + { + yield [ + 'An empty string - remove last character', + '', + true, + null, + ]; + + yield [ + 'An empty string - remove first character', + '', + false, + null, + ]; + + yield [ + 'Simple, two words - remove last character', + 'Lorem ipsum', + true, + 'Lorem ipsu', + ]; + + yield [ + 'Simple, two words - remove first character', + 'Lorem ipsum', + false, + 'orem ipsum', + ]; + + yield [ + 'Two sentences - remove last character', + 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis.', + true, + 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis', + ]; + + yield [ + 'Two sentences - remove first character', + 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis.', + false, + 'tiam ullamcorper. Suspendisse a pellentesque dui, non felis.', + ]; + } + + public function provideStringsToReplace() + { + yield [ + 'Different count of strings to search and replace - 1st part', + 'Lorem ipsum dolor sit amet', + [ + 'ipsum', + ], + 'commodo', + 'Lorem ipsum dolor sit amet', + ]; + + yield [ + 'Different count of strings to search and replace - 2nd part', + 'Lorem ipsum dolor sit amet', + 'ipsum', + [ + 'commodo', + ], + 'Lorem commodo dolor sit amet', + ]; + + yield [ + 'Replace 1 not existing word in 1 sentence (nothing to replace)', + 'Lorem ipsum dolor sit amet', + 'plum', + 'commodo', + 'Lorem ipsum dolor sit amet', + ]; + + yield [ + 'Replace 1 word in 1 sentence', + 'Lorem ipsum dolor sit amet', + 'ipsum', + 'commodo', + 'Lorem commodo dolor sit amet', + ]; + + yield [ + 'Replace 1 not existing word in 2 sentences (nothing to replace)', + [ + 'Lorem ipsum dolor sit amet', + 'Maecenas sed diam eget risus varius blandit sit amet', + ], + 'plum', + 'commodo', + [ + 'Lorem ipsum dolor sit amet', + 'Maecenas sed diam eget risus varius blandit sit amet', + ], + ]; + + yield [ + 'Replace 1 word in 2 sentences', + [ + 'Lorem ipsum dolor sit amet', + 'Maecenas sed diam eget risus varius blandit sit amet', + ], + 'amet', + 'commodo', + [ + 'Lorem ipsum dolor sit commodo', + 'Maecenas sed diam eget risus varius blandit sit commodo', + ], + ]; + } + + public function testBreakLongText() + { + self::assertEquals('Lorem ipsum dolor sit
amet, consectetur
adipiscing
elit', Miscellaneous::breakLongText($this->stringCommaSeparated, 20)); + self::assertEquals('Lorem ipsum dolor sit---amet, consectetur---adipiscing---elit', Miscellaneous::breakLongText($this->stringCommaSeparated, 20, '---')); + self::assertEquals('LoremIpsum
DolorSitAm
etConsecte
turAdipisc
ingElit', Miscellaneous::breakLongText($this->stringWithoutSpaces, 10)); + } + + /** + * @param int $first + * @param int $second + * @param int $expected + * + * @dataProvider provideGreatestCommonDivisor + */ + public function testCalculateGreatestCommonDivisor(int $first, int $second, int $expected): void + { + static::assertSame($expected, Miscellaneous::calculateGreatestCommonDivisor($first, $second)); } public function testCheckboxValue2Boolean() @@ -67,6 +1020,120 @@ class MiscellaneousTest extends BaseTestCase self::assertEquals(0, Miscellaneous::checkboxValue2Integer(null)); } + public function testConcatenatePathsInNixOs() + { + // For *nix operating system + $paths1 = [ + 'first/directory', + 'second/one', + 'and/the/third', + ]; + + self::assertEquals('/'.implode('/', $paths1), Miscellaneous::concatenatePaths($paths1)); + self::assertEquals('/'.implode('/', $paths1), Miscellaneous::concatenatePaths($paths1[0], $paths1[1], $paths1[2])); + } + + public function testConcatenatePathsInWindowsOs() + { + // For Windows operating system + $paths2 = [ + 'C:\first\directory', + 'second\one', + 'and\the\third', + ]; + + self::assertEquals(implode('\\', $paths2), Miscellaneous::concatenatePaths($paths2)); + } + + /** + * @param mixed $emptyPaths Empty paths co concatenate + * @dataProvider provideEmptyValue + */ + public function testConcatenatePathsWithEmptyPaths($emptyPaths) + { + self::assertEquals('', Miscellaneous::concatenatePaths($emptyPaths)); + } + + public function testConcatenatePathsWithOneEmptyPath() + { + $paths = [ + 'first/directory', + 'second/one', + '', + 'and/the/third', + ]; + + $concatenated = Miscellaneous::concatenatePaths($paths); + unset($paths[2]); + $imploded = implode('/', $paths); + + self::assertEquals('/'.$imploded, $concatenated); + } + + public function testConstructor() + { + static::assertHasNoConstructor(Miscellaneous::class); + } + + /** + * @param mixed $number Number for who the "0" characters should be inserted + * @param int $length Wanted length of final number + * @param bool $before If false, 0 characters will be inserted after given number + * @param string $expected String with added missing the "0" characters + * + * @dataProvider provideNumberToFillMissingZeros + */ + public function testFillMissingZeros($number, $length, $before, $expected): void + { + self::assertSame($expected, Miscellaneous::fillMissingZeros($number, $length, $before)); + } + + /** + * @param mixed $number Number for who the "0" characters should be inserted + * @dataProvider provideEmptyValueToFillMissingZeros + */ + public function testFillMissingZerosEmptyValue($number) + { + self::assertEquals('', Miscellaneous::fillMissingZeros($number, 1)); + } + + /** + * @param string $string The string to convert e.g. this-is-eXamplE (return: thisIsExample) + * @param string $separator (optional) Separator used to find parts of the string, e.g. '-' or ',' + * @param string $expected String in camel case + * + * @dataProvider provideStringToCamelCase + */ + public function testGetCamelCase($string, $separator, $expected) + { + self::assertEquals($expected, Miscellaneous::getCamelCase($string, $separator)); + } + + /** + * @param string $string The string to convert e.g. this-is-eXamplE (return: thisIsExample) + * @dataProvider provideEmptyValue + */ + public function testGetCamelCaseEmptyValue($string) + { + self::assertEquals('', Miscellaneous::getCamelCase($string)); + } + + public function testGetDirectoryContent() + { + $directoryPath = __DIR__.'/../'; + $filePath = __FILE__; + + self::assertNull(Miscellaneous::getDirectoryContent(null)); + self::assertNull(Miscellaneous::getDirectoryContent('')); + + self::assertGreaterThanOrEqual(0, count(Miscellaneous::getDirectoryContent($directoryPath))); + self::assertGreaterThanOrEqual(0, count(Miscellaneous::getDirectoryContent($directoryPath, true))); + self::assertGreaterThanOrEqual(0, count(Miscellaneous::getDirectoryContent($directoryPath, true, 5))); + + self::assertGreaterThanOrEqual(0, count(Miscellaneous::getDirectoryContent($filePath))); + self::assertGreaterThanOrEqual(0, count(Miscellaneous::getDirectoryContent($filePath, true))); + } + public function testGetFileExtension() { $fileName = 'Lorem.ipsum-dolor.sit.JPG'; @@ -74,26 +1141,6 @@ class MiscellaneousTest extends BaseTestCase self::assertEquals('jpg', Miscellaneous::getFileExtension($fileName, true)); } - /** - * @param string $fileName Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testGetFileNameWithoutExtensionEmptyValue($fileName) - { - self::assertEquals('', Miscellaneous::getFileNameWithoutExtension($fileName)); - } - - /** - * @param string $fileName The file name with extension - * @param string $withoutExtension The file name without extension - * - * @dataProvider provideFileNames - */ - public function testGetFileNameWithoutExtension($fileName, $withoutExtension) - { - self::assertEquals($withoutExtension, Miscellaneous::getFileNameWithoutExtension($fileName)); - } - /** * @param string $description Description of test * @param string $path A path that contains file name @@ -106,6 +1153,176 @@ class MiscellaneousTest extends BaseTestCase static::assertEquals($expected, Miscellaneous::getFileNameFromPath($path), $description); } + /** + * @param string $fileName The file name with extension + * @param string $withoutExtension The file name without extension + * + * @dataProvider provideFileNames + */ + public function testGetFileNameWithoutExtension($fileName, $withoutExtension) + { + self::assertEquals($withoutExtension, Miscellaneous::getFileNameWithoutExtension($fileName)); + } + + /** + * @param string $fileName Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testGetFileNameWithoutExtensionEmptyValue($fileName) + { + self::assertEquals('', Miscellaneous::getFileNameWithoutExtension($fileName)); + } + + public function testGetHumanReadableSize() + { + Locale::setLocale(LC_ALL, 'en', 'US'); + + self::assertEquals('400 B', Miscellaneous::getHumanReadableSize(400)); + self::assertEquals('1 KB', Miscellaneous::getHumanReadableSize(1024)); + self::assertEquals('1 MB', Miscellaneous::getHumanReadableSize(1024 * 1024)); + self::assertEquals('1.75 MB', Miscellaneous::getHumanReadableSize(1024 * 1024 * 1.75)); + } + + public function testGetInvertedColor() + { + // Simple cases + self::assertEquals('000000', Miscellaneous::getInvertedColor('fff')); + self::assertEquals('ffffff', Miscellaneous::getInvertedColor('000')); + self::assertEquals('000000', Miscellaneous::getInvertedColor('ffffff')); + self::assertEquals('ffffff', Miscellaneous::getInvertedColor('000000')); + self::assertEquals('#000000', Miscellaneous::getInvertedColor('#ffffff')); + self::assertEquals('#ffffff', Miscellaneous::getInvertedColor('#000000')); + + // Advanced cases - part 1 + self::assertEquals('ffffee', Miscellaneous::getInvertedColor('001')); + self::assertEquals('ffeeff', Miscellaneous::getInvertedColor('010')); + self::assertEquals('eeffff', Miscellaneous::getInvertedColor('100')); + self::assertEquals('333333', Miscellaneous::getInvertedColor('ccc')); + self::assertEquals('333333', Miscellaneous::getInvertedColor('CCC')); + + // Advanced cases - part 2 + self::assertEquals('3e3e3e', Miscellaneous::getInvertedColor('c1c1c1')); + self::assertEquals('3e3e3e', Miscellaneous::getInvertedColor('C1C1C1')); + self::assertEquals('#dd5a01', Miscellaneous::getInvertedColor('#22a5fe')); + self::assertEquals('#22dbb3', Miscellaneous::getInvertedColor('#dd244c')); + self::assertEquals('#464646', Miscellaneous::getInvertedColor('#b9b9b9')); + self::assertEquals('#080808', Miscellaneous::getInvertedColor('#f7f7f7')); + + // Advanced cases - verification + self::assertEquals('000011', Miscellaneous::getInvertedColor('ffffee')); + self::assertEquals('cccccc', Miscellaneous::getInvertedColor('333333')); + self::assertEquals('#22a5fe', Miscellaneous::getInvertedColor('#dd5a01')); + self::assertEquals('#22a5fe', Miscellaneous::getInvertedColor('#DD5A01')); + self::assertEquals('#f7f7f7', Miscellaneous::getInvertedColor('#080808')); + } + + public function testGetInvertedColorWithIncorrectLength() + { + $this->expectException(IncorrectColorHexLengthException::class); + + Miscellaneous::getInvertedColor(null); + Miscellaneous::getInvertedColor(''); + Miscellaneous::getInvertedColor(1); + Miscellaneous::getInvertedColor(12); + Miscellaneous::getInvertedColor(1234567); + Miscellaneous::getInvertedColor('1'); + Miscellaneous::getInvertedColor('12'); + Miscellaneous::getInvertedColor('1234567'); + } + + public function testGetInvertedColorWithInvalidValue() + { + $this->expectException(InvalidColorHexValueException::class); + + Miscellaneous::getInvertedColor('0011zz'); + Miscellaneous::getInvertedColor('001#zz'); + Miscellaneous::getInvertedColor('001!zz'); + Miscellaneous::getInvertedColor('001-zz'); + Miscellaneous::getInvertedColor('00ppqq'); + } + + /** + * @param string $description + * @param string $string + * @param string $separator + * @param string|null $expected + * + * @dataProvider provideLastElementOfString + */ + public function testGetLastElementOfString( + string $description, + string $string, + string $separator, + ?string $expected + ): void { + self::assertEquals($expected, Miscellaneous::getLastElementOfString($string, $separator), $description); + } + + public function testGetNewFileName() + { + self::assertEquals('test.jpg', Miscellaneous::getNewFileName('test.jpg', '', '')); + self::assertEquals('my-test.jpg', Miscellaneous::getNewFileName('test.jpg', 'my-', '')); + self::assertEquals('test-file.jpg', Miscellaneous::getNewFileName('test.jpg', '', '-file')); + self::assertEquals('my-test-file.jpg', Miscellaneous::getNewFileName('test.jpg', 'my-', '-file')); + } + + public function testGetOperatingSystemNameServer() + { + // While running Docker OS is a Linux + self::assertEquals('Linux', Miscellaneous::getOperatingSystemNameServer()); + } + + public function testGetProjectRootPath(): void + { + self::assertNotEmpty(Miscellaneous::getProjectRootPath()); + } + + public function testGetSafelyGlobalVariable() + { + self::assertEquals('', Miscellaneous::getSafelyGlobalVariable(INPUT_GET, 'lorem')); + self::assertEquals('', Miscellaneous::getSafelyGlobalVariable(INPUT_POST, 'lorem')); + self::assertEquals('', Miscellaneous::getSafelyGlobalVariable(INPUT_COOKIE, 'lorem')); + self::assertEquals('', Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'lorem')); + self::assertEquals('', Miscellaneous::getSafelyGlobalVariable(INPUT_ENV, 'lorem')); + + $_GET['lorem'] = 123; + self::assertEquals(123, Miscellaneous::getSafelyGlobalVariable(INPUT_GET, 'lorem')); + } + + /** + * @param string $description + * @param string $string + * @param string $separator + * @param array $expected + * + * @dataProvider provideStringElements + */ + public function testGetStringElements( + string $description, + string $string, + string $separator, + array $expected + ): void { + self::assertEquals($expected, Miscellaneous::getStringElements($string, $separator), $description); + } + + public function testGetStringWithoutLastElement() + { + self::assertEquals('Lorem ipsum dolor sit', Miscellaneous::getStringWithoutLastElement($this->stringSmall, ' ')); + self::assertEquals('', Miscellaneous::getStringWithoutLastElement($this->stringSmall, ';')); + } + + public function testGetType() + { + self::assertEquals('NULL', Miscellaneous::getType(null)); + self::assertEquals('string', Miscellaneous::getType($this->stringSmall)); + self::assertEquals('integer', Miscellaneous::getType(123)); + self::assertEquals('double', Miscellaneous::getType(1.23)); + self::assertEquals('array', Miscellaneous::getType([])); + self::assertEquals('stdClass', Miscellaneous::getType(new stdClass())); + self::assertEquals(__CLASS__, Miscellaneous::getType(new self())); + } + public function testGetUniqueFileName() { $originalFileName = 'Lorem.ipsum-dolor.sit.JPG'; @@ -117,62 +1334,13 @@ class MiscellaneousTest extends BaseTestCase // Without object ID $uniqueFileName2 = Miscellaneous::getUniqueFileName($originalFileName); - $isCorrect1 = (bool)preg_match($pattern, $uniqueFileName1); - $isCorrect2 = (bool)preg_match($pattern, $uniqueFileName2); + $isCorrect1 = (bool) preg_match($pattern, $uniqueFileName1); + $isCorrect2 = (bool) preg_match($pattern, $uniqueFileName2); self::assertTrue($isCorrect1); self::assertTrue($isCorrect2); } - public function testValue2NonNegativeInteger() - { - self::assertEquals(2, Miscellaneous::value2NonNegativeInteger('2')); - self::assertEquals(0, Miscellaneous::value2NonNegativeInteger('a')); - self::assertEquals('-', Miscellaneous::value2NonNegativeInteger('-4', '-')); - } - - public function testIsPhpModuleLoaded() - { - $loadedExtensions = get_loaded_extensions(); - $firstExtension = $loadedExtensions[0]; - - self::assertTrue(Miscellaneous::isPhpModuleLoaded($firstExtension)); - self::assertFalse(Miscellaneous::isPhpModuleLoaded('xyz123')); - } - - /** - * @param mixed $string Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testToLatinEmptyValue($string) - { - self::assertEquals('', Miscellaneous::toLatin($string)); - } - - /** - * @param string $expected Expected/converted string - * @param string $string String to convert - * @param string $replacementChar (optional) Replacement character for all non-latin characters - * - * @dataProvider provideStringToLatinNotLowerCaseHuman - */ - public function testToLatinNotLowerCaseHuman($expected, $string, $replacementChar = '-') - { - self::assertEquals($expected, Miscellaneous::toLatin($string, false, $replacementChar)); - } - - /** - * @param string $expected Expected/converted string - * @param string $string String to convert - * @param string $replacementChar (optional) Replacement character for all non-latin characters - * - * @dataProvider provideStringToLatinLowerCaseHuman - */ - public function testToLatinLowerCaseHuman($expected, $string, $replacementChar = '-') - { - self::assertEquals($expected, Miscellaneous::toLatin($string, true, $replacementChar)); - } - public function testGetUniqueString() { $prefix = ''; @@ -187,6 +1355,203 @@ class MiscellaneousTest extends BaseTestCase self::assertEquals(40, strlen(Miscellaneous::getUniqueString($prefix, $hashed))); } + public function testGetValidColorComponent() + { + // Negative cases + self::assertEquals(0, Miscellaneous::getValidColorComponent(null)); + self::assertEquals(0, Miscellaneous::getValidColorComponent('')); + self::assertEquals(0, Miscellaneous::getValidColorComponent('0')); + self::assertEquals(0, Miscellaneous::getValidColorComponent(0)); + self::assertEquals(0, Miscellaneous::getValidColorComponent(256)); + self::assertEquals(0, Miscellaneous::getValidColorComponent(256, false)); + + // Positive cases - part 1 + self::assertEquals(1, Miscellaneous::getValidColorComponent(1)); + self::assertEquals('0a', Miscellaneous::getValidColorComponent(10)); + self::assertEquals('0f', Miscellaneous::getValidColorComponent(15)); + self::assertEquals(64, Miscellaneous::getValidColorComponent(100)); + self::assertEquals('ff', Miscellaneous::getValidColorComponent(255)); + + // Positive cases - part 2 + self::assertEquals(1, Miscellaneous::getValidColorComponent(1, false)); + self::assertEquals(10, Miscellaneous::getValidColorComponent(10, false)); + self::assertEquals(15, Miscellaneous::getValidColorComponent(15, false)); + self::assertEquals(100, Miscellaneous::getValidColorComponent(100, false)); + self::assertEquals(255, Miscellaneous::getValidColorComponent(255, false)); + } + + public function testIncludeFileExtension() + { + $fileName = 'lorem-ipsum.jpg'; + + self::assertEquals($fileName, Miscellaneous::includeFileExtension($fileName, 'jpg')); + self::assertEquals(sprintf('%s.%s', $fileName, 'txt'), Miscellaneous::includeFileExtension($fileName, 'txt')); + } + + public function testIsBetween() + { + // Negative cases + self::assertFalse(Miscellaneous::isBetween(0, 0, 0)); + self::assertFalse(Miscellaneous::isBetween('0', '0', '0')); + self::assertFalse(Miscellaneous::isBetween(0, 0, 1)); + self::assertFalse(Miscellaneous::isBetween(-1, -1, -1)); + self::assertFalse(Miscellaneous::isBetween(1.2, 0.1, 1.1)); + + // Positive cases + self::assertTrue(Miscellaneous::isBetween(1, 0, 2)); + self::assertTrue(Miscellaneous::isBetween('1', '0', '2')); + self::assertTrue(Miscellaneous::isBetween(-1, -2, 2)); + self::assertTrue(Miscellaneous::isBetween(1.1, 0.1, 1.2)); + } + + public function testIsDecimal() + { + self::assertTrue(Miscellaneous::isDecimal(1.2)); + self::assertTrue(Miscellaneous::isDecimal('1.2')); + self::assertFalse(Miscellaneous::isDecimal('a')); + self::assertFalse(Miscellaneous::isDecimal(1)); + } + + public function testIsFilePath() + { + $filePath = __FILE__; + $directoryPath = dirname($filePath); + + self::assertTrue(Miscellaneous::isFilePath($filePath)); + self::assertFalse(Miscellaneous::isFilePath($directoryPath)); + } + + public function testIsPhpModuleLoaded() + { + $loadedExtensions = get_loaded_extensions(); + $firstExtension = $loadedExtensions[0]; + + self::assertTrue(Miscellaneous::isPhpModuleLoaded($firstExtension)); + self::assertFalse(Miscellaneous::isPhpModuleLoaded('xyz123')); + } + + public function testLowercaseFirst() + { + self::assertEquals('', Miscellaneous::lowercaseFirst('')); + self::assertEquals('', Miscellaneous::lowercaseFirst(null)); + self::assertEquals('', Miscellaneous::lowercaseFirst(false)); + + $text = 'LorEM ipsum dolor sit Amet'; + self::assertEquals('lorEM ipsum dolor sit Amet', Miscellaneous::lowercaseFirst($text)); + + $restLowercase = true; + self::assertEquals('lorem ipsum dolor sit amet', Miscellaneous::lowercaseFirst($text, $restLowercase)); + + $restLowercase = false; + self::assertEquals('lOREM IPSUM DOLOR SIT AMET', Miscellaneous::lowercaseFirst($text, $restLowercase)); + } + + public function testQuoteValue() + { + self::assertEquals(123, Miscellaneous::quoteValue(123)); + self::assertEquals('\'lorem ipsum\'', Miscellaneous::quoteValue('lorem ipsum')); + self::assertEquals('"lorem ipsum"', Miscellaneous::quoteValue('lorem ipsum', false)); + } + + public function testRemoveDirectoryUsingComplexDirectory() + { + $directory1Path = sys_get_temp_dir().'/lorem/ipsum'; + $directory2Path = sys_get_temp_dir().'/lorem/dolor/sit'; + + // Directory does not exist? Let's create it + // Required to avoid test failure + if (!file_exists($directory1Path)) { + mkdir($directory1Path, 0777, true); + } + + // Directory does not exist? Let's create it + // Required to avoid test failure + if (!file_exists($directory2Path)) { + mkdir($directory2Path, 0777, true); + } + + self::assertTrue(Miscellaneous::removeDirectory(sys_get_temp_dir().'/lorem')); + } + + public function testRemoveDirectoryUsingNoDirectory() + { + $directoryPath = sys_get_temp_dir().'/ipsum.txt'; + touch($directoryPath); + self::assertTrue(Miscellaneous::removeDirectory($directoryPath)); + } + + public function testRemoveDirectoryUsingNotExistingDirectory() + { + self::assertNull(Miscellaneous::removeDirectory('/abc/def/ghi')); + } + + public function testRemoveDirectoryUsingSimpleDirectory() + { + $directoryPath = sys_get_temp_dir().'/lorem/ipsum'; + mkdir($directoryPath, 0777, true); + self::assertTrue(Miscellaneous::removeDirectory($directoryPath)); + } + + /** + * @param string $text Text that may contain a directory's separator at the end + * @param string $separator (optional) The directory's separator, e.g. "/" + * @param string $expected Text without the ending directory's separator + * + * @dataProvider providePathsToRemoveEndingDirectorySeparator + */ + public function testRemoveEndingDirectorySeparator($text, $separator, $expected) + { + self::assertEquals($expected, Miscellaneous::removeEndingDirectorySeparator($text, $separator)); + } + + /** + * @param string $text Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testRemoveEndingDirectorySeparatorEmptyValue($text) + { + self::assertEquals('', Miscellaneous::removeEndingDirectorySeparator($text)); + } + + /** + * @param string $description Description of test case + * @param string $string The string which should be shortened + * @param bool $last (optional) If is set to true, last element is removed (default behaviour). + * Otherwise - first. + * @param null|string $expected Expected result + * + * @dataProvider provideStringToRemoveMarginalCharacter + */ + public function testRemoveMarginalCharacter( + string $description, + string $string, + bool $last, + ?string $expected + ): void { + self::assertEquals($expected, Miscellaneous::removeMarginalCharacter($string, $last), $description); + } + + /** + * @param string $text Text that may contain a directory's separator at the start / beginning + * @param string $separator The directory's separator, e.g. "/" + * @param string $expected Text without the starting / beginning directory's separator + * + * @dataProvider providePathsToRemoveStartingDirectorySeparator + */ + public function testRemoveStartingDirectorySeparator($text, $separator, $expected) + { + self::assertEquals($expected, Miscellaneous::removeStartingDirectorySeparator($text, $separator)); + } + + /** + * @param string $text Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testRemoveStartingDirectorySeparatorEmptyValue($text) + { + self::assertEquals('', Miscellaneous::removeStartingDirectorySeparator($text)); + } + /** * @param array|string $search An empty value to find * @dataProvider provideEmptyValue @@ -235,9 +1600,9 @@ class MiscellaneousTest extends BaseTestCase * strings. * @param mixed $result Result of replacing * - * @dataProvider provideStringsToReplace + * @dataProvider provideRegexToReplace */ - public function testReplaceUsingStrings($description, $subject, $search, $replacement, $result) + public function testReplaceUsingRegex($description, $subject, $search, $replacement, $result) { static::assertSame($result, Miscellaneous::replace($subject, $search, $replacement), $description); } @@ -251,9 +1616,9 @@ class MiscellaneousTest extends BaseTestCase * strings. * @param mixed $result Result of replacing * - * @dataProvider provideRegexToReplace + * @dataProvider provideStringsToReplace */ - public function testReplaceUsingRegex($description, $subject, $search, $replacement, $result) + public function testReplaceUsingStrings($description, $subject, $search, $replacement, $result) { static::assertSame($result, Miscellaneous::replace($subject, $search, $replacement), $description); } @@ -274,6 +1639,58 @@ class MiscellaneousTest extends BaseTestCase static::assertSame($result, Miscellaneous::replace($subject, $search, $replacement, true), $description); } + public function testSubstringToWord() + { + $suffix = '...'; + + self::assertEquals('Lorem ipsum'.$suffix, Miscellaneous::substringToWord($this->stringCommaSeparated, 20)); + self::assertEquals('Lorem ipsum dolor sit'.$suffix, Miscellaneous::substringToWord($this->stringCommaSeparated, 25)); + + self::assertEquals('Lorem ipsum dolor', Miscellaneous::substringToWord($this->stringCommaSeparated, 20, '')); + self::assertEquals('Lorem ipsum dolor sit amet, consectetur', Miscellaneous::substringToWord($this->stringCommaSeparated, 40, '')); + } + + /** + * @param mixed $string Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testToLatinEmptyValue($string) + { + self::assertEquals('', Miscellaneous::toLatin($string)); + } + + /** + * @param string $expected Expected/converted string + * @param string $string String to convert + * @param string $replacementChar (optional) Replacement character for all non-latin characters + * + * @dataProvider provideStringToLatinLowerCaseHuman + */ + public function testToLatinLowerCaseHuman($expected, $string, $replacementChar = '-') + { + self::assertEquals($expected, Miscellaneous::toLatin($string, true, $replacementChar)); + } + + /** + * @param string $expected Expected/converted string + * @param string $string String to convert + * @param string $replacementChar (optional) Replacement character for all non-latin characters + * + * @dataProvider provideStringToLatinNotLowerCaseHuman + */ + public function testToLatinNotLowerCaseHuman($expected, $string, $replacementChar = '-') + { + self::assertEquals($expected, Miscellaneous::toLatin($string, false, $replacementChar)); + } + + public function testTrimSmart() + { + self::assertNull(Miscellaneous::trimSmart(null)); + self::assertEquals(' ', Miscellaneous::trimSmart(' ')); + self::assertEquals('lorem ipsum', Miscellaneous::trimSmart(' lorem ipsum')); + self::assertEquals('lorem ipsum', Miscellaneous::trimSmart(' lorem ipsum ')); + } + public function testUppercaseFirst() { self::assertEquals('', Miscellaneous::uppercaseFirst('')); @@ -290,1428 +1707,11 @@ class MiscellaneousTest extends BaseTestCase self::assertEquals('LOREM IPSUM DOLOR SIT AMET', Miscellaneous::uppercaseFirst($text, $restLowercase)); } - public function testLowercaseFirst() + public function testValue2NonNegativeInteger() { - self::assertEquals('', Miscellaneous::lowercaseFirst('')); - self::assertEquals('', Miscellaneous::lowercaseFirst(null)); - self::assertEquals('', Miscellaneous::lowercaseFirst(false)); - - $text = 'LorEM ipsum dolor sit Amet'; - self::assertEquals('lorEM ipsum dolor sit Amet', Miscellaneous::lowercaseFirst($text)); - - $restLowercase = true; - self::assertEquals('lorem ipsum dolor sit amet', Miscellaneous::lowercaseFirst($text, $restLowercase)); - - $restLowercase = false; - self::assertEquals('lOREM IPSUM DOLOR SIT AMET', Miscellaneous::lowercaseFirst($text, $restLowercase)); - } - - public function testGetNewFileName() - { - self::assertEquals('test.jpg', Miscellaneous::getNewFileName('test.jpg', '', '')); - self::assertEquals('my-test.jpg', Miscellaneous::getNewFileName('test.jpg', 'my-', '')); - self::assertEquals('test-file.jpg', Miscellaneous::getNewFileName('test.jpg', '', '-file')); - self::assertEquals('my-test-file.jpg', Miscellaneous::getNewFileName('test.jpg', 'my-', '-file')); - } - - public function testGetOperatingSystemNameServer() - { - // While running Docker OS is a Linux - self::assertEquals('Linux', Miscellaneous::getOperatingSystemNameServer()); - } - - public function testSubstringToWord() - { - $suffix = '...'; - - self::assertEquals('Lorem ipsum' . $suffix, Miscellaneous::substringToWord($this->stringCommaSeparated, 20)); - self::assertEquals('Lorem ipsum dolor sit' . $suffix, Miscellaneous::substringToWord($this->stringCommaSeparated, 25)); - - self::assertEquals('Lorem ipsum dolor', Miscellaneous::substringToWord($this->stringCommaSeparated, 20, '')); - self::assertEquals('Lorem ipsum dolor sit amet, consectetur', Miscellaneous::substringToWord($this->stringCommaSeparated, 40, '')); - } - - public function testBreakLongText() - { - self::assertEquals('Lorem ipsum dolor sit
amet, consectetur
adipiscing
elit', Miscellaneous::breakLongText($this->stringCommaSeparated, 20)); - self::assertEquals('Lorem ipsum dolor sit---amet, consectetur---adipiscing---elit', Miscellaneous::breakLongText($this->stringCommaSeparated, 20, '---')); - self::assertEquals('LoremIpsum
DolorSitAm
etConsecte
turAdipisc
ingElit', Miscellaneous::breakLongText($this->stringWithoutSpaces, 10)); - } - - public function testRemoveDirectoryUsingNotExistingDirectory() - { - self::assertNull(Miscellaneous::removeDirectory('/abc/def/ghi')); - } - - public function testRemoveDirectoryUsingNoDirectory() - { - $directoryPath = sys_get_temp_dir() . '/ipsum.txt'; - touch($directoryPath); - self::assertTrue(Miscellaneous::removeDirectory($directoryPath)); - } - - public function testRemoveDirectoryUsingSimpleDirectory() - { - $directoryPath = sys_get_temp_dir() . '/lorem/ipsum'; - mkdir($directoryPath, 0777, true); - self::assertTrue(Miscellaneous::removeDirectory($directoryPath)); - } - - public function testRemoveDirectoryUsingComplexDirectory() - { - $directory1Path = sys_get_temp_dir() . '/lorem/ipsum'; - $directory2Path = sys_get_temp_dir() . '/lorem/dolor/sit'; - - // Directory does not exist? Let's create it - // Required to avoid test failure - if (!file_exists($directory1Path)) { - mkdir($directory1Path, 0777, true); - } - - // Directory does not exist? Let's create it - // Required to avoid test failure - if (!file_exists($directory2Path)) { - mkdir($directory2Path, 0777, true); - } - - self::assertTrue(Miscellaneous::removeDirectory(sys_get_temp_dir() . '/lorem')); - } - - /** - * @param string $text Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testRemoveStartingDirectorySeparatorEmptyValue($text) - { - self::assertEquals('', Miscellaneous::removeStartingDirectorySeparator($text)); - } - - /** - * @param string $text Text that may contain a directory's separator at the start / beginning - * @param string $separator The directory's separator, e.g. "/" - * @param string $expected Text without the starting / beginning directory's separator - * - * @dataProvider providePathsToRemoveStartingDirectorySeparator - */ - public function testRemoveStartingDirectorySeparator($text, $separator, $expected) - { - self::assertEquals($expected, Miscellaneous::removeStartingDirectorySeparator($text, $separator)); - } - - /** - * @param string $text Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testRemoveEndingDirectorySeparatorEmptyValue($text) - { - self::assertEquals('', Miscellaneous::removeEndingDirectorySeparator($text)); - } - - /** - * @param string $text Text that may contain a directory's separator at the end - * @param string $separator (optional) The directory's separator, e.g. "/" - * @param string $expected Text without the ending directory's separator - * - * @dataProvider providePathsToRemoveEndingDirectorySeparator - */ - public function testRemoveEndingDirectorySeparator($text, $separator, $expected) - { - self::assertEquals($expected, Miscellaneous::removeEndingDirectorySeparator($text, $separator)); - } - - public function testIsDecimal() - { - self::assertTrue(Miscellaneous::isDecimal(1.2)); - self::assertTrue(Miscellaneous::isDecimal('1.2')); - self::assertFalse(Miscellaneous::isDecimal('a')); - self::assertFalse(Miscellaneous::isDecimal(1)); - } - - public function testIsFilePath() - { - $filePath = __FILE__; - $directoryPath = dirname($filePath); - - self::assertTrue(Miscellaneous::isFilePath($filePath)); - self::assertFalse(Miscellaneous::isFilePath($directoryPath)); - } - - /** - * @param string $string The string to convert e.g. this-is-eXamplE (return: thisIsExample) - * @dataProvider provideEmptyValue - */ - public function testGetCamelCaseEmptyValue($string) - { - self::assertEquals('', Miscellaneous::getCamelCase($string)); - } - - /** - * @param string $string The string to convert e.g. this-is-eXamplE (return: thisIsExample) - * @param string $separator (optional) Separator used to find parts of the string, e.g. '-' or ',' - * @param string $expected String in camel case - * - * @dataProvider provideStringToCamelCase - */ - public function testGetCamelCase($string, $separator, $expected) - { - self::assertEquals($expected, Miscellaneous::getCamelCase($string, $separator)); - } - - public function testQuoteValue() - { - self::assertEquals(123, Miscellaneous::quoteValue(123)); - self::assertEquals('\'lorem ipsum\'', Miscellaneous::quoteValue('lorem ipsum')); - self::assertEquals('"lorem ipsum"', Miscellaneous::quoteValue('lorem ipsum', false)); - } - - public function testGetHumanReadableSize() - { - Locale::setLocale(LC_ALL, 'en', 'US'); - - self::assertEquals('400 B', Miscellaneous::getHumanReadableSize(400)); - self::assertEquals('1 KB', Miscellaneous::getHumanReadableSize(1024)); - self::assertEquals('1 MB', Miscellaneous::getHumanReadableSize(1024 * 1024)); - self::assertEquals('1.75 MB', Miscellaneous::getHumanReadableSize(1024 * 1024 * 1.75)); - } - - /** - * @param string $description - * @param string $string - * @param string $separator - * @param string|null $expected - * - * @dataProvider provideLastElementOfString - */ - public function testGetLastElementOfString( - string $description, - string $string, - string $separator, - ?string $expected - ): void { - self::assertEquals($expected, Miscellaneous::getLastElementOfString($string, $separator), $description); - } - - public function testTrimSmart() - { - self::assertNull(Miscellaneous::trimSmart(null)); - self::assertEquals(' ', Miscellaneous::trimSmart(' ')); - self::assertEquals('lorem ipsum', Miscellaneous::trimSmart(' lorem ipsum')); - self::assertEquals('lorem ipsum', Miscellaneous::trimSmart(' lorem ipsum ')); - } - - /** - * @param mixed $emptyPaths Empty paths co concatenate - * @dataProvider provideEmptyValue - */ - public function testConcatenatePathsWithEmptyPaths($emptyPaths) - { - self::assertEquals('', Miscellaneous::concatenatePaths($emptyPaths)); - } - - public function testConcatenatePathsWithOneEmptyPath() - { - $paths = [ - 'first/directory', - 'second/one', - '', - 'and/the/third', - ]; - - $concatenated = Miscellaneous::concatenatePaths($paths); - unset($paths[2]); - $imploded = implode('/', $paths); - - self::assertEquals('/' . $imploded, $concatenated); - } - - public function testConcatenatePathsInNixOs() - { - // For *nix operating system - $paths1 = [ - 'first/directory', - 'second/one', - 'and/the/third', - ]; - - self::assertEquals('/' . implode('/', $paths1), Miscellaneous::concatenatePaths($paths1)); - self::assertEquals('/' . implode('/', $paths1), Miscellaneous::concatenatePaths($paths1[0], $paths1[1], $paths1[2])); - } - - public function testConcatenatePathsInWindowsOs() - { - // For Windows operating system - $paths2 = [ - 'C:\first\directory', - 'second\one', - 'and\the\third', - ]; - - self::assertEquals(implode('\\', $paths2), Miscellaneous::concatenatePaths($paths2)); - } - - public function testIncludeFileExtension() - { - $fileName = 'lorem-ipsum.jpg'; - - self::assertEquals($fileName, Miscellaneous::includeFileExtension($fileName, 'jpg')); - self::assertEquals(sprintf('%s.%s', $fileName, 'txt'), Miscellaneous::includeFileExtension($fileName, 'txt')); - } - - /** - * @param string $description - * @param string $string - * @param string $separator - * @param array $expected - * - * @dataProvider provideStringElements - */ - public function testGetStringElements( - string $description, - string $string, - string $separator, - array $expected - ): void { - self::assertEquals($expected, Miscellaneous::getStringElements($string, $separator), $description); - } - - public function testGetStringWithoutLastElement() - { - self::assertEquals('Lorem ipsum dolor sit', Miscellaneous::getStringWithoutLastElement($this->stringSmall, ' ')); - self::assertEquals('', Miscellaneous::getStringWithoutLastElement($this->stringSmall, ';')); - } - - public function testGetSafelyGlobalVariable() - { - self::assertEquals('', Miscellaneous::getSafelyGlobalVariable(INPUT_GET, 'lorem')); - self::assertEquals('', Miscellaneous::getSafelyGlobalVariable(INPUT_POST, 'lorem')); - self::assertEquals('', Miscellaneous::getSafelyGlobalVariable(INPUT_COOKIE, 'lorem')); - self::assertEquals('', Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'lorem')); - self::assertEquals('', Miscellaneous::getSafelyGlobalVariable(INPUT_ENV, 'lorem')); - - $_GET['lorem'] = 123; - self::assertEquals(123, Miscellaneous::getSafelyGlobalVariable(INPUT_GET, 'lorem')); - } - - public function testIsBetween() - { - // Negative cases - self::assertFalse(Miscellaneous::isBetween(0, 0, 0)); - self::assertFalse(Miscellaneous::isBetween('0', '0', '0')); - self::assertFalse(Miscellaneous::isBetween(0, 0, 1)); - self::assertFalse(Miscellaneous::isBetween(-1, -1, -1)); - self::assertFalse(Miscellaneous::isBetween(1.2, 0.1, 1.1)); - - // Positive cases - self::assertTrue(Miscellaneous::isBetween(1, 0, 2)); - self::assertTrue(Miscellaneous::isBetween('1', '0', '2')); - self::assertTrue(Miscellaneous::isBetween(-1, -2, 2)); - self::assertTrue(Miscellaneous::isBetween(1.1, 0.1, 1.2)); - } - - public function testGetType() - { - self::assertEquals('NULL', Miscellaneous::getType(null)); - self::assertEquals('string', Miscellaneous::getType($this->stringSmall)); - self::assertEquals('integer', Miscellaneous::getType(123)); - self::assertEquals('double', Miscellaneous::getType(1.23)); - self::assertEquals('array', Miscellaneous::getType([])); - self::assertEquals('stdClass', Miscellaneous::getType(new stdClass())); - self::assertEquals(__CLASS__, Miscellaneous::getType(new self())); - } - - public function testGetValidColorComponent() - { - // Negative cases - self::assertEquals(0, Miscellaneous::getValidColorComponent(null)); - self::assertEquals(0, Miscellaneous::getValidColorComponent('')); - self::assertEquals(0, Miscellaneous::getValidColorComponent('0')); - self::assertEquals(0, Miscellaneous::getValidColorComponent(0)); - self::assertEquals(0, Miscellaneous::getValidColorComponent(256)); - self::assertEquals(0, Miscellaneous::getValidColorComponent(256, false)); - - // Positive cases - part 1 - self::assertEquals(1, Miscellaneous::getValidColorComponent(1)); - self::assertEquals('0a', Miscellaneous::getValidColorComponent(10)); - self::assertEquals('0f', Miscellaneous::getValidColorComponent(15)); - self::assertEquals(64, Miscellaneous::getValidColorComponent(100)); - self::assertEquals('ff', Miscellaneous::getValidColorComponent(255)); - - // Positive cases - part 2 - self::assertEquals(1, Miscellaneous::getValidColorComponent(1, false)); - self::assertEquals(10, Miscellaneous::getValidColorComponent(10, false)); - self::assertEquals(15, Miscellaneous::getValidColorComponent(15, false)); - self::assertEquals(100, Miscellaneous::getValidColorComponent(100, false)); - self::assertEquals(255, Miscellaneous::getValidColorComponent(255, false)); - } - - public function testGetInvertedColorWithIncorrectLength() - { - $this->expectException(IncorrectColorHexLengthException::class); - - Miscellaneous::getInvertedColor(null); - Miscellaneous::getInvertedColor(''); - Miscellaneous::getInvertedColor(1); - Miscellaneous::getInvertedColor(12); - Miscellaneous::getInvertedColor(1234567); - Miscellaneous::getInvertedColor('1'); - Miscellaneous::getInvertedColor('12'); - Miscellaneous::getInvertedColor('1234567'); - } - - public function testGetInvertedColorWithInvalidValue() - { - $this->expectException(InvalidColorHexValueException::class); - - Miscellaneous::getInvertedColor('0011zz'); - Miscellaneous::getInvertedColor('001#zz'); - Miscellaneous::getInvertedColor('001!zz'); - Miscellaneous::getInvertedColor('001-zz'); - Miscellaneous::getInvertedColor('00ppqq'); - } - - public function testGetInvertedColor() - { - // Simple cases - self::assertEquals('000000', Miscellaneous::getInvertedColor('fff')); - self::assertEquals('ffffff', Miscellaneous::getInvertedColor('000')); - self::assertEquals('000000', Miscellaneous::getInvertedColor('ffffff')); - self::assertEquals('ffffff', Miscellaneous::getInvertedColor('000000')); - self::assertEquals('#000000', Miscellaneous::getInvertedColor('#ffffff')); - self::assertEquals('#ffffff', Miscellaneous::getInvertedColor('#000000')); - - // Advanced cases - part 1 - self::assertEquals('ffffee', Miscellaneous::getInvertedColor('001')); - self::assertEquals('ffeeff', Miscellaneous::getInvertedColor('010')); - self::assertEquals('eeffff', Miscellaneous::getInvertedColor('100')); - self::assertEquals('333333', Miscellaneous::getInvertedColor('ccc')); - self::assertEquals('333333', Miscellaneous::getInvertedColor('CCC')); - - // Advanced cases - part 2 - self::assertEquals('3e3e3e', Miscellaneous::getInvertedColor('c1c1c1')); - self::assertEquals('3e3e3e', Miscellaneous::getInvertedColor('C1C1C1')); - self::assertEquals('#dd5a01', Miscellaneous::getInvertedColor('#22a5fe')); - self::assertEquals('#22dbb3', Miscellaneous::getInvertedColor('#dd244c')); - self::assertEquals('#464646', Miscellaneous::getInvertedColor('#b9b9b9')); - self::assertEquals('#080808', Miscellaneous::getInvertedColor('#f7f7f7')); - - // Advanced cases - verification - self::assertEquals('000011', Miscellaneous::getInvertedColor('ffffee')); - self::assertEquals('cccccc', Miscellaneous::getInvertedColor('333333')); - self::assertEquals('#22a5fe', Miscellaneous::getInvertedColor('#dd5a01')); - self::assertEquals('#22a5fe', Miscellaneous::getInvertedColor('#DD5A01')); - self::assertEquals('#f7f7f7', Miscellaneous::getInvertedColor('#080808')); - } - - /** - * @param mixed $number Number for who the "0" characters should be inserted - * @dataProvider provideEmptyValueToFillMissingZeros - */ - public function testFillMissingZerosEmptyValue($number) - { - self::assertEquals('', Miscellaneous::fillMissingZeros($number, 1)); - } - - /** - * @param mixed $number Number for who the "0" characters should be inserted - * @param int $length Wanted length of final number - * @param bool $before If false, 0 characters will be inserted after given number - * @param string $expected String with added missing the "0" characters - * - * @dataProvider provideNumberToFillMissingZeros - */ - public function testFillMissingZeros($number, $length, $before, $expected): void - { - self::assertSame($expected, Miscellaneous::fillMissingZeros($number, $length, $before)); - } - - public function testGetProjectRootPath(): void - { - self::assertNotEmpty(Miscellaneous::getProjectRootPath()); - } - - /** - * @param string $description Description of test case - * @param string $string The string which should be shortened - * @param bool $last (optional) If is set to true, last element is removed (default behaviour). - * Otherwise - first. - * @param null|string $expected Expected result - * - * @dataProvider provideStringToRemoveMarginalCharacter - */ - public function testRemoveMarginalCharacter( - string $description, - string $string, - bool $last, - ?string $expected - ): void { - self::assertEquals($expected, Miscellaneous::removeMarginalCharacter($string, $last), $description); - } - - /** - * @param int $first - * @param int $second - * @param int $expected - * - * @dataProvider provideGreatestCommonDivisor - */ - public function testCalculateGreatestCommonDivisor(int $first, int $second, int $expected): void - { - static::assertSame($expected, Miscellaneous::calculateGreatestCommonDivisor($first, $second)); - } - - /** - * Provides string to convert characters to latin characters and not lower cased and not human-readable - * - * @return Generator - */ - public function provideStringToLatinNotLowerCaseHuman(): ?Generator - { - yield[ - 'asuo', - 'ąśüö', - ]; - - yield[ - 'eoaslzzcn', - 'ęóąśłżźćń', - ]; - - yield[ - 'loremipsum', - 'loremipsum', - ]; - - yield[ - 'LoremIpsum', - 'LoremIpsum', - ]; - - yield[ - 'Lorem.Ipsum', - 'Lorem Ipsum', - '.', - ]; - - yield[ - 'Lorem.Ipsum', - 'Lorem=Ipsum', - '.', - ]; - - yield[ - 'LoremIpsumD', - 'LoremIpsumD', - ]; - - yield[ - 'LoremIpsumD', - 'LoremIpsumD', - '.', - ]; - - yield[ - 'lorem-ipsum', - 'lorem ipsum', - ]; - - yield[ - 'lorem-ipsum', - 'lorem;ipsum', - ]; - - yield[ - 'lorem1ipsum2', - 'lorem1ipsum2', - ]; - - yield[ - 'lorem_ipsum', - 'lorem ipsum', - '_', - ]; - - yield[ - 'LoremIpsum', - 'LoremIpsum', - ]; - - yield[ - 'Lorem Ipsum', - 'Lorem!Ipsum', - ' ', - ]; - - yield[ - 'Lorem Ipsum', - 'Lorem.Ipsum', - ' ', - ]; - - yield[ - 'Lorem|Ipsum', - 'Lorem.Ipsum', - '|', - ]; - } - - /** - * Provides string to convert characters to latin characters and lower cased and human-readable - * - * @return Generator - */ - public function provideStringToLatinLowerCaseHuman() - { - yield[ - 'asuo', - 'ąśüö', - ]; - - yield[ - 'eoaslzzcn', - 'ęóąśłżźćń', - ]; - - yield[ - 'loremipsum', - 'loremipsum', - ]; - - yield[ - 'lorem-ipsum', - 'lorem ipsum', - ]; - - yield[ - 'lorem-ipsum', - 'lorem;ipsum', - ]; - - yield[ - 'lorem1ipsum2', - 'lorem1ipsum2', - ]; - - yield[ - 'lorem_ipsum', - 'lorem ipsum', - '_', - ]; - - yield[ - 'lorem-ipsum', - 'lorem-ipsum', - ]; - - yield[ - 'lorem ipsum', - 'Lorem!Ipsum', - ' ', - ]; - - yield[ - 'lorem ipsum', - 'Lorem.Ipsum', - ' ', - ]; - - yield[ - 'lorem|ipsum', - 'Lorem.Ipsum', - '|', - ]; - - yield[ - 'lorem-ipsum', - 'LoremIpsum', - ]; - - yield[ - 'lorem.ipsum', - 'Lorem Ipsum', - '.', - ]; - - yield[ - 'lorem.ipsum', - 'Lorem=Ipsum', - '.', - ]; - - yield[ - 'lorem-ipsum-d', - 'LoremIpsumD', - ]; - - yield[ - 'lorem.ipsum.d', - 'LoremIpsumD', - '.', - ]; - } - - /** - * Provides names of files - * - * @return Generator - */ - public function provideFileNames() - { - yield[ - 'Lorem.ipsum-dolor.sit.JPG', - 'Lorem.ipsum-dolor.sit', - ]; - - yield[ - 'lets-test.doc', - 'lets-test', - ]; - - yield[ - 'something/else.txt', - 'something/else', - ]; - - yield[ - 'public/js/user.js', - 'public/js/user', - ]; - } - - /** - * Provides string to convert to camel case - * - * @return Generator - */ - public function provideStringToCamelCase() - { - yield[ - 'lorem ipsum', - ' ', - 'loremIpsum', - ]; - - yield[ - 'Lorem ipSum Dolor', - ' ', - 'loremIpsumDolor', - ]; - - yield[ - 'abc;def;ghi', - ';', - 'abcDefGhi', - ]; - } - - /** - * Provides path used to remove the starting / beginning directory's separator - * - * @return Generator - */ - public function providePathsToRemoveStartingDirectorySeparator() - { - yield[ - '/lorem/ipsum/dolor', - '/', - 'lorem/ipsum/dolor', - ]; - - yield[ - 'lorem/ipsum/dolor', - '/', - 'lorem/ipsum/dolor', - ]; - - yield[ - '\\lorem\ipsum\dolor', - '\\', - 'lorem\ipsum\dolor', - ]; - - yield[ - 'lorem\ipsum\dolor', - '\\', - 'lorem\ipsum\dolor', - ]; - - yield[ - ';lorem;ipsum;dolor', - ';', - 'lorem;ipsum;dolor', - ]; - - yield[ - 'lorem;ipsum;dolor', - ';', - 'lorem;ipsum;dolor', - ]; - } - - /** - * Provides path used to remove the ending directory's separator - * - * @return Generator - */ - public function providePathsToRemoveEndingDirectorySeparator() - { - yield[ - 'lorem/ipsum/dolor/', - '/', - 'lorem/ipsum/dolor', - ]; - - yield[ - 'lorem/ipsum/dolor', - '/', - 'lorem/ipsum/dolor', - ]; - - yield[ - 'lorem\ipsum\dolor\\', - '\\', - 'lorem\ipsum\dolor', - ]; - - yield[ - 'lorem\ipsum\dolor', - '\\', - 'lorem\ipsum\dolor', - ]; - - yield[ - 'lorem;ipsum;dolor;', - ';', - 'lorem;ipsum;dolor', - ]; - - yield[ - 'lorem;ipsum;dolor', - ';', - 'lorem;ipsum;dolor', - ]; - } - - /** - * Provides empty value used to fill missing zeros - * - * @return Generator - */ - public function provideEmptyValueToFillMissingZeros() - { - yield['']; - yield[' ']; - yield[null]; - yield[false]; - yield[[]]; - } - - /** - * Provides number used to fill missing zeros - * - * @return Generator - */ - public function provideNumberToFillMissingZeros() - { - yield[ - 0, - 0, - true, - '0', - ]; - - yield[ - 0, - 0, - false, - '0', - ]; - - yield[ - 1, - 0, - true, - '1', - ]; - - yield[ - 1, - 0, - false, - '1', - ]; - - yield[ - 1, - 1, - true, - '1', - ]; - - yield[ - 1, - 1, - false, - '1', - ]; - - yield[ - 123, - 5, - true, - '00123', - ]; - - yield[ - 123, - 5, - false, - '12300', - ]; - } - - public function provideEmptyValuesToReplace() - { - yield[ - 'An empty string as subject', - '', - 'test', - 'another test', - '', - ]; - - yield[ - 'An empty array as subject', - [], - 'test', - 'another test', - [], - ]; - - yield[ - 'Null as subject', - null, - 'test', - 'another test', - null, - ]; - - yield[ - 'An empty string to search', - 'test', - '', - 'another test', - 'test', - ]; - - yield[ - 'An empty array to search', - 'test', - [], - 'another test', - 'test', - ]; - - yield[ - 'Null to search', - 'test', - null, - 'another test', - 'test', - ]; - - yield[ - 'An empty string as replacement', - 'test', - 'another test', - '', - 'test', - ]; - - yield[ - 'An empty array as replacement', - 'test', - 'another test', - [], - 'test', - ]; - - yield[ - 'Null as replacement', - 'test', - 'another test', - null, - 'test', - ]; - } - - public function provideStringsToReplace() - { - yield[ - 'Different count of strings to search and replace - 1st part', - 'Lorem ipsum dolor sit amet', - [ - 'ipsum', - ], - 'commodo', - 'Lorem ipsum dolor sit amet', - ]; - - yield[ - 'Different count of strings to search and replace - 2nd part', - 'Lorem ipsum dolor sit amet', - 'ipsum', - [ - 'commodo', - ], - 'Lorem commodo dolor sit amet', - ]; - - yield[ - 'Replace 1 not existing word in 1 sentence (nothing to replace)', - 'Lorem ipsum dolor sit amet', - 'plum', - 'commodo', - 'Lorem ipsum dolor sit amet', - ]; - - yield[ - 'Replace 1 word in 1 sentence', - 'Lorem ipsum dolor sit amet', - 'ipsum', - 'commodo', - 'Lorem commodo dolor sit amet', - ]; - - yield[ - 'Replace 1 not existing word in 2 sentences (nothing to replace)', - [ - 'Lorem ipsum dolor sit amet', - 'Maecenas sed diam eget risus varius blandit sit amet', - ], - 'plum', - 'commodo', - [ - 'Lorem ipsum dolor sit amet', - 'Maecenas sed diam eget risus varius blandit sit amet', - ], - ]; - - yield[ - 'Replace 1 word in 2 sentences', - [ - 'Lorem ipsum dolor sit amet', - 'Maecenas sed diam eget risus varius blandit sit amet', - ], - 'amet', - 'commodo', - [ - 'Lorem ipsum dolor sit commodo', - 'Maecenas sed diam eget risus varius blandit sit commodo', - ], - ]; - } - - public function provideRegexToReplace() - { - yield[ - 'Different count of strings to search and replace - 1st part', - 'Lorem ipsum dolor sit amet', - [ - '|ipsum|', - ], - 'commodo', - 'Lorem ipsum dolor sit amet', - ]; - - yield[ - 'Different count of strings to search and replace - 2nd part', - 'Lorem ipsum dolor sit amet', - '|ipsum|', - [ - 'commodo', - ], - 'Lorem ipsum dolor sit amet', - ]; - - yield[ - '1 pattern (word -> "")', - 'Lorem ipsum dolor sit amet', - '|ipsum|', - '', - 'Lorem dolor sit amet', - ]; - - yield[ - '1 pattern (word -> word)', - 'Lorem ipsum dolor sit amet', - '|ipsum|', - 'commodo', - 'Lorem commodo dolor sit amet', - ]; - - yield[ - '2 patterns (word -> word)', - 'Lorem ipsum dolor sit amet', - [ - '|ipsum|', - '|amet|', - ], - [ - 'commodo', - 'egestas', - ], - 'Lorem commodo dolor sit egestas', - ]; - - yield[ - '1 word in 2 sentences', - [ - 'Lorem ipsum dolor sit amet', - 'Maecenas sed diam eget risus varius blandit sit amet', - ], - '|amet|', - 'commodo', - [ - 'Lorem ipsum dolor sit commodo', - 'Maecenas sed diam eget risus varius blandit sit commodo', - ], - ]; - - yield[ - '2 words in 2 sentences', - [ - 'Lorem ipsum dolor sit amet', - 'Maecenas sed diam eget risus varius blandit sit amet', - ], - [ - '|ipsum|', - '|amet|', - ], - [ - 'commodo', - 'egestas', - ], - [ - 'Lorem commodo dolor sit egestas', - 'Maecenas sed diam eget risus varius blandit sit egestas', - ], - ]; - } - - public function provideDataToReplaceWithQuoteStrings() - { - yield[ - 'An empty string as subject', - '', - 'test', - 'another test', - '', - ]; - - yield[ - 'An empty string to search', - 'test', - '', - 'another test', - 'test', - ]; - - yield[ - 'An empty string as replacement', - 'test', - 'another test', - '', - 'test', - ]; - - yield[ - 'Replace 1 not existing word in 1 sentence (nothing to replace)', - 'Lorem ipsum dolor sit amet', - 'plum', - 'commodo', - 'Lorem ipsum dolor sit amet', - ]; - - yield[ - 'Replace 1 word in 1 sentence', - 'Lorem ipsum dolor sit amet', - 'ipsum', - 'commodo', - 'Lorem \'commodo\' dolor sit amet', - ]; - - yield[ - 'Replace 1 word in 2 sentences', - [ - 'Lorem ipsum dolor sit amet', - 'Maecenas sed diam eget risus varius blandit sit amet', - ], - 'amet', - 'commodo', - [ - 'Lorem ipsum dolor sit \'commodo\'', - 'Maecenas sed diam eget risus varius blandit sit \'commodo\'', - ], - ]; - - yield[ - '1 pattern (word -> "")', - 'Lorem ipsum dolor sit amet', - '|ipsum|', - '', - 'Lorem \'\' dolor sit amet', - ]; - - yield[ - '1 pattern (word -> word)', - 'Lorem ipsum dolor sit amet', - '|ipsum|', - 'commodo', - 'Lorem \'commodo\' dolor sit amet', - ]; - - yield[ - '2 patterns (word -> word)', - 'Lorem ipsum dolor sit amet', - [ - '|ipsum|', - '|amet|', - ], - [ - 'commodo', - 'egestas', - ], - 'Lorem \'commodo\' dolor sit \'egestas\'', - ]; - } - - public function provideStringToRemoveMarginalCharacter(): ?Generator - { - yield[ - 'An empty string - remove last character', - '', - true, - null, - ]; - - yield[ - 'An empty string - remove first character', - '', - false, - null, - ]; - - yield[ - 'Simple, two words - remove last character', - 'Lorem ipsum', - true, - 'Lorem ipsu', - ]; - - yield[ - 'Simple, two words - remove first character', - 'Lorem ipsum', - false, - 'orem ipsum', - ]; - - yield[ - 'Two sentences - remove last character', - 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis.', - true, - 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis', - ]; - - yield[ - 'Two sentences - remove first character', - 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis.', - false, - 'tiam ullamcorper. Suspendisse a pellentesque dui, non felis.', - ]; - } - - public function provideGreatestCommonDivisor(): ?Generator - { - yield[ - 0, - 0, - 0, - ]; - - yield[ - 1, - 1, - 1, - ]; - - yield[ - 5, - 3, - 1, - ]; - - yield[ - 6, - 3, - 3, - ]; - - yield[ - 12, - 9, - 3, - ]; - - yield[ - 20, - 12, - 4, - ]; - - yield[ - 120, - 80, - 40, - ]; - } - - public function provideFilePath(): ?Generator - { - yield[ - 'Path with file', - 'lorem/ipsum-dolor/sit.amet.JPG', - 'sit.amet.JPG', - ]; - - yield[ - 'Path with complicated name of file', - 'lorem/ipsum-dolor/this-1_2 3 & my! 4+file.jpg', - 'this-1_2 3 & my! 4+file.jpg', - ]; - - yield[ - 'Path without file', - 'lorem/ipsum-dolor/sit-amet', - '', - ]; - - yield[ - 'Path with a dot "." in name of directory', - 'lorem/ipsum.dolor/sit.amet.JPG', - 'sit.amet.JPG', - ]; - - yield[ - 'Relative path', - 'lorem/ipsum/../dolor/sit.amet.JPG', - 'sit.amet.JPG', - ]; - } - - public function provideStringElements(): ?Generator - { - yield[ - 'An empty string', - '', - '', - [], - ]; - - yield[ - 'One-character string', - 'a', - ',', - [], - ]; - - yield[ - 'String without given separator', - 'abc', - ',', - [], - ]; - - yield[ - 'Simple, short string', - 'a, b, c', - ',', - [ - 'a', - ' b', - ' c', - ], - ]; - - yield[ - 'A sentence', - 'Lorem ipsum - dolor sit - amet, consectetur adipiscing - elit.', - '-', - [ - 'Lorem ipsum ', - ' dolor sit ', - ' amet, consectetur adipiscing ', - ' elit.', - ], - ]; - - yield[ - 'A class namespace', - 'This\\Is\\My\\Class\\For\\Testing', - '\\', - [ - 'This', - 'Is', - 'My', - 'Class', - 'For', - 'Testing', - ], - ]; - } - - public function provideLastElementOfString(): ?Generator - { - yield[ - 'An empty string', - '', - '', - null, - ]; - - yield[ - 'One-character string', - 'a', - ',', - null, - ]; - - yield[ - 'String without given separator', - 'abc', - ',', - null, - ]; - - yield[ - 'Simple, short string', - 'a, b, c', - ',', - ' c', - ]; - - yield[ - 'A sentence', - 'Lorem ipsum - dolor sit - amet, consectetur adipiscing - elit.', - '-', - ' elit.', - ]; - - yield[ - 'A class namespace', - 'This\\Is\\My\\Class\\For\\Testing', - '\\', - 'Testing', - ]; + self::assertEquals(2, Miscellaneous::value2NonNegativeInteger('2')); + self::assertEquals(0, Miscellaneous::value2NonNegativeInteger('a')); + self::assertEquals('-', Miscellaneous::value2NonNegativeInteger('-4', '-')); } /** diff --git a/tests/Utilities/QueryBuilderUtilityTest.php b/tests/Utilities/QueryBuilderUtilityTest.php index 3f4aa4d..2b59e6a 100644 --- a/tests/Utilities/QueryBuilderUtilityTest.php +++ b/tests/Utilities/QueryBuilderUtilityTest.php @@ -17,6 +17,7 @@ use Doctrine\ORM\QueryBuilder; use Generator; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Utilities\QueryBuilderUtility; +use stdClass; /** * Test case of the useful methods for query builder (the Doctrine's QueryBuilder class) @@ -25,24 +26,260 @@ use Meritoo\Common\Utilities\QueryBuilderUtility; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Utilities\QueryBuilderUtility + * @covers \Meritoo\Common\Utilities\QueryBuilderUtility */ class QueryBuilderUtilityTest extends BaseTestCase { + /** + * Provides query builder and criteria used in WHERE clause + * + * @return Generator + */ + public function provideQueryBuilderAndCriteria() + { + $entityManager = $this + ->getMockBuilder(EntityManager::class) + ->disableOriginalConstructor() + ->setMethods(['getExpressionBuilder']) + ->getMock(); + + $entityManager + ->expects(static::any()) + ->method('getExpressionBuilder') + ->willReturn(new Expr()) + ; + + yield [ + (new QueryBuilder($entityManager))->from('lorem_ipsum', 'lm'), + [ + 'lorem' => 11, + 'ipsum' => 22, + 'dolor' => null, + ], + ]; + + yield [ + (new QueryBuilder($entityManager))->from('lorem_ipsum', 'lm'), + [ + 'lorem' => [ + 11, + '>=', + ], + 'ipsum' => [ + 22, + '<', + ], + 'dolor' => null, + ], + ]; + } + + /** + * Provides query builder and parameters to add to given query builder + * + * @return Generator + */ + public function provideQueryBuilderAndParameters() + { + $entityManager = $this->createMock(EntityManagerInterface::class); + + yield [ + new QueryBuilder($entityManager), + [], + ]; + + yield [ + new QueryBuilder($entityManager), + new ArrayCollection(), + ]; + + yield [ + new QueryBuilder($entityManager), + [ + 'lorem' => 11, + 'ipsum' => 22, + ], + ]; + + yield [ + new QueryBuilder($entityManager), + new ArrayCollection([ + 'lorem' => 11, + 'ipsum' => 22, + ]), + ]; + + yield [ + new QueryBuilder($entityManager), + [ + new Parameter('lorem', 11), + new Parameter('ipsum', 22), + ], + ]; + + yield [ + new QueryBuilder($entityManager), + new ArrayCollection([ + new Parameter('lorem', 11), + new Parameter('ipsum', 22), + ]), + ]; + } + + /** + * Provides query builder, name of property and expected alias of given property + * + * @return Generator + */ + public function provideQueryBuilderAndPropertyAlias() + { + $entityManager = $this->createMock(EntityManagerInterface::class); + + yield [ + new QueryBuilder($entityManager), + '', + null, + ]; + + yield [ + new QueryBuilder($entityManager), + 'lorem', + null, + ]; + + yield [ + (new QueryBuilder($entityManager))->from('lorem_ipsum', 'lm'), + 'lm', + null, + ]; + + yield [ + (new QueryBuilder($entityManager)) + ->from('lorem', 'l') + ->leftJoin('l.ipsum', 'i'), + 'ipsum', + 'i', + ]; + + yield [ + (new QueryBuilder($entityManager)) + ->from('lorem', 'l') + ->leftJoin('l.ipsum', 'i') + ->innerJoin('i.dolor', 'd'), + 'ipsum1', + null, + ]; + + yield [ + (new QueryBuilder($entityManager)) + ->from('lorem', 'l') + ->leftJoin('l.ipsum', 'i') + ->innerJoin('i.dolor', 'd'), + 'ipsum', + 'i', + ]; + + yield [ + (new QueryBuilder($entityManager)) + ->from('lorem', 'l') + ->leftJoin('l.ipsum', 'i') + ->innerJoin('i.dolor', 'd'), + 'dolor', + 'd', + ]; + } + + /** + * Provides query builder to retrieve root alias and expected root alias + * + * @return Generator + */ + public function provideQueryBuilderAndRootAlias() + { + $entityManager = $this->createMock(EntityManagerInterface::class); + + yield [ + new QueryBuilder($entityManager), + null, + ]; + + yield [ + (new QueryBuilder($entityManager))->from('lorem_ipsum', 'lm'), + 'lm', + ]; + + yield [ + (new QueryBuilder($entityManager)) + ->from('lorem', 'l') + ->leftJoin('l.ipsum', 'i'), + 'l', + ]; + } + + /** + * @param QueryBuilder $queryBuilder The query builder + * @param array|ArrayCollection $parameters Parameters to add. Collection of Doctrine\ORM\Query\Parameter + * instances or an array with key-value pairs. + * + * @dataProvider provideQueryBuilderAndParameters + */ + public function testAddParameters(QueryBuilder $queryBuilder, $parameters) + { + $newQueryBuilder = QueryBuilderUtility::addParameters($queryBuilder, $parameters); + + static::assertSame($queryBuilder, $newQueryBuilder); + static::assertCount(count($parameters), $newQueryBuilder->getParameters()); + } + public function testConstructor() { static::assertHasNoConstructor(QueryBuilderUtility::class); } - /** - * @param QueryBuilder $queryBuilder The query builder to retrieve root alias - * @param null|string $rootAlias Expected root alias of given query builder - * - * @dataProvider provideQueryBuilderAndRootAlias - */ - public function testGetRootAlias(QueryBuilder $queryBuilder, $rootAlias) + public function testDeleteEntities() { - static::assertSame($rootAlias, QueryBuilderUtility::getRootAlias($queryBuilder)); + $methods = [ + 'remove', + 'flush', + ]; + + $entityManager = $this + ->getMockBuilder(EntityManager::class) + ->disableOriginalConstructor() + ->setMethods($methods) + ->getMock(); + + $entities1 = []; + + $entities2 = [ + new stdClass(), + ]; + + static::assertFalse(QueryBuilderUtility::deleteEntities($entityManager, $entities1)); + static::assertTrue(QueryBuilderUtility::deleteEntities($entityManager, $entities2)); + } + + public function testDeleteEntitiesWithoutFlush() + { + $methods = [ + 'remove', + 'flush', + ]; + + $entityManager = $this + ->getMockBuilder(EntityManager::class) + ->disableOriginalConstructor() + ->setMethods($methods) + ->getMock(); + + $entities1 = []; + + $entities2 = [ + new stdClass(), + ]; + + static::assertFalse(QueryBuilderUtility::deleteEntities($entityManager, $entities1, false)); + static::assertTrue(QueryBuilderUtility::deleteEntities($entityManager, $entities2, false)); } /** @@ -57,31 +294,15 @@ class QueryBuilderUtilityTest extends BaseTestCase static::assertSame($propertyAlias, QueryBuilderUtility::getJoinedPropertyAlias($queryBuilder, $propertyName)); } - public function testSetCriteriaWithoutCriteria() + /** + * @param QueryBuilder $queryBuilder The query builder to retrieve root alias + * @param null|string $rootAlias Expected root alias of given query builder + * + * @dataProvider provideQueryBuilderAndRootAlias + */ + public function testGetRootAlias(QueryBuilder $queryBuilder, $rootAlias) { - $entityManager = $this->createMock(EntityManagerInterface::class); - $queryBuilder = new QueryBuilder($entityManager); - $newQueryBuilder = QueryBuilderUtility::setCriteria($queryBuilder); - - static::assertSame($queryBuilder, $newQueryBuilder); - static::assertCount(0, $newQueryBuilder->getParameters()); - static::assertNull($newQueryBuilder->getDQLPart('where')); - } - - public function testSetCriteriaWithoutAlias() - { - $criteria = [ - 'lorem' => 11, - 'ipsum' => 22, - ]; - - $entityManager = $this->createMock(EntityManagerInterface::class); - $queryBuilder = new QueryBuilder($entityManager); - $newQueryBuilder = QueryBuilderUtility::setCriteria($queryBuilder, $criteria); - - static::assertSame($queryBuilder, $newQueryBuilder); - static::assertCount(count($criteria), $newQueryBuilder->getParameters()); - static::assertNotNull($newQueryBuilder->getDQLPart('where')); + static::assertSame($rootAlias, QueryBuilderUtility::getRootAlias($queryBuilder)); } /** @@ -108,253 +329,30 @@ class QueryBuilderUtilityTest extends BaseTestCase static::assertNotNull($newQueryBuilder->getDQLPart('where')); } - public function testDeleteEntitiesWithoutFlush() + public function testSetCriteriaWithoutAlias() { - $methods = [ - 'remove', - 'flush', + $criteria = [ + 'lorem' => 11, + 'ipsum' => 22, ]; - $entityManager = $this - ->getMockBuilder(EntityManager::class) - ->disableOriginalConstructor() - ->setMethods($methods) - ->getMock() - ; - - $entities1 = []; - - $entities2 = [ - new \stdClass(), - ]; - - static::assertFalse(QueryBuilderUtility::deleteEntities($entityManager, $entities1, false)); - static::assertTrue(QueryBuilderUtility::deleteEntities($entityManager, $entities2, false)); - } - - public function testDeleteEntities() - { - $methods = [ - 'remove', - 'flush', - ]; - - $entityManager = $this - ->getMockBuilder(EntityManager::class) - ->disableOriginalConstructor() - ->setMethods($methods) - ->getMock() - ; - - $entities1 = []; - - $entities2 = [ - new \stdClass(), - ]; - - static::assertFalse(QueryBuilderUtility::deleteEntities($entityManager, $entities1)); - static::assertTrue(QueryBuilderUtility::deleteEntities($entityManager, $entities2)); - } - - /** - * @param QueryBuilder $queryBuilder The query builder - * @param array|ArrayCollection $parameters Parameters to add. Collection of Doctrine\ORM\Query\Parameter - * instances or an array with key-value pairs. - * - * @dataProvider provideQueryBuilderAndParameters - */ - public function testAddParameters(QueryBuilder $queryBuilder, $parameters) - { - $newQueryBuilder = QueryBuilderUtility::addParameters($queryBuilder, $parameters); + $entityManager = $this->createMock(EntityManagerInterface::class); + $queryBuilder = new QueryBuilder($entityManager); + $newQueryBuilder = QueryBuilderUtility::setCriteria($queryBuilder, $criteria); static::assertSame($queryBuilder, $newQueryBuilder); - static::assertCount(count($parameters), $newQueryBuilder->getParameters()); + static::assertCount(count($criteria), $newQueryBuilder->getParameters()); + static::assertNotNull($newQueryBuilder->getDQLPart('where')); } - /** - * Provides query builder to retrieve root alias and expected root alias - * - * @return Generator - */ - public function provideQueryBuilderAndRootAlias() + public function testSetCriteriaWithoutCriteria() { $entityManager = $this->createMock(EntityManagerInterface::class); + $queryBuilder = new QueryBuilder($entityManager); + $newQueryBuilder = QueryBuilderUtility::setCriteria($queryBuilder); - yield[ - new QueryBuilder($entityManager), - null, - ]; - - yield[ - (new QueryBuilder($entityManager))->from('lorem_ipsum', 'lm'), - 'lm', - ]; - - yield[ - (new QueryBuilder($entityManager)) - ->from('lorem', 'l') - ->leftJoin('l.ipsum', 'i'), - 'l', - ]; - } - - /** - * Provides query builder, name of property and expected alias of given property - * - * @return Generator - */ - public function provideQueryBuilderAndPropertyAlias() - { - $entityManager = $this->createMock(EntityManagerInterface::class); - - yield[ - new QueryBuilder($entityManager), - '', - null, - ]; - - yield[ - new QueryBuilder($entityManager), - 'lorem', - null, - ]; - - yield[ - (new QueryBuilder($entityManager))->from('lorem_ipsum', 'lm'), - 'lm', - null, - ]; - - yield[ - (new QueryBuilder($entityManager)) - ->from('lorem', 'l') - ->leftJoin('l.ipsum', 'i'), - 'ipsum', - 'i', - ]; - - yield[ - (new QueryBuilder($entityManager)) - ->from('lorem', 'l') - ->leftJoin('l.ipsum', 'i') - ->innerJoin('i.dolor', 'd'), - 'ipsum1', - null, - ]; - - yield[ - (new QueryBuilder($entityManager)) - ->from('lorem', 'l') - ->leftJoin('l.ipsum', 'i') - ->innerJoin('i.dolor', 'd'), - 'ipsum', - 'i', - ]; - - yield[ - (new QueryBuilder($entityManager)) - ->from('lorem', 'l') - ->leftJoin('l.ipsum', 'i') - ->innerJoin('i.dolor', 'd'), - 'dolor', - 'd', - ]; - } - - /** - * Provides query builder and criteria used in WHERE clause - * - * @return Generator - */ - public function provideQueryBuilderAndCriteria() - { - $entityManager = $this - ->getMockBuilder(EntityManager::class) - ->disableOriginalConstructor() - ->setMethods(['getExpressionBuilder']) - ->getMock() - ; - - $entityManager - ->expects(static::any()) - ->method('getExpressionBuilder') - ->willReturn(new Expr()) - ; - - yield[ - (new QueryBuilder($entityManager))->from('lorem_ipsum', 'lm'), - [ - 'lorem' => 11, - 'ipsum' => 22, - 'dolor' => null, - ], - ]; - - yield[ - (new QueryBuilder($entityManager))->from('lorem_ipsum', 'lm'), - [ - 'lorem' => [ - 11, - '>=', - ], - 'ipsum' => [ - 22, - '<', - ], - 'dolor' => null, - ], - ]; - } - - /** - * Provides query builder and parameters to add to given query builder - * - * @return Generator - */ - public function provideQueryBuilderAndParameters() - { - $entityManager = $this->createMock(EntityManagerInterface::class); - - yield[ - new QueryBuilder($entityManager), - [], - ]; - - yield[ - new QueryBuilder($entityManager), - new ArrayCollection(), - ]; - - yield[ - new QueryBuilder($entityManager), - [ - 'lorem' => 11, - 'ipsum' => 22, - ], - ]; - - yield[ - new QueryBuilder($entityManager), - new ArrayCollection([ - 'lorem' => 11, - 'ipsum' => 22, - ]), - ]; - - yield[ - new QueryBuilder($entityManager), - [ - new Parameter('lorem', 11), - new Parameter('ipsum', 22), - ], - ]; - - yield[ - new QueryBuilder($entityManager), - new ArrayCollection([ - new Parameter('lorem', 11), - new Parameter('ipsum', 22), - ]), - ]; + static::assertSame($queryBuilder, $newQueryBuilder); + static::assertCount(0, $newQueryBuilder->getParameters()); + static::assertNull($newQueryBuilder->getDQLPart('where')); } } diff --git a/tests/Utilities/Reflection/A.php b/tests/Utilities/Reflection/A.php index df948d6..b5fcbcb 100644 --- a/tests/Utilities/Reflection/A.php +++ b/tests/Utilities/Reflection/A.php @@ -24,13 +24,13 @@ class A private $count = 1; - protected function lorem() - { - return 'ipsum'; - } - protected function getCount() { return $this->count; } + + protected function lorem() + { + return 'ipsum'; + } } diff --git a/tests/Utilities/Reflection/C.php b/tests/Utilities/Reflection/C.php index f035b38..cf8b860 100644 --- a/tests/Utilities/Reflection/C.php +++ b/tests/Utilities/Reflection/C.php @@ -20,13 +20,13 @@ namespace Meritoo\Test\Common\Utilities\Reflection; */ class C extends B { - public function getPositive() - { - return true; - } - public function getNegative() { return false; } + + public function getPositive() + { + return true; + } } diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index c7adbbe..6f16f0a 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -43,105 +43,187 @@ use stdClass; */ class ReflectionTest extends BaseTestCase { + public function provideClassToGetConstants(): ?Generator + { + yield [ + new stdClass(), + [], + ]; + + yield [ + stdClass::class, + [], + ]; + + yield [ + H::class, + [ + 'DOLOR' => 'sit', + 'LOREM' => 'ipsum', + 'MAX_USERS' => 5, + 'MIN_USERS' => 2, + ], + ]; + } + + public function provideInvalidClassAndTrait(): ?Generator + { + yield [ + '', + '', + ]; + + yield [ + null, + null, + ]; + + yield [ + 0, + 0, + ]; + } + + public function provideObjectAndNotExistingProperties(): ?Generator + { + yield [ + new stdClass(), + [ + 'test' => 1, + ], + ]; + + yield [ + new A(), + [ + 'test' => 2, + ], + ]; + + yield [ + new B(), + [ + 'firstName' => '', + ], + ]; + } + + public function provideObjectAndNotExistingProperty(): ?Generator + { + yield [ + new stdClass(), + 'test', + ]; + + yield [ + new A(), + 'test', + ]; + + yield [ + new B(), + 'firstName', + ]; + } + + public function provideObjectAndPropertiesValues(): ?Generator + { + yield [ + new A(), + [ + 'count' => 123, + ], + ]; + + yield [ + new B(), + [ + 'name' => 'test test', + ], + ]; + + yield [ + new G(), + [ + 'firstName' => 'Jane', + ], + ]; + + yield [ + new G(), + [ + 'lastName' => 'Smith', + ], + ]; + + yield [ + new G(), + [ + 'firstName' => 'Jane', + 'lastName' => 'Brown', + ], + ]; + + yield [ + new F( + 123, + 'New York', + 'USA', + 'UnKnown' + ), + [ + 'g' => new G(), + ], + ]; + + yield [ + new F( + 123, + 'New York', + 'USA', + 'UnKnown', + 'Mary', + 'Brown' + ), + [ + 'country' => 'Canada', + 'accountBalance' => 456, + ], + ]; + } + + public function provideObjectPropertyAndValue(): ?Generator + { + yield [ + new A(), + 'count', + 123, + ]; + + yield [ + new B(), + 'name', + 'test test', + ]; + + yield [ + new G(), + 'firstName', + 'Jane', + ]; + + yield [ + new G(), + 'lastName', + 'Smith', + ]; + } + public function testConstructor(): void { static::assertHasNoConstructor(Reflection::class); } - /** - * @param mixed $invalidClass Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testGetClassNameInvalidClass($invalidClass): void - { - self::assertNull(Reflection::getClassName($invalidClass)); - self::assertNull(Reflection::getClassName(123)); - } - - public function testGetClassNameNotExistingClass(): void - { - // Not existing class - self::assertEquals('', Reflection::getClassName('xyz')); - self::assertEquals('', Reflection::getClassName('xyz', true)); - } - - public function testGetClassNameExistingClass(): void - { - // Existing class - self::assertEquals(self::class, Reflection::getClassName(self::class)); - self::assertEquals('ReflectionTest', Reflection::getClassName(self::class, true)); - self::assertEquals(DateTime::class, Reflection::getClassName(new DateTime())); - self::assertEquals(DateTime::class, Reflection::getClassName(new DateTime(), true)); - - self::assertEquals(DateTime::class, Reflection::getClassName([ - new DateTime(), - new DateTime('yesterday'), - ])); - } - - /** - * A case when namespace of class contains name of class (iow. name of class occurs twice) - */ - public function testGetClassWhileNamespaceContainsClassName(): void - { - self::assertEquals( - BaseCollection::class, - Reflection::getClassName(BaseCollection::class) - ); - - self::assertEquals( - 'BaseCollection', - Reflection::getClassName(BaseCollection::class, true) - ); - } - - public function testGetClassNamespaceNotExistingClass(): void - { - // Not existing class - self::assertEquals('', Reflection::getClassNamespace('xyz')); - } - - public function testGetClassNamespaceExistingClass(): void - { - // Existing class - self::assertEquals('Meritoo\Test\Common\Utilities', Reflection::getClassNamespace(self::class)); - self::assertEquals(DateTime::class, Reflection::getClassNamespace(new DateTime())); - - self::assertEquals(DateTime::class, Reflection::getClassNamespace([ - new DateTime(), - new DateTime('yesterday'), - ])); - } - - /** - * A case when namespace of class contains name of class (name of class is duplicated, occurs twice) - */ - public function testGetClassNamespaceWhileNamespaceContainsClassName(): void - { - self::assertEquals( - 'Meritoo\Common\Collection', - Reflection::getClassNamespace(BaseCollection::class) - ); - } - - /** - * @param mixed $invalidClass Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testGetChildClassesInvalidClass($invalidClass): void - { - $this->expectException(CannotResolveClassNameException::class); - - self::assertNull(Reflection::getChildClasses($invalidClass)); - self::assertNull(Reflection::getChildClasses(123)); - } - - public function testGetChildClassesNotExistingClass(): void - { - $this->expectException(CannotResolveClassNameException::class); - self::assertEquals('', Reflection::getChildClasses('xyz')); - } - public function testGetChildClassesExistingClass(): void { /* @@ -167,6 +249,149 @@ class ReflectionTest extends BaseTestCase self::assertEquals($effect, Reflection::getChildClasses(A::class)); } + /** + * @param mixed $invalidClass Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testGetChildClassesInvalidClass($invalidClass): void + { + $this->expectException(CannotResolveClassNameException::class); + + self::assertNull(Reflection::getChildClasses($invalidClass)); + self::assertNull(Reflection::getChildClasses(123)); + } + + public function testGetChildClassesNotExistingClass(): void + { + $this->expectException(CannotResolveClassNameException::class); + self::assertEquals('', Reflection::getChildClasses('xyz')); + } + + public function testGetClassNameExistingClass(): void + { + // Existing class + self::assertEquals(self::class, Reflection::getClassName(self::class)); + self::assertEquals('ReflectionTest', Reflection::getClassName(self::class, true)); + self::assertEquals(DateTime::class, Reflection::getClassName(new DateTime())); + self::assertEquals(DateTime::class, Reflection::getClassName(new DateTime(), true)); + + self::assertEquals(DateTime::class, Reflection::getClassName([ + new DateTime(), + new DateTime('yesterday'), + ])); + } + + /** + * @param mixed $invalidClass Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testGetClassNameInvalidClass($invalidClass): void + { + self::assertNull(Reflection::getClassName($invalidClass)); + self::assertNull(Reflection::getClassName(123)); + } + + public function testGetClassNameNotExistingClass(): void + { + // Not existing class + self::assertEquals('', Reflection::getClassName('xyz')); + self::assertEquals('', Reflection::getClassName('xyz', true)); + } + + public function testGetClassNamespaceExistingClass(): void + { + // Existing class + self::assertEquals('Meritoo\Test\Common\Utilities', Reflection::getClassNamespace(self::class)); + self::assertEquals(DateTime::class, Reflection::getClassNamespace(new DateTime())); + + self::assertEquals(DateTime::class, Reflection::getClassNamespace([ + new DateTime(), + new DateTime('yesterday'), + ])); + } + + public function testGetClassNamespaceNotExistingClass(): void + { + // Not existing class + self::assertEquals('', Reflection::getClassNamespace('xyz')); + } + + /** + * A case when namespace of class contains name of class (name of class is duplicated, occurs twice) + */ + public function testGetClassNamespaceWhileNamespaceContainsClassName(): void + { + self::assertEquals( + 'Meritoo\Common\Collection', + Reflection::getClassNamespace(BaseCollection::class) + ); + } + + /** + * A case when namespace of class contains name of class (iow. name of class occurs twice) + */ + public function testGetClassWhileNamespaceContainsClassName(): void + { + self::assertEquals( + BaseCollection::class, + Reflection::getClassName(BaseCollection::class) + ); + + self::assertEquals( + 'BaseCollection', + Reflection::getClassName(BaseCollection::class, true) + ); + } + + public function testGetConstantValue(): void + { + static::assertSame(H::LOREM, Reflection::getConstantValue(H::class, 'LOREM')); + } + + public function testGetConstantValueUsingClassWithoutConstant(): void + { + static::assertNull(Reflection::getConstantValue(H::class, 'users')); + } + + /** + * @param object|string $class The object or name of object's class + * @param array $expected Expected constants + * + * @dataProvider provideClassToGetConstants + */ + public function testGetConstants($class, array $expected): void + { + static::assertSame($expected, Reflection::getConstants($class)); + } + + public function testGetMaxNumberConstant(): void + { + static::assertSame(5, Reflection::getMaxNumberConstant(H::class)); + } + + public function testGetMaxNumberConstantUsingClassWithoutConstants(): void + { + static::assertNull(Reflection::getMaxNumberConstant(A::class)); + } + + public function testGetMethods(): void + { + self::assertCount(1, Reflection::getMethods(B::class, true)); + self::assertCount(3, Reflection::getMethods(B::class)); + self::assertCount(2, Reflection::getMethods(A::class)); + self::assertCount(2, Reflection::getMethods(C::class, true)); + self::assertCount(5, Reflection::getMethods(C::class)); + } + + public function testGetOneChildClass(): void + { + // Required to get all classes by get_declared_classes() function and avoid throw of + // Meritoo\Common\Exception\Reflection\MissingChildClassesException exception + new C(); + + self::assertEquals(C::class, Reflection::getOneChildClass(B::class)); + } + public function testGetOneChildClassWithMissingChildClasses(): void { $this->expectException(MissingChildClassesException::class); @@ -185,62 +410,6 @@ class ReflectionTest extends BaseTestCase Reflection::getOneChildClass(A::class); } - public function testGetOneChildClass(): void - { - // Required to get all classes by get_declared_classes() function and avoid throw of - // Meritoo\Common\Exception\Reflection\MissingChildClassesException exception - new C(); - - self::assertEquals(C::class, Reflection::getOneChildClass(B::class)); - } - - public function testGetMethods(): void - { - self::assertCount(1, Reflection::getMethods(B::class, true)); - self::assertCount(3, Reflection::getMethods(B::class)); - self::assertCount(2, Reflection::getMethods(A::class)); - self::assertCount(2, Reflection::getMethods(C::class, true)); - self::assertCount(5, Reflection::getMethods(C::class)); - } - - /** - * @param array|object|string $class An array of objects, namespaces, object or namespace - * @param array|string $trait An array of strings or string - * - * @dataProvider provideInvalidClassAndTrait - */ - public function testUsesTraitInvalidClass($class, $trait): void - { - $this->expectException(CannotResolveClassNameException::class); - self::assertNull(Reflection::usesTrait($class, $trait)); - } - - /** - * @param mixed $trait Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testUsesTraitInvalidTrait($trait): void - { - $this->expectException(CannotResolveClassNameException::class); - Reflection::usesTrait(DateTime::class, $trait); - } - - public function testUsesTraitExistingClass(): void - { - self::assertTrue(Reflection::usesTrait(A::class, E::class)); - self::assertFalse(Reflection::usesTrait(B::class, E::class)); - self::assertFalse(Reflection::usesTrait(C::class, E::class)); - self::assertFalse(Reflection::usesTrait(D::class, E::class)); - } - - public function testUsesTraitExistingClassAndVerifyParents(): void - { - self::assertTrue(Reflection::usesTrait(A::class, E::class, true)); - self::assertTrue(Reflection::usesTrait(B::class, E::class, true)); - self::assertTrue(Reflection::usesTrait(C::class, E::class, true)); - self::assertFalse(Reflection::usesTrait(D::class, E::class, true)); - } - public function testGetProperties(): void { self::assertCount(1, Reflection::getProperties(B::class)); @@ -269,10 +438,27 @@ class ReflectionTest extends BaseTestCase self::assertCount(2, Reflection::getProperties(B::class, null, true)); } - public function testGetPropertyValueOfNotExistingProperty(): void + public function testGetPropertyUsingClassWithPrivateProperty(): void { - self::assertNull(Reflection::getPropertyValue(new D(), 'something')); - self::assertNull(Reflection::getPropertyValue(new D(), 'something', true)); + $property = Reflection::getProperty(A::class, 'count', ReflectionProperty::IS_PRIVATE); + + static::assertInstanceOf(ReflectionProperty::class, $property); + static::assertTrue($property->isPrivate()); + static::assertSame('count', $property->getName()); + } + + public function testGetPropertyUsingClassWithProtectedProperty(): void + { + $property = Reflection::getProperty(B::class, 'name', ReflectionProperty::IS_PROTECTED); + + static::assertInstanceOf(ReflectionProperty::class, $property); + static::assertTrue($property->isProtected()); + static::assertSame('name', $property->getName()); + } + + public function testGetPropertyUsingClassWithoutProperty(): void + { + static::assertNull(Reflection::getProperty(A::class, 'lorem')); } public function testGetPropertyValueFromChain(): void @@ -281,20 +467,16 @@ class ReflectionTest extends BaseTestCase self::assertEquals('John', Reflection::getPropertyValue($f, 'g.firstName')); } - public function testGetPropertyValueWithPublicGetter(): void + public function testGetPropertyValueFromParentClass(): void { - $country = 'USA'; - $f = new F(1000, 'New York', $country, 'john.scott'); - - self::assertEquals($country, Reflection::getPropertyValue($f, 'country')); + $c = new C(); + self::assertEquals(1, Reflection::getPropertyValue($c, 'count', true)); } - public function testGetPropertyValueWithProtectedGetter(): void + public function testGetPropertyValueOfNotExistingProperty(): void { - $city = 'New York'; - $f = new F(1000, $city, 'USA', 'john.scott'); - - self::assertEquals($city, Reflection::getPropertyValue($f, 'city')); + self::assertNull(Reflection::getPropertyValue(new D(), 'something')); + self::assertNull(Reflection::getPropertyValue(new D(), 'something', true)); } public function testGetPropertyValueWithPrivateGetter(): void @@ -305,6 +487,22 @@ class ReflectionTest extends BaseTestCase self::assertEquals($accountBalance, Reflection::getPropertyValue($f, 'accountBalance')); } + public function testGetPropertyValueWithProtectedGetter(): void + { + $city = 'New York'; + $f = new F(1000, $city, 'USA', 'john.scott'); + + self::assertEquals($city, Reflection::getPropertyValue($f, 'city')); + } + + public function testGetPropertyValueWithPublicGetter(): void + { + $country = 'USA'; + $f = new F(1000, 'New York', $country, 'john.scott'); + + self::assertEquals($country, Reflection::getPropertyValue($f, 'country')); + } + public function testGetPropertyValueWithoutGetter(): void { $username = 'john.scott'; @@ -313,86 +511,6 @@ class ReflectionTest extends BaseTestCase self::assertEquals($username, Reflection::getPropertyValue($f, 'username')); } - public function testGetPropertyValueFromParentClass(): void - { - $c = new C(); - self::assertEquals(1, Reflection::getPropertyValue($c, 'count', true)); - } - - public function testGetPropertyValuesFromEmptySource(): void - { - self::assertEquals([], Reflection::getPropertyValues([], 'something')); - self::assertEquals([], Reflection::getPropertyValues(new Templates(), 'something')); - } - - public function testGetPropertyValuesOfNotExistingPropertyFromSingleObject(): void - { - self::assertEquals([], Reflection::getPropertyValues(new D(), 'something')); - self::assertEquals([], Reflection::getPropertyValues(new D(), 'something', true)); - } - - public function testGetPropertyValuesOfNotExistingPropertyFromMultipleObjects(): void - { - $objects = [ - new A(), - new A(), - new A(), - new B(), - new B(), - new C(), - new D(), - ]; - - self::assertEquals([], Reflection::getPropertyValues($objects, 'something')); - self::assertEquals([], Reflection::getPropertyValues($objects, 'something', true)); - - $collection = new ObjectsCollection($objects); - - self::assertEquals([], Reflection::getPropertyValues($collection, 'something')); - self::assertEquals([], Reflection::getPropertyValues($collection, 'something', true)); - } - - public function testGetPropertyValuesOfExistingPropertyFromSingleObject(): void - { - self::assertEquals(['John'], Reflection::getPropertyValues(new G(), 'firstName')); - self::assertEquals(['John'], Reflection::getPropertyValues(new G(), 'firstName', true)); - } - - public function testGetPropertyValuesOfExistingPropertyFromMultipleObjects(): void - { - $expected = [ - 'New York', - 'London', - 'Tokyo', - ]; - - $objects = [ - new F(1000, 'New York', 'USA', 'john.scott'), - new F(2000, 'London', 'GB', 'john.scott'), - new F(3000, 'Tokyo', 'Japan', 'john.scott'), - ]; - - self::assertEquals($expected, Reflection::getPropertyValues($objects, 'city')); - self::assertEquals($expected, Reflection::getPropertyValues($objects, 'city', true)); - - $collection = new ObjectsCollection($objects); - - self::assertEquals($expected, Reflection::getPropertyValues($collection, 'city')); - self::assertEquals($expected, Reflection::getPropertyValues($collection, 'city', true)); - } - - public function testGetPropertyValuesFromChainAndSingleObject(): void - { - $f = new F(1000, 'New York', 'USA', 'john.scott'); - $j = new J(); - - self::assertEquals(['John'], Reflection::getPropertyValues($f, 'g.firstName')); - self::assertEquals(['John'], Reflection::getPropertyValues($f, 'g.firstName', true)); - - self::assertEquals(['John'], Reflection::getPropertyValues($j, 'f.g.firstName')); - self::assertEquals(['John'], Reflection::getPropertyValues($j, 'f.g.firstName', true)); - } - public function testGetPropertyValuesFromChainAndMultipleObjects(): void { $expected = [ @@ -416,39 +534,78 @@ class ReflectionTest extends BaseTestCase self::assertEquals($expected, Reflection::getPropertyValues($collection, 'g.firstName', true)); } - public function testGetMaxNumberConstantUsingClassWithoutConstants(): void + public function testGetPropertyValuesFromChainAndSingleObject(): void { - static::assertNull(Reflection::getMaxNumberConstant(A::class)); + $f = new F(1000, 'New York', 'USA', 'john.scott'); + $j = new J(); + + self::assertEquals(['John'], Reflection::getPropertyValues($f, 'g.firstName')); + self::assertEquals(['John'], Reflection::getPropertyValues($f, 'g.firstName', true)); + + self::assertEquals(['John'], Reflection::getPropertyValues($j, 'f.g.firstName')); + self::assertEquals(['John'], Reflection::getPropertyValues($j, 'f.g.firstName', true)); } - public function testGetMaxNumberConstant(): void + public function testGetPropertyValuesFromEmptySource(): void { - static::assertSame(5, Reflection::getMaxNumberConstant(H::class)); + self::assertEquals([], Reflection::getPropertyValues([], 'something')); + self::assertEquals([], Reflection::getPropertyValues(new Templates(), 'something')); } - public function testHasMethodUsingClassWithoutMethod(): void + public function testGetPropertyValuesOfExistingPropertyFromMultipleObjects(): void { - static::assertFalse(Reflection::hasMethod(A::class, 'getUser')); + $expected = [ + 'New York', + 'London', + 'Tokyo', + ]; + + $objects = [ + new F(1000, 'New York', 'USA', 'john.scott'), + new F(2000, 'London', 'GB', 'john.scott'), + new F(3000, 'Tokyo', 'Japan', 'john.scott'), + ]; + + self::assertEquals($expected, Reflection::getPropertyValues($objects, 'city')); + self::assertEquals($expected, Reflection::getPropertyValues($objects, 'city', true)); + + $collection = new ObjectsCollection($objects); + + self::assertEquals($expected, Reflection::getPropertyValues($collection, 'city')); + self::assertEquals($expected, Reflection::getPropertyValues($collection, 'city', true)); } - public function testHasMethod(): void + public function testGetPropertyValuesOfExistingPropertyFromSingleObject(): void { - static::assertTrue(Reflection::hasMethod(A::class, 'getCount')); + self::assertEquals(['John'], Reflection::getPropertyValues(new G(), 'firstName')); + self::assertEquals(['John'], Reflection::getPropertyValues(new G(), 'firstName', true)); } - public function testHasPropertyUsingClassWithoutProperty(): void + public function testGetPropertyValuesOfNotExistingPropertyFromMultipleObjects(): void { - static::assertFalse(Reflection::hasProperty(A::class, 'users')); + $objects = [ + new A(), + new A(), + new A(), + new B(), + new B(), + new C(), + new D(), + ]; + + self::assertEquals([], Reflection::getPropertyValues($objects, 'something')); + self::assertEquals([], Reflection::getPropertyValues($objects, 'something', true)); + + $collection = new ObjectsCollection($objects); + + self::assertEquals([], Reflection::getPropertyValues($collection, 'something')); + self::assertEquals([], Reflection::getPropertyValues($collection, 'something', true)); } - public function testHasProperty(): void + public function testGetPropertyValuesOfNotExistingPropertyFromSingleObject(): void { - static::assertTrue(Reflection::hasProperty(A::class, 'count')); - } - - public function testHasConstantUsingClassWithoutConstant(): void - { - static::assertFalse(Reflection::hasConstant(H::class, 'users')); + self::assertEquals([], Reflection::getPropertyValues(new D(), 'something')); + self::assertEquals([], Reflection::getPropertyValues(new D(), 'something', true)); } public function testHasConstant(): void @@ -456,40 +613,29 @@ class ReflectionTest extends BaseTestCase static::assertTrue(Reflection::hasConstant(H::class, 'LOREM')); } - public function testGetConstantValueUsingClassWithoutConstant(): void + public function testHasConstantUsingClassWithoutConstant(): void { - static::assertNull(Reflection::getConstantValue(H::class, 'users')); + static::assertFalse(Reflection::hasConstant(H::class, 'users')); } - /** - * @param object|string $class The object or name of object's class - * @param array $expected Expected constants - * - * @dataProvider provideClassToGetConstants - */ - public function testGetConstants($class, array $expected): void + public function testHasMethod(): void { - static::assertSame($expected, Reflection::getConstants($class)); + static::assertTrue(Reflection::hasMethod(A::class, 'getCount')); } - public function testGetConstantValue(): void + public function testHasMethodUsingClassWithoutMethod(): void { - static::assertSame(H::LOREM, Reflection::getConstantValue(H::class, 'LOREM')); + static::assertFalse(Reflection::hasMethod(A::class, 'getUser')); } - public function testIsInterfaceImplementedUsingClassWithoutInterface(): void + public function testHasProperty(): void { - static::assertFalse(Reflection::isInterfaceImplemented(A::class, I::class)); + static::assertTrue(Reflection::hasProperty(A::class, 'count')); } - public function testIsInterfaceImplemented(): void + public function testHasPropertyUsingClassWithoutProperty(): void { - static::assertTrue(Reflection::isInterfaceImplemented(B::class, I::class)); - } - - public function testIsChildOfClassUsingClassWithoutChildClass(): void - { - static::assertFalse(Reflection::isChildOfClass(A::class, B::class)); + static::assertFalse(Reflection::hasProperty(A::class, 'users')); } public function testIsChildOfClass(): void @@ -497,39 +643,56 @@ class ReflectionTest extends BaseTestCase static::assertTrue(Reflection::isChildOfClass(B::class, A::class)); } - public function testGetPropertyUsingClassWithoutProperty(): void + public function testIsChildOfClassUsingClassWithoutChildClass(): void { - static::assertNull(Reflection::getProperty(A::class, 'lorem')); + static::assertFalse(Reflection::isChildOfClass(A::class, B::class)); } - public function testGetPropertyUsingClassWithPrivateProperty(): void + public function testIsInterfaceImplemented(): void { - $property = Reflection::getProperty(A::class, 'count', ReflectionProperty::IS_PRIVATE); - - static::assertInstanceOf(ReflectionProperty::class, $property); - static::assertTrue($property->isPrivate()); - static::assertSame('count', $property->getName()); + static::assertTrue(Reflection::isInterfaceImplemented(B::class, I::class)); } - public function testGetPropertyUsingClassWithProtectedProperty(): void + public function testIsInterfaceImplementedUsingClassWithoutInterface(): void { - $property = Reflection::getProperty(B::class, 'name', ReflectionProperty::IS_PROTECTED); - - static::assertInstanceOf(ReflectionProperty::class, $property); - static::assertTrue($property->isProtected()); - static::assertSame('name', $property->getName()); + static::assertFalse(Reflection::isInterfaceImplemented(A::class, I::class)); } /** - * @param mixed $object Object that should contains given property - * @param string $property Name of the property + * @param mixed $object Object that should contains given property + * @param array $propertiesValues Key-value pairs, where key - name of the property, value - value of the property * - * @dataProvider provideObjectAndNotExistingProperty + * @dataProvider provideObjectAndPropertiesValues */ - public function testSetPropertyValueUsingNotExistingProperty($object, $property): void + public function testSetPropertiesValues($object, array $propertiesValues): void + { + Reflection::setPropertiesValues($object, $propertiesValues); + + foreach ($propertiesValues as $property => $value) { + $realValue = Reflection::getPropertyValue($object, $property); + static::assertSame($value, $realValue); + } + } + + /** + * @param mixed $object Object that should contains given property + * @param array $propertiesValues Key-value pairs, where key - name of the property, value - value of the property + * + * @dataProvider provideObjectAndNotExistingProperties + */ + public function testSetPropertiesValuesUsingNotExistingProperties($object, array $propertiesValues): void { $this->expectException(NotExistingPropertyException::class); - Reflection::setPropertyValue($object, $property, 'test test test'); + Reflection::setPropertiesValues($object, $propertiesValues); + } + + public function testSetPropertiesValuesWithoutProperties(): void + { + $object = new G(); + Reflection::setPropertiesValues($object, []); + + static::assertSame($object->getFirstName(), 'John'); + static::assertSame($object->getLastName(), 'Scott'); } /** @@ -549,216 +712,53 @@ class ReflectionTest extends BaseTestCase static::assertSame($newValue, $value); } - public function testSetPropertiesValuesWithoutProperties(): void - { - $object = new G(); - Reflection::setPropertiesValues($object, []); - - static::assertSame($object->getFirstName(), 'John'); - static::assertSame($object->getLastName(), 'Scott'); - } - /** - * @param mixed $object Object that should contains given property - * @param array $propertiesValues Key-value pairs, where key - name of the property, value - value of the property + * @param mixed $object Object that should contains given property + * @param string $property Name of the property * - * @dataProvider provideObjectAndNotExistingProperties + * @dataProvider provideObjectAndNotExistingProperty */ - public function testSetPropertiesValuesUsingNotExistingProperties($object, array $propertiesValues): void + public function testSetPropertyValueUsingNotExistingProperty($object, $property): void { $this->expectException(NotExistingPropertyException::class); - Reflection::setPropertiesValues($object, $propertiesValues); + Reflection::setPropertyValue($object, $property, 'test test test'); + } + + public function testUsesTraitExistingClass(): void + { + self::assertTrue(Reflection::usesTrait(A::class, E::class)); + self::assertFalse(Reflection::usesTrait(B::class, E::class)); + self::assertFalse(Reflection::usesTrait(C::class, E::class)); + self::assertFalse(Reflection::usesTrait(D::class, E::class)); + } + + public function testUsesTraitExistingClassAndVerifyParents(): void + { + self::assertTrue(Reflection::usesTrait(A::class, E::class, true)); + self::assertTrue(Reflection::usesTrait(B::class, E::class, true)); + self::assertTrue(Reflection::usesTrait(C::class, E::class, true)); + self::assertFalse(Reflection::usesTrait(D::class, E::class, true)); } /** - * @param mixed $object Object that should contains given property - * @param array $propertiesValues Key-value pairs, where key - name of the property, value - value of the property + * @param array|object|string $class An array of objects, namespaces, object or namespace + * @param array|string $trait An array of strings or string * - * @dataProvider provideObjectAndPropertiesValues + * @dataProvider provideInvalidClassAndTrait */ - public function testSetPropertiesValues($object, array $propertiesValues): void + public function testUsesTraitInvalidClass($class, $trait): void { - Reflection::setPropertiesValues($object, $propertiesValues); - - foreach ($propertiesValues as $property => $value) { - $realValue = Reflection::getPropertyValue($object, $property); - static::assertSame($value, $realValue); - } + $this->expectException(CannotResolveClassNameException::class); + self::assertNull(Reflection::usesTrait($class, $trait)); } - public function provideInvalidClassAndTrait(): ?Generator + /** + * @param mixed $trait Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testUsesTraitInvalidTrait($trait): void { - yield[ - '', - '', - ]; - - yield[ - null, - null, - ]; - - yield[ - 0, - 0, - ]; - } - - public function provideObjectAndNotExistingProperty(): ?Generator - { - yield[ - new stdClass(), - 'test', - ]; - - yield[ - new A(), - 'test', - ]; - - yield[ - new B(), - 'firstName', - ]; - } - - public function provideObjectPropertyAndValue(): ?Generator - { - yield[ - new A(), - 'count', - 123, - ]; - - yield[ - new B(), - 'name', - 'test test', - ]; - - yield[ - new G(), - 'firstName', - 'Jane', - ]; - - yield[ - new G(), - 'lastName', - 'Smith', - ]; - } - - public function provideObjectAndNotExistingProperties(): ?Generator - { - yield[ - new stdClass(), - [ - 'test' => 1, - ], - ]; - - yield[ - new A(), - [ - 'test' => 2, - ], - ]; - - yield[ - new B(), - [ - 'firstName' => '', - ], - ]; - } - - public function provideObjectAndPropertiesValues(): ?Generator - { - yield[ - new A(), - [ - 'count' => 123, - ], - ]; - - yield[ - new B(), - [ - 'name' => 'test test', - ], - ]; - - yield[ - new G(), - [ - 'firstName' => 'Jane', - ], - ]; - - yield[ - new G(), - [ - 'lastName' => 'Smith', - ], - ]; - - yield[ - new G(), - [ - 'firstName' => 'Jane', - 'lastName' => 'Brown', - ], - ]; - - yield[ - new F( - 123, - 'New York', - 'USA', - 'UnKnown' - ), - [ - 'g' => new G(), - ], - ]; - - yield[ - new F( - 123, - 'New York', - 'USA', - 'UnKnown', - 'Mary', - 'Brown' - ), - [ - 'country' => 'Canada', - 'accountBalance' => 456, - ], - ]; - } - - public function provideClassToGetConstants(): ?Generator - { - yield[ - new stdClass(), - [], - ]; - - yield[ - stdClass::class, - [], - ]; - - yield[ - H::class, - [ - 'DOLOR' => 'sit', - 'LOREM' => 'ipsum', - 'MAX_USERS' => 5, - 'MIN_USERS' => 2, - ], - ]; + $this->expectException(CannotResolveClassNameException::class); + Reflection::usesTrait(DateTime::class, $trait); } } diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index 48c61d5..a92021e 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -13,6 +13,7 @@ use Meritoo\Common\Exception\Regex\IncorrectColorHexLengthException; use Meritoo\Common\Exception\Regex\InvalidColorHexValueException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Utilities\Regex; +use stdClass; /** * Test case of the useful regular expressions methods @@ -28,11 +29,1751 @@ class RegexTest extends BaseTestCase private $simpleText; private $camelCaseText; + /** + * Provides value to verify if it is a binary value + * + * @return Generator + */ + public function provideBinaryValue() + { + $file1Path = $this->getFilePathForTesting('lorem-ipsum.txt'); + $file2Path = $this->getFilePathForTesting('minion.jpg'); + + yield [ + null, + false, + ]; + + yield [ + [], + false, + ]; + + yield [ + '', + false, + ]; + + yield [ + 'abc', + false, + ]; + + yield [ + '1234', + false, + ]; + + yield [ + 1234, + false, + ]; + + yield [ + 12.34, + false, + ]; + + yield [ + fread(fopen($file1Path, 'rb'), 1), + false, + ]; + + yield [ + fread(fopen($file2Path, 'rb'), 1), + true, + ]; + } + + /** + * Provides name of bundle and information if it's valid name + * + * @return Generator + */ + public function provideBundleName() + { + yield [ + 'something', + false, + ]; + + yield [ + 'something_different', + false, + ]; + + yield [ + 'something-else', + false, + ]; + + yield [ + 'myExtraBundle', + false, + ]; + + yield [ + 'MyExtra', + false, + ]; + + yield [ + 'MyExtraBundle', + true, + ]; + + yield [ + 'MySuperExtraGorgeousBundle', + true, + ]; + } + + /** + * Provides value of color + * + * @return Generator + */ + public function provideColor() + { + yield [ + '#1b0', + '11bb00', + ]; + + yield [ + '#1B0', + '11bb00', + ]; + + yield [ + '#1ab1ab', + '1ab1ab', + ]; + + yield [ + '#1AB1AB', + '1ab1ab', + ]; + + yield [ + '#000', + '000000', + ]; + } + + /** + * Provides empty non color-related value + * + * @return Generator + */ + public function provideColorEmptyValue() + { + yield [ + '', + ]; + + yield [ + 0, + ]; + + yield [ + '0', + ]; + + yield [ + false, + ]; + } + + /** + * Provides value of color with incorrect length + * + * @return Generator + */ + public function provideColorIncorrectLength() + { + yield [ + '12', + ]; + + yield [ + '1234', + ]; + + yield [ + '12345678', + ]; + + yield [ + '#12', + ]; + + yield [ + '#1234', + ]; + + yield [ + '#12345678', + ]; + } + + /** + * Provides invalid value of color + * + * @return Generator + */ + public function provideColorInvalidValue() + { + yield [ + '#qwerty', + ]; + + yield [ + 'qwerty', + ]; + } + + /** + * Provides e-mail and information if it's valid + * + * @return Generator + */ + public function provideEmail() + { + yield [ + '1', + false, + ]; + + yield [ + 1, + false, + ]; + + yield [ + 'a@a', + false, + ]; + + yield [ + 'a@a.com', + false, + ]; + + yield [ + 'aa@a.com', + true, + ]; + + yield [ + 'a.b@d.com', + true, + ]; + } + + /** + * Provides empty non money-related value + * + * @return Generator + */ + public function provideEmptyNonMoneyValue() + { + yield ['']; + yield [' ']; + yield [null]; + yield [false]; + yield [[]]; + } + + public function provideFileName(): ?Generator + { + yield [ + 'An empty string', + '', + false, + ]; + + yield [ + 'Path of this file, of file with test case', + __DIR__, + false, + ]; + + yield [ + 'Name of this file, of file with test case', + __FILE__, + true, + ]; + + yield [ + 'Complicated name of file', + 'this-1_2 3 & my! 4+file.jpg', + true, + ]; + + yield [ + 'Complicated name of file', + 'directory1/directory2/this-1_2 3 & my! 4+file.jpg', + true, + ]; + } + + /** + * Provides html attribute and information if it's valid + * + * @return Generator + */ + public function provideHtmlAttribute() + { + yield [ + 'abc = def', + false, + ]; + + yield [ + 'a b c=def', + false, + ]; + + yield [ + 'abc=def', + false, + ]; + + yield [ + 'a1b2c=d3e4f', + false, + ]; + + yield [ + 'abc="def"', + true, + ]; + + yield [ + 'a1b2c="d3e4f"', + true, + ]; + } + + /** + * Provides html attribute and information if attributes are valid + * + * @return Generator + */ + public function provideHtmlAttributes() + { + yield [ + 'abc = def', + false, + ]; + + yield [ + 'abc = def ghi = jkl', + false, + ]; + + yield [ + 'abc=def ghi=jkl', + false, + ]; + + yield [ + 'abc=def ghi=jkl mno=pqr', + false, + ]; + + yield [ + 'abc="def"', + true, + ]; + + yield [ + 'abc="def" ghi="jkl"', + true, + ]; + + yield [ + 'abc="def" ghi="jkl" mno="pqr"', + true, + ]; + + yield [ + 'a2bc="d4ef" ghi="j k l" mno="pq9r"', + true, + ]; + } + + /** + * Provides money-related value and information if the value is valid + * + * @return Generator + */ + public function provideMoneyValue() + { + yield [ + 'abc', + false, + ]; + + yield [ + '-a.b', + false, + ]; + + yield [ + 'a,b', + false, + ]; + + yield [ + 0, + true, + ]; + + yield [ + 1, + true, + ]; + + yield [ + -1, + true, + ]; + + yield [ + 1.2, + true, + ]; + + yield [ + 1.202, + true, + ]; + + yield [ + -1.202, + true, + ]; + + yield [ + '0', + true, + ]; + + yield [ + '1', + true, + ]; + + yield [ + '-1', + true, + ]; + + yield [ + '1.2', + true, + ]; + + yield [ + '1.202', + true, + ]; + + yield [ + '-1.202', + true, + ]; + + yield [ + '1,202', + true, + ]; + + yield [ + '-1,2', + true, + ]; + + yield [ + '-1,202', + true, + ]; + } + + /** + * Provides pattern and array with keys that should match that pattern + * + * @return Generator + */ + public function providePatternForArrayKeys() + { + yield [ + '/\d/', + [], + [], + ]; + + yield [ + '/\d+/', + [ + 'lorem' => 'ipsum', + 'dolor' => 123, + 'sit', + 4 => '456', + ], + [ + 0 => 'sit', + 4 => '456', + ], + ]; + + yield [ + '/\d+-[a-z]+/', + [ + 'lorem', + '456-ipsum' => 123, + '001-sit' => false, + 'dolor', + ], + [ + '456-ipsum' => 123, + '001-sit' => false, + ], + ]; + } + + /** + * Provides pattern and array with values that should match that pattern + * + * @return Generator + */ + public function providePatternForArrayValues() + { + yield [ + '/\d/', + [], + [], + ]; + + yield [ + '/\d+/', + [ + 'lorem', + 'ipsum', + 123, + 'dolor', + '456', + ], + [ + 2 => 123, + 4 => '456', + ], + ]; + + yield [ + '/\d+-[a-z]+/', + [ + 'lorem', + 123, + false, + 'dolor', + '456-ipsum', + ], + [ + 4 => '456-ipsum', + ], + ]; + } + + /** + * Provides patterns and subject for the pregMultiMatch() method + * + * @return Generator + */ + public function providePatternsAndSubjectForPregMultiMatch() + { + yield [ + '', + '', + false, + ]; + + yield [ + [], + '', + false, + ]; + + yield [ + '/\d+/', + 'Lorem ipsum dolor sit', + false, + ]; + + yield [ + [ + '/\d+/', + '/^[a-z]{4}$/', + ], + 'Lorem ipsum dolor sit', + false, + ]; + + yield [ + '/\w+/', + 'Lorem ipsum dolor sit', + true, + ]; + + yield [ + [ + '/\d+/', + '/\w+/', + ], + 'Lorem ipsum dolor sit', + true, + ]; + } + + /** + * Provides patterns and subject for the pregMultiMatch() method when must match all patterns + * + * @return Generator + */ + public function providePatternsAndSubjectForPregMultiMatchWhenMustMatchAllPatterns() + { + yield [ + '', + '', + false, + ]; + + yield [ + [], + '', + false, + ]; + + yield [ + '/\d+/', + 'Lorem ipsum dolor sit', + false, + ]; + + yield [ + [ + '/\d+/', + '/^[a-z]{4}$/', + ], + 'Lorem ipsum dolor sit', + false, + ]; + + yield [ + '/\w+/', + 'Lorem ipsum dolor sit', + true, + ]; + + yield [ + [ + '/[a-zA-Z ]+/', + '/\w+/', + ], + 'Lorem ipsum dolor sit', + true, + ]; + } + + /** + * Provides phone number and information if it's valid + * + * @return Generator + */ + public function providePhoneNumber() + { + yield [ + 'abc', + false, + ]; + + yield [ + '1-2-3', + false, + ]; + + yield [ + '123', + true, + ]; + + yield [ + '123 456 789', + true, + ]; + + yield [ + '123456789', + true, + ]; + } + + /** + * Provides regular expression for array filtering and the array + * + * @return Generator + */ + public function provideRegularExpressionForArrayFiltering() + { + yield [ + [], + 'id', + '/\d+/', + [], + ]; + + yield [ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'birth_date', + '/\d+/', + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + ]; + + yield [ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 123, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'id', + '/\d{3}/', + [ + 1 => [ + 'id' => 123, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + ], + ]; + + yield [ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 123, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 456, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'first_name', + '/George|Mike/', + [ + 1 => [ + 'id' => 123, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + 2 => [ + 'id' => 456, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + ]; + + yield [ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green-Blue', + 'is_active' => false, + ], + ], + 'last_name', + '/\w+-\w+/', + [ + 2 => [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green-Blue', + 'is_active' => false, + ], + ], + ]; + } + + /** + * Provides simple compare expression for array filtering and the array + * + * @return Generator + */ + public function provideSimpleExpressionForArrayFiltering() + { + yield [ + [], + 'id', + ' == 2', + [], + ]; + + yield [ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'birth_date', + ' == 2', + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + ]; + + yield [ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'id', + ' == 2', + [ + 1 => [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + ], + ]; + + yield [ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'id', + ' >= 2', + [ + 1 => [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + 2 => [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + ]; + + yield [ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'is_active', + ' !== true', + [ + 2 => [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + ]; + + yield [ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'first_name', + ' == \'Mike\'', + [ + 2 => [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + ]; + } + + public function provideSizeToVerify() + { + yield [ + 'One number only', + 200, + ' x ', + false, + ]; + + yield [ + 'One number only as string', + '200', + ' x ', + false, + ]; + + yield [ + 'The " " as invalid separator', + '200 100', + ' x ', + false, + ]; + + yield [ + 'The "|" as separator (invalid separator)', + '200 | 100', + ' x ', + false, + ]; + + yield [ + 'The "|" as invalid separator and no spaces around separator', + '200|100', + ' x ', + false, + ]; + + yield [ + 'The "X" as invalid separator', + '200 X 100', + ' x ', + false, + ]; + + yield [ + 'Simple, valid size', + '200 x 100', + ' x ', + true, + ]; + + yield [ + 'Too much spaces at the right of separator', + '200 x 100', + ' x ', + true, + ]; + + yield [ + 'Too much spaces at the left of separator', + '200 x 100', + ' x ', + true, + ]; + + yield [ + 'Too much spaces around separator', + '200 x 100', + ' x ', + true, + ]; + + yield [ + 'Too much spaces before width', + ' 200 x 100', + ' x ', + true, + ]; + + yield [ + 'Too much spaces after height', + '200 x 100 ', + ' x ', + true, + ]; + + yield [ + 'Too much spaces before width and after height', + ' 200 x 100 ', + ' x ', + true, + ]; + + yield [ + 'Too much spaces everywhere (1st)', + ' 200 x 100 ', + ' x ', + true, + ]; + + yield [ + 'Too much spaces everywhere (2nd)', + ' 200 x 100 ', + ' x ', + true, + ]; + + yield [ + 'Too much spaces everywhere (3rd)', + ' 200 x 100 ', + ' x ', + true, + ]; + + yield [ + 'The " X " as custom separator', + '200 X 100', + ' X ', + true, + ]; + + yield [ + 'The "|" as custom separator', + '200|100', + '|', + true, + ]; + + yield [ + 'The " | " as custom separator', + '200 | 100', + ' | ', + true, + ]; + + yield [ + 'The "::" as custom separator', + '200::100', + '::', + true, + ]; + + yield [ + 'The " :: " as custom separator', + '200 :: 100', + ' :: ', + true, + ]; + + yield [ + 'The "." as custom separator', + '200.100', + '.', + true, + ]; + + yield [ + 'The " . " as custom separator', + '200 . 100', + ' . ', + true, + ]; + + yield [ + 'The "/" as custom separator', + '200/100', + '/', + true, + ]; + + yield [ + 'The " / " as custom separator', + '200 / 100', + ' / ', + true, + ]; + + yield [ + 'The " : " as custom separator and too much spaces everywhere', + ' 200 : 100 ', + ' : ', + true, + ]; + } + + public function provideStringToClearBeginningSlash(): ?Generator + { + yield [ + '', + '', + ]; + + yield [ + '/', + '', + ]; + + yield [ + '\\', + '\\', + ]; + + yield [ + '//', + '/', + ]; + + yield [ + 'lorem ipsum', + 'lorem ipsum', + ]; + + yield [ + '1234', + '1234', + ]; + + yield [ + 'lorem/ipsum', + 'lorem/ipsum', + ]; + + yield [ + 'lorem / ipsum', + 'lorem / ipsum', + ]; + + yield [ + 'lorem\ipsum', + 'lorem\ipsum', + ]; + + yield [ + 'lorem \ ipsum', + 'lorem \ ipsum', + ]; + + yield [ + '\lorem ipsum', + '\lorem ipsum', + ]; + + yield [ + '\ lorem ipsum', + '\ lorem ipsum', + ]; + + yield [ + 'lorem ipsum/', + 'lorem ipsum/', + ]; + + yield [ + 'lorem ipsum /', + 'lorem ipsum /', + ]; + + yield [ + '/lorem ipsum', + 'lorem ipsum', + ]; + + yield [ + '/ lorem ipsum', + ' lorem ipsum', + ]; + + yield [ + '/123 456', + '123 456', + ]; + + yield [ + '/ 123 456', + ' 123 456', + ]; + + yield [ + '/lorem 123 ipsum 456', + 'lorem 123 ipsum 456', + ]; + + yield [ + '/ lorem 123 ipsum 456', + ' lorem 123 ipsum 456', + ]; + } + + public function provideStringToClearEndingSlash(): ?Generator + { + yield [ + '', + '', + ]; + + yield [ + '/', + '', + ]; + + yield [ + '\\', + '\\', + ]; + + yield [ + '//', + '/', + ]; + + yield [ + 'lorem ipsum', + 'lorem ipsum', + ]; + + yield [ + '1234', + '1234', + ]; + + yield [ + 'lorem/ipsum', + 'lorem/ipsum', + ]; + + yield [ + 'lorem / ipsum', + 'lorem / ipsum', + ]; + + yield [ + 'lorem\ipsum', + 'lorem\ipsum', + ]; + + yield [ + 'lorem \ ipsum', + 'lorem \ ipsum', + ]; + + yield [ + '\lorem ipsum', + '\lorem ipsum', + ]; + + yield [ + '\ lorem ipsum', + '\ lorem ipsum', + ]; + + yield [ + '/lorem ipsum', + '/lorem ipsum', + ]; + + yield [ + '/ lorem ipsum', + '/ lorem ipsum', + ]; + + yield [ + 'lorem ipsum/', + 'lorem ipsum', + ]; + + yield [ + 'lorem ipsum /', + 'lorem ipsum ', + ]; + + yield [ + '123 456/', + '123 456', + ]; + + yield [ + '123 456 /', + '123 456 ', + ]; + + yield [ + 'lorem 123 ipsum 456/', + 'lorem 123 ipsum 456', + ]; + + yield [ + 'lorem 123 ipsum 456 /', + 'lorem 123 ipsum 456 ', + ]; + } + + /** + * Provides tax ID and information if it's valid + * + * @return Generator + */ + public function provideTaxId() + { + yield [ + '123', + false, + ]; + + yield [ + '12345', + false, + ]; + + yield [ + '1122334455', + false, + ]; + + yield [ + '1234567890', + false, + ]; + + yield [ + '0987654321', + false, + ]; + + // Microsoft sp. z o.o. + yield [ + '5270103391', + true, + ]; + + // Onet S.A. + yield [ + '7340009469', + true, + ]; + } + + /** + * Provide value to create slug + * + * @return Generator + */ + public function provideValueSlug() + { + yield [ + [], + false, + ]; + + yield [ + null, + false, + ]; + + yield [ + '', + '', + ]; + + yield [ + 1234, + '1234', + ]; + + yield [ + '1234', + '1234', + ]; + + yield [ + '1/2/3/4', + '1234', + ]; + + yield [ + '1 / 2 / 3 / 4', + '1-2-3-4', + ]; + + yield [ + 'test', + 'test', + ]; + + yield [ + 'test test', + 'test-test', + ]; + + yield [ + 'lorem ipsum dolor sit', + 'lorem-ipsum-dolor-sit', + ]; + + yield [ + 'Lorem ipsum. Dolor sit 12.34 amet.', + 'lorem-ipsum-dolor-sit-1234-amet', + ]; + + yield [ + 'Was sind Löwen, Bären, Vögel und Käfer (für die Prüfung)?', + 'was-sind-lowen-baren-vogel-und-kafer-fur-die-prufung', + ]; + + yield [ + 'äöü (ÄÖÜ)', + 'aou-aou', + ]; + + yield [ + 'Półka dębowa. Kolor: żółędziowy. Wymiary: 80 x 30 cm.', + 'polka-debowa-kolor-zoledziowy-wymiary-80-x-30-cm', + ]; + + yield [ + 'ąęółńśżźć (ĄĘÓŁŃŚŻŹĆ)', + 'aeolnszzc-aeolnszzc', + ]; + } + + /** + * @param string $htmlAttributes The html attributes to verify + * @param bool $expected Information if attributes are valid + * + * @dataProvider provideHtmlAttributes + */ + public static function testAreValidHtmlAttributes($htmlAttributes, $expected) + { + self::assertEquals($expected, Regex::areValidHtmlAttributes($htmlAttributes)); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public static function testAreValidHtmlAttributesUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::areValidHtmlAttributes($emptyValue)); + } + + /** + * @param array $array The array that should be filtered + * @param string $arrayColumnKey Column name + * @param string $filterExpression Regular expression, e.g. "/\d+/" or "/[a-z]+[,;]{2,}/" + * @param array $expected Expected array + * + * @dataProvider provideRegularExpressionForArrayFiltering + */ + public function testArrayFilterUsingRegularExpression($array, $arrayColumnKey, $filterExpression, $expected) + { + self::assertEquals($expected, Regex::arrayFilter($array, $arrayColumnKey, $filterExpression, true)); + } + + /** + * @param array $array The array that should be filtered + * @param string $arrayColumnKey Column name + * @param string $filterExpression Simple filter expression, e.g. "== 2" or "!= \'home\'" + * @param array $expected Expected array + * + * @dataProvider provideSimpleExpressionForArrayFiltering + */ + public function testArrayFilterUsingSimpleExpression($array, $arrayColumnKey, $filterExpression, $expected) + { + self::assertEquals($expected, Regex::arrayFilter($array, $arrayColumnKey, $filterExpression)); + } + + public function testCamelCase2humanReadable() + { + self::assertEquals('', Regex::camelCase2humanReadable('')); + self::assertEquals('lorem', Regex::camelCase2humanReadable('lorem')); + + self::assertEquals($this->simpleText, Regex::camelCase2humanReadable($this->camelCaseText)); + self::assertEquals(ucfirst($this->simpleText), Regex::camelCase2humanReadable($this->camelCaseText, true)); + } + + public function testCamelCase2simpleLowercase() + { + self::assertEquals('', Regex::camelCase2simpleLowercase('')); + self::assertEquals('lorem', Regex::camelCase2simpleLowercase('lorem')); + self::assertEquals('Lorem', Regex::camelCase2simpleLowercase('Lorem', '', false)); + self::assertEquals('lorem-ipsum-dolor-sit', Regex::camelCase2simpleLowercase($this->camelCaseText, '-')); + self::assertEquals('lorem-Ipsum-Dolor-Sit', Regex::camelCase2simpleLowercase($this->camelCaseText, '-', false)); + } + + /** + * @param string $string + * @param string $expected + * + * @dataProvider provideStringToClearBeginningSlash + */ + public function testClearBeginningSlash(string $string, string $expected): void + { + static::assertSame($expected, Regex::clearBeginningSlash($string)); + } + + /** + * @param string $string + * @param string $expected + * + * @dataProvider provideStringToClearEndingSlash + */ + public function testClearEndingSlash(string $string, string $expected): void + { + static::assertSame($expected, Regex::clearEndingSlash($string)); + } + public function testConstructor() { static::assertHasNoConstructor(Regex::class); } + public function testContains() + { + self::assertTrue(Regex::contains($this->simpleText, 'ipsum')); + self::assertFalse(Regex::contains($this->simpleText, 'neque')); + + self::assertFalse(Regex::contains($this->simpleText, '.')); + self::assertTrue(Regex::contains($this->simpleText, 'l')); + } + + public function testContainsEntities() + { + self::assertFalse(Regex::containsEntities('Lorem ipsum')); + self::assertTrue(Regex::containsEntities('Lorem ipsum »')); + } + + /** + * @param string $value Value that should be transformed to slug + * @param string $expected Expected slug + * + * @dataProvider provideValueSlug + */ + public function testCreateSlug($value, $expected) + { + self::assertSame($expected, Regex::createSlug($value)); + } + + public function testEndsWith() + { + self::assertFalse(Regex::endsWith($this->simpleText, '\.\.\.')); + self::assertFalse(Regex::endsWith($this->simpleText, '\.')); + self::assertTrue(Regex::endsWith($this->simpleText, 't')); + } + + public function testEndsWithDirectorySeparator() + { + // Not provided, default separator + self::assertTrue(Regex::endsWithDirectorySeparator('my simple text/')); + self::assertFalse(Regex::endsWithDirectorySeparator('my simple text')); + + // Slash as separator + $separatorSlash = '/'; + + self::assertTrue(Regex::endsWithDirectorySeparator('my simple text/', $separatorSlash)); + self::assertFalse(Regex::endsWithDirectorySeparator('my simple text', $separatorSlash)); + + // Backslash as separator + $separatorBackslash = '\\'; + + self::assertTrue(Regex::endsWithDirectorySeparator('my simple text\\', $separatorBackslash)); + self::assertFalse(Regex::endsWithDirectorySeparator('my simple text', $separatorBackslash)); + } + + /** + * @param string $pattern Pattern to match + * @param array $dataArray The array + * @param array $expected Expected array + * + * @dataProvider providePatternForArrayKeys + */ + public static function testGetArrayValuesByPatternUsingKeys($pattern, array $dataArray, $expected) + { + self::assertEquals($expected, Regex::getArrayValuesByPattern($pattern, $dataArray, true)); + } + + /** + * @param string $pattern Pattern to match + * @param array $dataArray The array + * @param array $expected Expected array + * + * @dataProvider providePatternForArrayValues + */ + public static function testGetArrayValuesByPatternUsingValues($pattern, array $dataArray, $expected) + { + self::assertEquals($expected, Regex::getArrayValuesByPattern($pattern, $dataArray)); + } + + public function testGetBundleNamePattern() + { + self::assertEquals('/^(([A-Z]{1}[a-z0-9]+)((?2))*)(Bundle)$/', Regex::getBundleNamePattern()); + } + public function testGetCamelCaseParts() { $parts = []; @@ -64,22 +1805,328 @@ class RegexTest extends BaseTestCase self::assertEquals($parts, Regex::getCamelCaseParts($string)); } - public function testCamelCase2humanReadable() + public function testGetHtmlAttributePattern() { - self::assertEquals('', Regex::camelCase2humanReadable('')); - self::assertEquals('lorem', Regex::camelCase2humanReadable('lorem')); - - self::assertEquals($this->simpleText, Regex::camelCase2humanReadable($this->camelCaseText)); - self::assertEquals(ucfirst($this->simpleText), Regex::camelCase2humanReadable($this->camelCaseText, true)); + self::assertEquals('/([\w-]+)="([\w -]+)"/', Regex::getHtmlAttributePattern()); } - public function testCamelCase2simpleLowercase() + public function testGetMoneyPattern() { - self::assertEquals('', Regex::camelCase2simpleLowercase('')); - self::assertEquals('lorem', Regex::camelCase2simpleLowercase('lorem')); - self::assertEquals('Lorem', Regex::camelCase2simpleLowercase('Lorem', '', false)); - self::assertEquals('lorem-ipsum-dolor-sit', Regex::camelCase2simpleLowercase($this->camelCaseText, '-')); - self::assertEquals('lorem-Ipsum-Dolor-Sit', Regex::camelCase2simpleLowercase($this->camelCaseText, '-', false)); + self::assertEquals('/^[-+]?\d+([\.,]{1}\d*)?$/', Regex::getMoneyPattern()); + } + + public static function testGetUrlPatternWithProtocolRequired() + { + $pattern = '/^([a-z]+:\/\/)([\da-z\.-]+)\.([a-z\.]{2,6})(\/)?([\w\.\-]*)?(\?)?([\w \.\-\/=&]*)\/?$/i'; + self::assertEquals($pattern, Regex::getUrlPattern(true)); + } + + public static function testGetUrlPatternWithoutProtocol() + { + $pattern = '/^([a-z]+:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})(\/)?([\w\.\-]*)?(\?)?([\w \.\-\/=&]*)\/?$/i'; + self::assertEquals($pattern, Regex::getUrlPattern()); + } + + /** + * @param string $color Color to verify + * @param string $expected Expected value of color + * + * @dataProvider provideColor + */ + public function testGetValidColorHexValue($color, $expected) + { + self::assertEquals($expected, Regex::getValidColorHexValue($color)); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideColorEmptyValue + */ + public function testGetValidColorHexValueUsingEmptyValue($emptyValue) + { + $this->expectException(IncorrectColorHexLengthException::class); + Regex::getValidColorHexValue($emptyValue); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideColorEmptyValue + */ + public function testGetValidColorHexValueUsingEmptyValueWithoutException($emptyValue) + { + self::assertFalse(Regex::getValidColorHexValue($emptyValue, false)); + } + + /** + * @param string $incorrectColor Incorrect value of color + * @dataProvider provideColorIncorrectLength + */ + public function testGetValidColorHexValueUsingIncorrectValue($incorrectColor) + { + $this->expectException(IncorrectColorHexLengthException::class); + Regex::getValidColorHexValue($incorrectColor); + } + + /** + * @param string $incorrectColor Incorrect value of color + * @dataProvider provideColorIncorrectLength + */ + public function testGetValidColorHexValueUsingIncorrectValueWithoutException($incorrectColor) + { + self::assertFalse(Regex::getValidColorHexValue($incorrectColor, false)); + } + + /** + * @param string $invalidColor Invalid value of color + * @dataProvider provideColorInvalidValue + */ + public function testGetValidColorHexValueUsingInvalidValue($invalidColor) + { + $this->expectException(InvalidColorHexValueException::class); + Regex::getValidColorHexValue($invalidColor); + } + + /** + * @param string $invalidColor Invalid value of color + * @dataProvider provideColorInvalidValue + */ + public function testGetValidColorHexValueUsingInvalidValueWithoutException($invalidColor) + { + self::assertFalse(Regex::getValidColorHexValue($invalidColor, false)); + } + + /** + * @param mixed $nonScalarValue Non scalar value, e.g. [] or null + * @dataProvider provideNonScalarValue + */ + public function testGetValidColorHexValueUsingNonScalarValue($nonScalarValue) + { + self::assertFalse(Regex::getValidColorHexValue($nonScalarValue)); + } + + /** + * @param string $value Value to verify + * @param bool $expected Information if value is a binary value + * + * @dataProvider provideBinaryValue + */ + public static function testIsBinaryValue($value, $expected) + { + self::assertEquals($expected, Regex::isBinaryValue($value)); + } + + /** + * @param string $description Description of test + * @param string $fileName + * @param bool $expected Expected result + * + * @dataProvider provideFileName + */ + public function testIsFileName(string $description, string $fileName, bool $expected): void + { + static::assertSame($expected, Regex::isFileName($fileName), $description); + } + + public function testIsLetterOrDigit() + { + self::assertTrue(Regex::isLetterOrDigit('a')); + self::assertTrue(Regex::isLetterOrDigit(10)); + self::assertFalse(Regex::isLetterOrDigit(';')); + } + + public function testIsQuoted() + { + self::assertTrue(Regex::isQuoted('\'lorem ipsum\'')); + self::assertTrue(Regex::isQuoted('"lorem ipsum"')); + + self::assertFalse(Regex::isQuoted('lorem ipsum')); + self::assertFalse(Regex::isQuoted(new stdClass())); + } + + public function testIsSetUriParameter() + { + $uri = 'www.domain.com/?name=phil&type=4'; + + $parameterName = 'type'; + self::assertTrue(Regex::isSetUriParameter($uri, $parameterName)); + + $parameterName = 'color'; + self::assertFalse(Regex::isSetUriParameter($uri, $parameterName)); + } + + /** + * @param string $description Description of test + * @param string $value Value to verify + * @param string $separator Separator used to split width and height + * @param bool $expected Expected result of verification + * + * @dataProvider provideSizeToVerify + */ + public function testIsSizeValue($description, $value, $separator, $expected) + { + self::assertEquals($expected, Regex::isSizeValue($value, $separator), $description); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public static function testIsSizeValueUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::isSizeValue($emptyValue)); + } + + public function testIsSubPathOf() + { + self::assertFalse(Regex::isSubPathOf(null, null)); + self::assertFalse(Regex::isSubPathOf('', '')); + + self::assertFalse(Regex::isSubPathOf('', '/my/directory')); + self::assertFalse(Regex::isSubPathOf('/my/file', '')); + self::assertFalse(Regex::isSubPathOf('/my/file', '/my/directory')); + + self::assertTrue(Regex::isSubPathOf('/my/directory', '/my/directory')); + self::assertTrue(Regex::isSubPathOf('/my/directory/', '/my/directory')); + self::assertTrue(Regex::isSubPathOf('/my/directory', '/my/directory/')); + self::assertTrue(Regex::isSubPathOf('/my/directory/', '/my/directory/')); + + self::assertTrue(Regex::isSubPathOf('/my/another/directory/another/file', '/my/another/directory')); + } + + /** + * @param string $bundleName Full name of bundle to verify, e.g. "MyExtraBundle" + * @param bool $expected Information if it's valid name + * + * @dataProvider provideBundleName + */ + public function testIsValidBundleName($bundleName, $expected) + { + self::assertEquals($expected, Regex::isValidBundleName($bundleName)); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testIsValidBundleNameUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::isValidBundleName($emptyValue)); + } + + /** + * @param string $email E-mail address to validate / verify + * @param bool $expected Information if e-mail is valid + * + * @dataProvider provideEmail + */ + public static function testIsValidEmail($email, $expected) + { + self::assertEquals($expected, Regex::isValidEmail($email)); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public static function testIsValidEmailUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::isValidEmail($emptyValue)); + } + + /** + * @param string $htmlAttribute The html attribute to verify + * @param bool $expected Information if it's valid attribute + * + * @dataProvider provideHtmlAttribute + */ + public function testIsValidHtmlAttribute($htmlAttribute, $expected) + { + self::assertEquals($expected, Regex::isValidHtmlAttribute($htmlAttribute)); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testIsValidHtmlAttributeUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::isValidHtmlAttribute($emptyValue)); + } + + /** + * @param mixed $value Value to verify + * @param bool $expected Information if given value is a money value + * + * @dataProvider provideMoneyValue + */ + public function testIsValidMoneyValue($value, $expected) + { + self::assertEquals($expected, Regex::isValidMoneyValue($value)); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyNonMoneyValue + */ + public function testIsValidMoneyValueUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::isValidMoneyValue($emptyValue)); + } + + public function testIsValidNip() + { + self::assertFalse(Regex::isValidNip(null)); + self::assertFalse(Regex::isValidNip('')); + self::assertFalse(Regex::isValidNip(1234)); + self::assertFalse(Regex::isValidNip(1234567890)); + self::assertFalse(Regex::isValidNip(0000000000)); + self::assertFalse(Regex::isValidNip('1234567890')); + self::assertFalse(Regex::isValidNip('0000000000')); + self::assertFalse(Regex::isValidNip('abc')); + self::assertFalse(Regex::isValidNip($this->simpleText)); + + self::assertTrue(Regex::isValidNip('7340009469')); // Onet S.A. + self::assertTrue(Regex::isValidNip('5252530705')); // Facebook Poland sp. z o.o. + } + + /** + * @param string $phoneNumber The phone number to validate / verify + * @param bool $expected Information if phone number is valid + * + * @dataProvider providePhoneNumber + */ + public static function testIsValidPhoneNumber($phoneNumber, $expected) + { + self::assertEquals($expected, Regex::isValidPhoneNumber($phoneNumber)); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public static function testIsValidPhoneNumberUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::isValidPhoneNumber($emptyValue)); + } + + /** + * @param string $taxIdString Tax ID (NIP) string + * @param bool $expected Information if tax ID is valid + * + * @dataProvider provideTaxId + */ + public static function testIsValidTaxId($taxIdString, $expected) + { + self::assertEquals($expected, Regex::isValidTaxId($taxIdString)); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public static function testIsValidTaxIdUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::isValidTaxId($emptyValue)); } public function testIsValidUrl() @@ -124,28 +2171,37 @@ class RegexTest extends BaseTestCase } } - public function testIsSubPathOf() + public function testIsWindowsBasedPath() { - self::assertFalse(Regex::isSubPathOf(null, null)); - self::assertFalse(Regex::isSubPathOf('', '')); + self::assertTrue(Regex::isWindowsBasedPath('C:\path\to\directory')); + self::assertTrue(Regex::isWindowsBasedPath('C:\path\to\file.jpg')); - self::assertFalse(Regex::isSubPathOf('', '/my/directory')); - self::assertFalse(Regex::isSubPathOf('/my/file', '')); - self::assertFalse(Regex::isSubPathOf('/my/file', '/my/directory')); - - self::assertTrue(Regex::isSubPathOf('/my/directory', '/my/directory')); - self::assertTrue(Regex::isSubPathOf('/my/directory/', '/my/directory')); - self::assertTrue(Regex::isSubPathOf('/my/directory', '/my/directory/')); - self::assertTrue(Regex::isSubPathOf('/my/directory/', '/my/directory/')); - - self::assertTrue(Regex::isSubPathOf('/my/another/directory/another/file', '/my/another/directory')); + self::assertFalse(Regex::isWindowsBasedPath('/path/to/directory')); + self::assertFalse(Regex::isWindowsBasedPath('/path/to/file.jpg')); } - public function testIsLetterOrDigit() + /** + * @param array|string $patterns The patterns to match + * @param string $subject The string to check + * @param bool $expected Information if given $subject matches given $patterns + * + * @dataProvider providePatternsAndSubjectForPregMultiMatch + */ + public function testPregMultiMatch($patterns, $subject, $expected) { - self::assertTrue(Regex::isLetterOrDigit('a')); - self::assertTrue(Regex::isLetterOrDigit(10)); - self::assertFalse(Regex::isLetterOrDigit(';')); + self::assertEquals($expected, Regex::pregMultiMatch($patterns, $subject)); + } + + /** + * @param array|string $patterns The patterns to match + * @param string $subject The string to check + * @param bool $expected Information if given $subject matches given $patterns + * + * @dataProvider providePatternsAndSubjectForPregMultiMatchWhenMustMatchAllPatterns + */ + public function testPregMultiMatchWhenMustMatchAllPatterns($patterns, $subject, $expected) + { + self::assertEquals($expected, Regex::pregMultiMatch($patterns, $subject, true)); } public function testStartsWith() @@ -192,2061 +2248,6 @@ class RegexTest extends BaseTestCase self::assertFalse(Regex::startsWithDirectorySeparator('my\extra\directory', $separatorBackslash)); } - public function testEndsWithDirectorySeparator() - { - // Not provided, default separator - self::assertTrue(Regex::endsWithDirectorySeparator('my simple text/')); - self::assertFalse(Regex::endsWithDirectorySeparator('my simple text')); - - // Slash as separator - $separatorSlash = '/'; - - self::assertTrue(Regex::endsWithDirectorySeparator('my simple text/', $separatorSlash)); - self::assertFalse(Regex::endsWithDirectorySeparator('my simple text', $separatorSlash)); - - // Backslash as separator - $separatorBackslash = '\\'; - - self::assertTrue(Regex::endsWithDirectorySeparator('my simple text\\', $separatorBackslash)); - self::assertFalse(Regex::endsWithDirectorySeparator('my simple text', $separatorBackslash)); - } - - public function testEndsWith() - { - self::assertFalse(Regex::endsWith($this->simpleText, '\.\.\.')); - self::assertFalse(Regex::endsWith($this->simpleText, '\.')); - self::assertTrue(Regex::endsWith($this->simpleText, 't')); - } - - public function testIsSetUriParameter() - { - $uri = 'www.domain.com/?name=phil&type=4'; - - $parameterName = 'type'; - self::assertTrue(Regex::isSetUriParameter($uri, $parameterName)); - - $parameterName = 'color'; - self::assertFalse(Regex::isSetUriParameter($uri, $parameterName)); - } - - public function testContainsEntities() - { - self::assertFalse(Regex::containsEntities('Lorem ipsum')); - self::assertTrue(Regex::containsEntities('Lorem ipsum »')); - } - - public function testContains() - { - self::assertTrue(Regex::contains($this->simpleText, 'ipsum')); - self::assertFalse(Regex::contains($this->simpleText, 'neque')); - - self::assertFalse(Regex::contains($this->simpleText, '.')); - self::assertTrue(Regex::contains($this->simpleText, 'l')); - } - - /** - * @param string $description Description of test - * @param string $fileName - * @param bool $expected Expected result - * - * @dataProvider provideFileName - */ - public function testIsFileName(string $description, string $fileName, bool $expected): void - { - static::assertSame($expected, Regex::isFileName($fileName), $description); - } - - public function testIsQuoted() - { - self::assertTrue(Regex::isQuoted('\'lorem ipsum\'')); - self::assertTrue(Regex::isQuoted('"lorem ipsum"')); - - self::assertFalse(Regex::isQuoted('lorem ipsum')); - self::assertFalse(Regex::isQuoted(new \stdClass())); - } - - public function testIsWindowsBasedPath() - { - self::assertTrue(Regex::isWindowsBasedPath('C:\path\to\directory')); - self::assertTrue(Regex::isWindowsBasedPath('C:\path\to\file.jpg')); - - self::assertFalse(Regex::isWindowsBasedPath('/path/to/directory')); - self::assertFalse(Regex::isWindowsBasedPath('/path/to/file.jpg')); - } - - public function testIsValidNip() - { - self::assertFalse(Regex::isValidNip(null)); - self::assertFalse(Regex::isValidNip('')); - self::assertFalse(Regex::isValidNip(1234)); - self::assertFalse(Regex::isValidNip(1234567890)); - self::assertFalse(Regex::isValidNip(0000000000)); - self::assertFalse(Regex::isValidNip('1234567890')); - self::assertFalse(Regex::isValidNip('0000000000')); - self::assertFalse(Regex::isValidNip('abc')); - self::assertFalse(Regex::isValidNip($this->simpleText)); - - self::assertTrue(Regex::isValidNip('7340009469')); // Onet S.A. - self::assertTrue(Regex::isValidNip('5252530705')); // Facebook Poland sp. z o.o. - } - - /** - * @param mixed $emptyValue Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testIsValidBundleNameUsingEmptyValue($emptyValue) - { - self::assertFalse(Regex::isValidBundleName($emptyValue)); - } - - /** - * @param string $bundleName Full name of bundle to verify, e.g. "MyExtraBundle" - * @param bool $expected Information if it's valid name - * - * @dataProvider provideBundleName - */ - public function testIsValidBundleName($bundleName, $expected) - { - self::assertEquals($expected, Regex::isValidBundleName($bundleName)); - } - - public function testGetBundleNamePattern() - { - self::assertEquals('/^(([A-Z]{1}[a-z0-9]+)((?2))*)(Bundle)$/', Regex::getBundleNamePattern()); - } - - public function testGetHtmlAttributePattern() - { - self::assertEquals('/([\w-]+)="([\w -]+)"/', Regex::getHtmlAttributePattern()); - } - - /** - * @param mixed $emptyValue Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testIsValidHtmlAttributeUsingEmptyValue($emptyValue) - { - self::assertFalse(Regex::isValidHtmlAttribute($emptyValue)); - } - - /** - * @param string $htmlAttribute The html attribute to verify - * @param bool $expected Information if it's valid attribute - * - * @dataProvider provideHtmlAttribute - */ - public function testIsValidHtmlAttribute($htmlAttribute, $expected) - { - self::assertEquals($expected, Regex::isValidHtmlAttribute($htmlAttribute)); - } - - /** - * @param mixed $emptyValue Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public static function testAreValidHtmlAttributesUsingEmptyValue($emptyValue) - { - self::assertFalse(Regex::areValidHtmlAttributes($emptyValue)); - } - - /** - * @param string $htmlAttributes The html attributes to verify - * @param bool $expected Information if attributes are valid - * - * @dataProvider provideHtmlAttributes - */ - public static function testAreValidHtmlAttributes($htmlAttributes, $expected) - { - self::assertEquals($expected, Regex::areValidHtmlAttributes($htmlAttributes)); - } - - /** - * @param string $value Value to verify - * @param bool $expected Information if value is a binary value - * - * @dataProvider provideBinaryValue - */ - public static function testIsBinaryValue($value, $expected) - { - self::assertEquals($expected, Regex::isBinaryValue($value)); - } - - /** - * @param mixed $emptyValue Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public static function testIsValidEmailUsingEmptyValue($emptyValue) - { - self::assertFalse(Regex::isValidEmail($emptyValue)); - } - - /** - * @param string $email E-mail address to validate / verify - * @param bool $expected Information if e-mail is valid - * - * @dataProvider provideEmail - */ - public static function testIsValidEmail($email, $expected) - { - self::assertEquals($expected, Regex::isValidEmail($email)); - } - - /** - * @param mixed $emptyValue Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public static function testIsValidTaxIdUsingEmptyValue($emptyValue) - { - self::assertFalse(Regex::isValidTaxId($emptyValue)); - } - - /** - * @param string $taxIdString Tax ID (NIP) string - * @param bool $expected Information if tax ID is valid - * - * @dataProvider provideTaxId - */ - public static function testIsValidTaxId($taxIdString, $expected) - { - self::assertEquals($expected, Regex::isValidTaxId($taxIdString)); - } - - /** - * @param mixed $emptyValue Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public static function testIsValidPhoneNumberUsingEmptyValue($emptyValue) - { - self::assertFalse(Regex::isValidPhoneNumber($emptyValue)); - } - - /** - * @param string $phoneNumber The phone number to validate / verify - * @param bool $expected Information if phone number is valid - * - * @dataProvider providePhoneNumber - */ - public static function testIsValidPhoneNumber($phoneNumber, $expected) - { - self::assertEquals($expected, Regex::isValidPhoneNumber($phoneNumber)); - } - - /** - * @param string $pattern Pattern to match - * @param array $dataArray The array - * @param array $expected Expected array - * - * @dataProvider providePatternForArrayValues - */ - public static function testGetArrayValuesByPatternUsingValues($pattern, array $dataArray, $expected) - { - self::assertEquals($expected, Regex::getArrayValuesByPattern($pattern, $dataArray)); - } - - /** - * @param string $pattern Pattern to match - * @param array $dataArray The array - * @param array $expected Expected array - * - * @dataProvider providePatternForArrayKeys - */ - public static function testGetArrayValuesByPatternUsingKeys($pattern, array $dataArray, $expected) - { - self::assertEquals($expected, Regex::getArrayValuesByPattern($pattern, $dataArray, true)); - } - - public static function testGetUrlPatternWithProtocolRequired() - { - $pattern = '/^([a-z]+:\/\/)([\da-z\.-]+)\.([a-z\.]{2,6})(\/)?([\w\.\-]*)?(\?)?([\w \.\-\/=&]*)\/?$/i'; - self::assertEquals($pattern, Regex::getUrlPattern(true)); - } - - public static function testGetUrlPatternWithoutProtocol() - { - $pattern = '/^([a-z]+:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})(\/)?([\w\.\-]*)?(\?)?([\w \.\-\/=&]*)\/?$/i'; - self::assertEquals($pattern, Regex::getUrlPattern()); - } - - /** - * @param array $array The array that should be filtered - * @param string $arrayColumnKey Column name - * @param string $filterExpression Simple filter expression, e.g. "== 2" or "!= \'home\'" - * @param array $expected Expected array - * - * @dataProvider provideSimpleExpressionForArrayFiltering - */ - public function testArrayFilterUsingSimpleExpression($array, $arrayColumnKey, $filterExpression, $expected) - { - self::assertEquals($expected, Regex::arrayFilter($array, $arrayColumnKey, $filterExpression)); - } - - /** - * @param array $array The array that should be filtered - * @param string $arrayColumnKey Column name - * @param string $filterExpression Regular expression, e.g. "/\d+/" or "/[a-z]+[,;]{2,}/" - * @param array $expected Expected array - * - * @dataProvider provideRegularExpressionForArrayFiltering - */ - public function testArrayFilterUsingRegularExpression($array, $arrayColumnKey, $filterExpression, $expected) - { - self::assertEquals($expected, Regex::arrayFilter($array, $arrayColumnKey, $filterExpression, true)); - } - - /** - * @param array|string $patterns The patterns to match - * @param string $subject The string to check - * @param bool $expected Information if given $subject matches given $patterns - * - * @dataProvider providePatternsAndSubjectForPregMultiMatch - */ - public function testPregMultiMatch($patterns, $subject, $expected) - { - self::assertEquals($expected, Regex::pregMultiMatch($patterns, $subject)); - } - - /** - * @param array|string $patterns The patterns to match - * @param string $subject The string to check - * @param bool $expected Information if given $subject matches given $patterns - * - * @dataProvider providePatternsAndSubjectForPregMultiMatchWhenMustMatchAllPatterns - */ - public function testPregMultiMatchWhenMustMatchAllPatterns($patterns, $subject, $expected) - { - self::assertEquals($expected, Regex::pregMultiMatch($patterns, $subject, true)); - } - - public function testGetMoneyPattern() - { - self::assertEquals('/^[-+]?\d+([\.,]{1}\d*)?$/', Regex::getMoneyPattern()); - } - - /** - * @param mixed $emptyValue Empty value, e.g. "" - * @dataProvider provideEmptyNonMoneyValue - */ - public function testIsValidMoneyValueUsingEmptyValue($emptyValue) - { - self::assertFalse(Regex::isValidMoneyValue($emptyValue)); - } - - /** - * @param mixed $value Value to verify - * @param bool $expected Information if given value is a money value - * - * @dataProvider provideMoneyValue - */ - public function testIsValidMoneyValue($value, $expected) - { - self::assertEquals($expected, Regex::isValidMoneyValue($value)); - } - - /** - * @param mixed $nonScalarValue Non scalar value, e.g. [] or null - * @dataProvider provideNonScalarValue - */ - public function testGetValidColorHexValueUsingNonScalarValue($nonScalarValue) - { - self::assertFalse(Regex::getValidColorHexValue($nonScalarValue)); - } - - /** - * @param mixed $emptyValue Empty value, e.g. "" - * @dataProvider provideColorEmptyValue - */ - public function testGetValidColorHexValueUsingEmptyValueWithoutException($emptyValue) - { - self::assertFalse(Regex::getValidColorHexValue($emptyValue, false)); - } - - /** - * @param mixed $emptyValue Empty value, e.g. "" - * @dataProvider provideColorEmptyValue - */ - public function testGetValidColorHexValueUsingEmptyValue($emptyValue) - { - $this->expectException(IncorrectColorHexLengthException::class); - Regex::getValidColorHexValue($emptyValue); - } - - /** - * @param string $incorrectColor Incorrect value of color - * @dataProvider provideColorIncorrectLength - */ - public function testGetValidColorHexValueUsingIncorrectValueWithoutException($incorrectColor) - { - self::assertFalse(Regex::getValidColorHexValue($incorrectColor, false)); - } - - /** - * @param string $incorrectColor Incorrect value of color - * @dataProvider provideColorIncorrectLength - */ - public function testGetValidColorHexValueUsingIncorrectValue($incorrectColor) - { - $this->expectException(IncorrectColorHexLengthException::class); - Regex::getValidColorHexValue($incorrectColor); - } - - /** - * @param string $invalidColor Invalid value of color - * @dataProvider provideColorInvalidValue - */ - public function testGetValidColorHexValueUsingInvalidValueWithoutException($invalidColor) - { - self::assertFalse(Regex::getValidColorHexValue($invalidColor, false)); - } - - /** - * @param string $invalidColor Invalid value of color - * @dataProvider provideColorInvalidValue - */ - public function testGetValidColorHexValueUsingInvalidValue($invalidColor) - { - $this->expectException(InvalidColorHexValueException::class); - Regex::getValidColorHexValue($invalidColor); - } - - /** - * @param string $color Color to verify - * @param string $expected Expected value of color - * - * @dataProvider provideColor - */ - public function testGetValidColorHexValue($color, $expected) - { - self::assertEquals($expected, Regex::getValidColorHexValue($color)); - } - - /** - * @param mixed $emptyValue Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public static function testIsSizeValueUsingEmptyValue($emptyValue) - { - self::assertFalse(Regex::isSizeValue($emptyValue)); - } - - /** - * @param string $description Description of test - * @param string $value Value to verify - * @param string $separator Separator used to split width and height - * @param bool $expected Expected result of verification - * - * @dataProvider provideSizeToVerify - */ - public function testIsSizeValue($description, $value, $separator, $expected) - { - self::assertEquals($expected, Regex::isSizeValue($value, $separator), $description); - } - - /** - * @param string $value Value that should be transformed to slug - * @param string $expected Expected slug - * - * @dataProvider provideValueSlug - */ - public function testCreateSlug($value, $expected) - { - self::assertSame($expected, Regex::createSlug($value)); - } - - /** - * @param string $string - * @param string $expected - * - * @dataProvider provideStringToClearBeginningSlash - */ - public function testClearBeginningSlash(string $string, string $expected): void - { - static::assertSame($expected, Regex::clearBeginningSlash($string)); - } - - /** - * @param string $string - * @param string $expected - * - * @dataProvider provideStringToClearEndingSlash - */ - public function testClearEndingSlash(string $string, string $expected): void - { - static::assertSame($expected, Regex::clearEndingSlash($string)); - } - - /** - * Provides name of bundle and information if it's valid name - * - * @return Generator - */ - public function provideBundleName() - { - yield[ - 'something', - false, - ]; - - yield[ - 'something_different', - false, - ]; - - yield[ - 'something-else', - false, - ]; - - yield[ - 'myExtraBundle', - false, - ]; - - yield[ - 'MyExtra', - false, - ]; - - yield[ - 'MyExtraBundle', - true, - ]; - - yield[ - 'MySuperExtraGorgeousBundle', - true, - ]; - } - - /** - * Provides html attribute and information if it's valid - * - * @return Generator - */ - public function provideHtmlAttribute() - { - yield[ - 'abc = def', - false, - ]; - - yield[ - 'a b c=def', - false, - ]; - - yield[ - 'abc=def', - false, - ]; - - yield[ - 'a1b2c=d3e4f', - false, - ]; - - yield[ - 'abc="def"', - true, - ]; - - yield[ - 'a1b2c="d3e4f"', - true, - ]; - } - - /** - * Provides html attribute and information if attributes are valid - * - * @return Generator - */ - public function provideHtmlAttributes() - { - yield[ - 'abc = def', - false, - ]; - - yield[ - 'abc = def ghi = jkl', - false, - ]; - - yield[ - 'abc=def ghi=jkl', - false, - ]; - - yield[ - 'abc=def ghi=jkl mno=pqr', - false, - ]; - - yield[ - 'abc="def"', - true, - ]; - - yield[ - 'abc="def" ghi="jkl"', - true, - ]; - - yield[ - 'abc="def" ghi="jkl" mno="pqr"', - true, - ]; - - yield[ - 'a2bc="d4ef" ghi="j k l" mno="pq9r"', - true, - ]; - } - - /** - * Provides value to verify if it is a binary value - * - * @return Generator - */ - public function provideBinaryValue() - { - $file1Path = $this->getFilePathForTesting('lorem-ipsum.txt'); - $file2Path = $this->getFilePathForTesting('minion.jpg'); - - yield[ - null, - false, - ]; - - yield[ - [], - false, - ]; - - yield[ - '', - false, - ]; - - yield[ - 'abc', - false, - ]; - - yield[ - '1234', - false, - ]; - - yield[ - 1234, - false, - ]; - - yield[ - 12.34, - false, - ]; - - yield[ - fread(fopen($file1Path, 'rb'), 1), - false, - ]; - - yield[ - fread(fopen($file2Path, 'rb'), 1), - true, - ]; - } - - /** - * Provides e-mail and information if it's valid - * - * @return Generator - */ - public function provideEmail() - { - yield[ - '1', - false, - ]; - - yield[ - 1, - false, - ]; - - yield[ - 'a@a', - false, - ]; - - yield[ - 'a@a.com', - false, - ]; - - yield[ - 'aa@a.com', - true, - ]; - - yield[ - 'a.b@d.com', - true, - ]; - } - - /** - * Provides tax ID and information if it's valid - * - * @return Generator - */ - public function provideTaxId() - { - yield[ - '123', - false, - ]; - - yield[ - '12345', - false, - ]; - - yield[ - '1122334455', - false, - ]; - - yield[ - '1234567890', - false, - ]; - - yield[ - '0987654321', - false, - ]; - - // Microsoft sp. z o.o. - yield[ - '5270103391', - true, - ]; - - // Onet S.A. - yield[ - '7340009469', - true, - ]; - } - - /** - * Provides phone number and information if it's valid - * - * @return Generator - */ - public function providePhoneNumber() - { - yield[ - 'abc', - false, - ]; - - yield[ - '1-2-3', - false, - ]; - - yield[ - '123', - true, - ]; - - yield[ - '123 456 789', - true, - ]; - - yield[ - '123456789', - true, - ]; - } - - /** - * Provides pattern and array with values that should match that pattern - * - * @return Generator - */ - public function providePatternForArrayValues() - { - yield[ - '/\d/', - [], - [], - ]; - - yield[ - '/\d+/', - [ - 'lorem', - 'ipsum', - 123, - 'dolor', - '456', - ], - [ - 2 => 123, - 4 => '456', - ], - ]; - - yield[ - '/\d+-[a-z]+/', - [ - 'lorem', - 123, - false, - 'dolor', - '456-ipsum', - ], - [ - 4 => '456-ipsum', - ], - ]; - } - - /** - * Provides pattern and array with keys that should match that pattern - * - * @return Generator - */ - public function providePatternForArrayKeys() - { - yield[ - '/\d/', - [], - [], - ]; - - yield[ - '/\d+/', - [ - 'lorem' => 'ipsum', - 'dolor' => 123, - 'sit', - 4 => '456', - ], - [ - 0 => 'sit', - 4 => '456', - ], - ]; - - yield[ - '/\d+-[a-z]+/', - [ - 'lorem', - '456-ipsum' => 123, - '001-sit' => false, - 'dolor', - ], - [ - '456-ipsum' => 123, - '001-sit' => false, - ], - ]; - } - - /** - * Provides simple compare expression for array filtering and the array - * - * @return Generator - */ - public function provideSimpleExpressionForArrayFiltering() - { - yield[ - [], - 'id', - ' == 2', - [], - ]; - - yield[ - [ - [ - 'id' => 1, - 'first_name' => 'Jane', - 'last_name' => 'Scott', - 'is_active' => true, - ], - [ - 'id' => 2, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - [ - 'id' => 3, - 'first_name' => 'Mike', - 'last_name' => 'Green', - 'is_active' => false, - ], - ], - 'birth_date', - ' == 2', - [ - [ - 'id' => 1, - 'first_name' => 'Jane', - 'last_name' => 'Scott', - 'is_active' => true, - ], - [ - 'id' => 2, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - [ - 'id' => 3, - 'first_name' => 'Mike', - 'last_name' => 'Green', - 'is_active' => false, - ], - ], - ]; - - yield[ - [ - [ - 'id' => 1, - 'first_name' => 'Jane', - 'last_name' => 'Scott', - 'is_active' => true, - ], - [ - 'id' => 2, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - [ - 'id' => 3, - 'first_name' => 'Mike', - 'last_name' => 'Green', - 'is_active' => false, - ], - ], - 'id', - ' == 2', - [ - 1 => [ - 'id' => 2, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - ], - ]; - - yield[ - [ - [ - 'id' => 1, - 'first_name' => 'Jane', - 'last_name' => 'Scott', - 'is_active' => true, - ], - [ - 'id' => 2, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - [ - 'id' => 3, - 'first_name' => 'Mike', - 'last_name' => 'Green', - 'is_active' => false, - ], - ], - 'id', - ' >= 2', - [ - 1 => [ - 'id' => 2, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - 2 => [ - 'id' => 3, - 'first_name' => 'Mike', - 'last_name' => 'Green', - 'is_active' => false, - ], - ], - ]; - - yield[ - [ - [ - 'id' => 1, - 'first_name' => 'Jane', - 'last_name' => 'Scott', - 'is_active' => true, - ], - [ - 'id' => 2, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - [ - 'id' => 3, - 'first_name' => 'Mike', - 'last_name' => 'Green', - 'is_active' => false, - ], - ], - 'is_active', - ' !== true', - [ - 2 => [ - 'id' => 3, - 'first_name' => 'Mike', - 'last_name' => 'Green', - 'is_active' => false, - ], - ], - ]; - - yield[ - [ - [ - 'id' => 1, - 'first_name' => 'Jane', - 'last_name' => 'Scott', - 'is_active' => true, - ], - [ - 'id' => 2, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - [ - 'id' => 3, - 'first_name' => 'Mike', - 'last_name' => 'Green', - 'is_active' => false, - ], - ], - 'first_name', - ' == \'Mike\'', - [ - 2 => [ - 'id' => 3, - 'first_name' => 'Mike', - 'last_name' => 'Green', - 'is_active' => false, - ], - ], - ]; - } - - /** - * Provides regular expression for array filtering and the array - * - * @return Generator - */ - public function provideRegularExpressionForArrayFiltering() - { - yield[ - [], - 'id', - '/\d+/', - [], - ]; - - yield[ - [ - [ - 'id' => 1, - 'first_name' => 'Jane', - 'last_name' => 'Scott', - 'is_active' => true, - ], - [ - 'id' => 2, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - [ - 'id' => 3, - 'first_name' => 'Mike', - 'last_name' => 'Green', - 'is_active' => false, - ], - ], - 'birth_date', - '/\d+/', - [ - [ - 'id' => 1, - 'first_name' => 'Jane', - 'last_name' => 'Scott', - 'is_active' => true, - ], - [ - 'id' => 2, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - [ - 'id' => 3, - 'first_name' => 'Mike', - 'last_name' => 'Green', - 'is_active' => false, - ], - ], - ]; - - yield[ - [ - [ - 'id' => 1, - 'first_name' => 'Jane', - 'last_name' => 'Scott', - 'is_active' => true, - ], - [ - 'id' => 123, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - [ - 'id' => 3, - 'first_name' => 'Mike', - 'last_name' => 'Green', - 'is_active' => false, - ], - ], - 'id', - '/\d{3}/', - [ - 1 => [ - 'id' => 123, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - ], - ]; - - yield[ - [ - [ - 'id' => 1, - 'first_name' => 'Jane', - 'last_name' => 'Scott', - 'is_active' => true, - ], - [ - 'id' => 123, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - [ - 'id' => 456, - 'first_name' => 'Mike', - 'last_name' => 'Green', - 'is_active' => false, - ], - ], - 'first_name', - '/George|Mike/', - [ - 1 => [ - 'id' => 123, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - 2 => [ - 'id' => 456, - 'first_name' => 'Mike', - 'last_name' => 'Green', - 'is_active' => false, - ], - ], - ]; - - yield[ - [ - [ - 'id' => 1, - 'first_name' => 'Jane', - 'last_name' => 'Scott', - 'is_active' => true, - ], - [ - 'id' => 2, - 'first_name' => 'George', - 'last_name' => 'Brown', - 'is_active' => true, - ], - [ - 'id' => 3, - 'first_name' => 'Mike', - 'last_name' => 'Green-Blue', - 'is_active' => false, - ], - ], - 'last_name', - '/\w+-\w+/', - [ - 2 => [ - 'id' => 3, - 'first_name' => 'Mike', - 'last_name' => 'Green-Blue', - 'is_active' => false, - ], - ], - ]; - } - - /** - * Provides patterns and subject for the pregMultiMatch() method - * - * @return Generator - */ - public function providePatternsAndSubjectForPregMultiMatch() - { - yield[ - '', - '', - false, - ]; - - yield[ - [], - '', - false, - ]; - - yield[ - '/\d+/', - 'Lorem ipsum dolor sit', - false, - ]; - - yield[ - [ - '/\d+/', - '/^[a-z]{4}$/', - ], - 'Lorem ipsum dolor sit', - false, - ]; - - yield[ - '/\w+/', - 'Lorem ipsum dolor sit', - true, - ]; - - yield[ - [ - '/\d+/', - '/\w+/', - ], - 'Lorem ipsum dolor sit', - true, - ]; - } - - /** - * Provides patterns and subject for the pregMultiMatch() method when must match all patterns - * - * @return Generator - */ - public function providePatternsAndSubjectForPregMultiMatchWhenMustMatchAllPatterns() - { - yield[ - '', - '', - false, - ]; - - yield[ - [], - '', - false, - ]; - - yield[ - '/\d+/', - 'Lorem ipsum dolor sit', - false, - ]; - - yield[ - [ - '/\d+/', - '/^[a-z]{4}$/', - ], - 'Lorem ipsum dolor sit', - false, - ]; - - yield[ - '/\w+/', - 'Lorem ipsum dolor sit', - true, - ]; - - yield[ - [ - '/[a-zA-Z ]+/', - '/\w+/', - ], - 'Lorem ipsum dolor sit', - true, - ]; - } - - /** - * Provides empty non money-related value - * - * @return Generator - */ - public function provideEmptyNonMoneyValue() - { - yield['']; - yield[' ']; - yield[null]; - yield[false]; - yield[[]]; - } - - /** - * Provides money-related value and information if the value is valid - * - * @return Generator - */ - public function provideMoneyValue() - { - yield[ - 'abc', - false, - ]; - - yield[ - '-a.b', - false, - ]; - - yield[ - 'a,b', - false, - ]; - - yield[ - 0, - true, - ]; - - yield[ - 1, - true, - ]; - - yield[ - -1, - true, - ]; - - yield[ - 1.2, - true, - ]; - - yield[ - 1.202, - true, - ]; - - yield[ - -1.202, - true, - ]; - - yield[ - '0', - true, - ]; - - yield[ - '1', - true, - ]; - - yield[ - '-1', - true, - ]; - - yield[ - '1.2', - true, - ]; - - yield[ - '1.202', - true, - ]; - - yield[ - '-1.202', - true, - ]; - - yield[ - '1,202', - true, - ]; - - yield[ - '-1,2', - true, - ]; - - yield[ - '-1,202', - true, - ]; - } - - /** - * Provides value of color with incorrect length - * - * @return Generator - */ - public function provideColorIncorrectLength() - { - yield[ - '12', - ]; - - yield[ - '1234', - ]; - - yield[ - '12345678', - ]; - - yield[ - '#12', - ]; - - yield[ - '#1234', - ]; - - yield[ - '#12345678', - ]; - } - - /** - * Provides invalid value of color - * - * @return Generator - */ - public function provideColorInvalidValue() - { - yield[ - '#qwerty', - ]; - - yield[ - 'qwerty', - ]; - } - - /** - * Provides empty non color-related value - * - * @return Generator - */ - public function provideColorEmptyValue() - { - yield[ - '', - ]; - - yield[ - 0, - ]; - - yield[ - '0', - ]; - - yield[ - false, - ]; - } - - /** - * Provides value of color - * - * @return Generator - */ - public function provideColor() - { - yield[ - '#1b0', - '11bb00', - ]; - - yield[ - '#1B0', - '11bb00', - ]; - - yield[ - '#1ab1ab', - '1ab1ab', - ]; - - yield[ - '#1AB1AB', - '1ab1ab', - ]; - - yield[ - '#000', - '000000', - ]; - } - - /** - * Provide value to create slug - * - * @return Generator - */ - public function provideValueSlug() - { - yield[ - [], - false, - ]; - - yield[ - null, - false, - ]; - - yield[ - '', - '', - ]; - - yield[ - 1234, - '1234', - ]; - - yield[ - '1234', - '1234', - ]; - - yield[ - '1/2/3/4', - '1234', - ]; - - yield[ - '1 / 2 / 3 / 4', - '1-2-3-4', - ]; - - yield[ - 'test', - 'test', - ]; - - yield[ - 'test test', - 'test-test', - ]; - - yield[ - 'lorem ipsum dolor sit', - 'lorem-ipsum-dolor-sit', - ]; - - yield[ - 'Lorem ipsum. Dolor sit 12.34 amet.', - 'lorem-ipsum-dolor-sit-1234-amet', - ]; - - yield[ - 'Was sind Löwen, Bären, Vögel und Käfer (für die Prüfung)?', - 'was-sind-lowen-baren-vogel-und-kafer-fur-die-prufung', - ]; - - yield[ - 'äöü (ÄÖÜ)', - 'aou-aou', - ]; - - yield[ - 'Półka dębowa. Kolor: żółędziowy. Wymiary: 80 x 30 cm.', - 'polka-debowa-kolor-zoledziowy-wymiary-80-x-30-cm', - ]; - - yield[ - 'ąęółńśżźć (ĄĘÓŁŃŚŻŹĆ)', - 'aeolnszzc-aeolnszzc', - ]; - } - - public function provideSizeToVerify() - { - yield[ - 'One number only', - 200, - ' x ', - false, - ]; - - yield[ - 'One number only as string', - '200', - ' x ', - false, - ]; - - yield[ - 'The " " as invalid separator', - '200 100', - ' x ', - false, - ]; - - yield[ - 'The "|" as separator (invalid separator)', - '200 | 100', - ' x ', - false, - ]; - - yield[ - 'The "|" as invalid separator and no spaces around separator', - '200|100', - ' x ', - false, - ]; - - yield[ - 'The "X" as invalid separator', - '200 X 100', - ' x ', - false, - ]; - - yield[ - 'Simple, valid size', - '200 x 100', - ' x ', - true, - ]; - - yield[ - 'Too much spaces at the right of separator', - '200 x 100', - ' x ', - true, - ]; - - yield[ - 'Too much spaces at the left of separator', - '200 x 100', - ' x ', - true, - ]; - - yield[ - 'Too much spaces around separator', - '200 x 100', - ' x ', - true, - ]; - - yield[ - 'Too much spaces before width', - ' 200 x 100', - ' x ', - true, - ]; - - yield[ - 'Too much spaces after height', - '200 x 100 ', - ' x ', - true, - ]; - - yield[ - 'Too much spaces before width and after height', - ' 200 x 100 ', - ' x ', - true, - ]; - - yield[ - 'Too much spaces everywhere (1st)', - ' 200 x 100 ', - ' x ', - true, - ]; - - yield[ - 'Too much spaces everywhere (2nd)', - ' 200 x 100 ', - ' x ', - true, - ]; - - yield[ - 'Too much spaces everywhere (3rd)', - ' 200 x 100 ', - ' x ', - true, - ]; - - yield[ - 'The " X " as custom separator', - '200 X 100', - ' X ', - true, - ]; - - yield[ - 'The "|" as custom separator', - '200|100', - '|', - true, - ]; - - yield[ - 'The " | " as custom separator', - '200 | 100', - ' | ', - true, - ]; - - yield[ - 'The "::" as custom separator', - '200::100', - '::', - true, - ]; - - yield[ - 'The " :: " as custom separator', - '200 :: 100', - ' :: ', - true, - ]; - - yield[ - 'The "." as custom separator', - '200.100', - '.', - true, - ]; - - yield[ - 'The " . " as custom separator', - '200 . 100', - ' . ', - true, - ]; - - yield[ - 'The "/" as custom separator', - '200/100', - '/', - true, - ]; - - yield[ - 'The " / " as custom separator', - '200 / 100', - ' / ', - true, - ]; - - yield[ - 'The " : " as custom separator and too much spaces everywhere', - ' 200 : 100 ', - ' : ', - true, - ]; - } - - public function provideStringToClearBeginningSlash(): ?Generator - { - yield[ - '', - '', - ]; - - yield[ - '/', - '', - ]; - - yield[ - '\\', - '\\', - ]; - - yield[ - '//', - '/', - ]; - - yield[ - 'lorem ipsum', - 'lorem ipsum', - ]; - - yield[ - '1234', - '1234', - ]; - - yield[ - 'lorem/ipsum', - 'lorem/ipsum', - ]; - - yield[ - 'lorem / ipsum', - 'lorem / ipsum', - ]; - - yield[ - 'lorem\ipsum', - 'lorem\ipsum', - ]; - - yield[ - 'lorem \ ipsum', - 'lorem \ ipsum', - ]; - - yield[ - '\lorem ipsum', - '\lorem ipsum', - ]; - - yield[ - '\ lorem ipsum', - '\ lorem ipsum', - ]; - - yield[ - 'lorem ipsum/', - 'lorem ipsum/', - ]; - - yield[ - 'lorem ipsum /', - 'lorem ipsum /', - ]; - - yield[ - '/lorem ipsum', - 'lorem ipsum', - ]; - - yield[ - '/ lorem ipsum', - ' lorem ipsum', - ]; - - yield[ - '/123 456', - '123 456', - ]; - - yield[ - '/ 123 456', - ' 123 456', - ]; - - yield[ - '/lorem 123 ipsum 456', - 'lorem 123 ipsum 456', - ]; - - yield[ - '/ lorem 123 ipsum 456', - ' lorem 123 ipsum 456', - ]; - } - - public function provideStringToClearEndingSlash(): ?Generator - { - yield[ - '', - '', - ]; - - yield[ - '/', - '', - ]; - - yield[ - '\\', - '\\', - ]; - - yield[ - '//', - '/', - ]; - - yield[ - 'lorem ipsum', - 'lorem ipsum', - ]; - - yield[ - '1234', - '1234', - ]; - - yield[ - 'lorem/ipsum', - 'lorem/ipsum', - ]; - - yield[ - 'lorem / ipsum', - 'lorem / ipsum', - ]; - - yield[ - 'lorem\ipsum', - 'lorem\ipsum', - ]; - - yield[ - 'lorem \ ipsum', - 'lorem \ ipsum', - ]; - - yield[ - '\lorem ipsum', - '\lorem ipsum', - ]; - - yield[ - '\ lorem ipsum', - '\ lorem ipsum', - ]; - - yield[ - '/lorem ipsum', - '/lorem ipsum', - ]; - - yield[ - '/ lorem ipsum', - '/ lorem ipsum', - ]; - - yield[ - 'lorem ipsum/', - 'lorem ipsum', - ]; - - yield[ - 'lorem ipsum /', - 'lorem ipsum ', - ]; - - yield[ - '123 456/', - '123 456', - ]; - - yield[ - '123 456 /', - '123 456 ', - ]; - - yield[ - 'lorem 123 ipsum 456/', - 'lorem 123 ipsum 456', - ]; - - yield[ - 'lorem 123 ipsum 456 /', - 'lorem 123 ipsum 456 ', - ]; - } - - public function provideFileName(): ?Generator - { - yield[ - 'An empty string', - '', - false, - ]; - - yield[ - 'Path of this file, of file with test case', - __DIR__, - false, - ]; - - yield[ - 'Name of this file, of file with test case', - __FILE__, - true, - ]; - - yield[ - 'Complicated name of file', - 'this-1_2 3 & my! 4+file.jpg', - true, - ]; - - yield[ - 'Complicated name of file', - 'directory1/directory2/this-1_2 3 & my! 4+file.jpg', - true, - ]; - } - /** * {@inheritdoc} */ diff --git a/tests/Utilities/RepositoryTest.php b/tests/Utilities/RepositoryTest.php index dfb85c4..572b9ef 100644 --- a/tests/Utilities/RepositoryTest.php +++ b/tests/Utilities/RepositoryTest.php @@ -28,17 +28,814 @@ use stdClass; */ class RepositoryTest extends BaseTestCase { + /** + * Provides arrays with extreme position used to replenish positions of them + * + * @return Generator + */ + public function provideArraysWithExtremePosition() + { + yield [ + [ + [ + Repository::POSITION_KEY => 1, + ], + [], + [], + ], + true, + [ + [ + Repository::POSITION_KEY => 1, + ], + [ + Repository::POSITION_KEY => 2, + ], + [ + Repository::POSITION_KEY => 3, + ], + ], + ]; + + yield [ + [ + [], + [], + [ + Repository::POSITION_KEY => 1, + ], + ], + true, + [ + [ + Repository::POSITION_KEY => 2, + ], + [ + Repository::POSITION_KEY => 3, + ], + [ + Repository::POSITION_KEY => 1, + ], + ], + ]; + + yield [ + [ + [ + Repository::POSITION_KEY => 1, + ], + [], + [], + ], + false, + [ + [ + Repository::POSITION_KEY => 1, + ], + [ + Repository::POSITION_KEY => 0, + ], + [ + Repository::POSITION_KEY => -1, + ], + ], + ]; + + yield [ + [ + [], + [], + [ + Repository::POSITION_KEY => 1, + ], + ], + false, + [ + [ + Repository::POSITION_KEY => 0, + ], + [ + Repository::POSITION_KEY => -1, + ], + [ + Repository::POSITION_KEY => 1, + ], + ], + ]; + } + + /** + * Provides arrays with extreme position used to get extreme position + * + * @return Generator + */ + public function provideArraysWithExtremePositionToGetExtremePosition() + { + yield [ + [ + [ + Repository::POSITION_KEY => 1, + ], + [], + [], + ], + true, + 1, + ]; + + yield [ + [ + [ + Repository::POSITION_KEY => 1, + ], + [], + [], + ], + false, + 1, + ]; + + yield [ + [ + [], + [], + [ + Repository::POSITION_KEY => 1, + ], + ], + true, + 1, + ]; + + yield [ + [ + [], + [], + [ + Repository::POSITION_KEY => 1, + ], + ], + false, + 1, + ]; + + yield [ + [ + [ + Repository::POSITION_KEY => 1, + ], + [], + [ + Repository::POSITION_KEY => 2, + ], + [], + ], + true, + 2, + ]; + + yield [ + [ + [ + Repository::POSITION_KEY => 1, + ], + [], + [ + Repository::POSITION_KEY => 2, + ], + [], + ], + false, + 1, + ]; + } + + /** + * Provides arrays without extreme position used to replenish positions of them + * + * @return Generator + */ + public function provideArraysWithoutExtremePosition() + { + yield [ + [ + [], + [], + ], + true, + [ + [ + Repository::POSITION_KEY => 1, + ], + [ + Repository::POSITION_KEY => 2, + ], + ], + ]; + + yield [ + [ + [], + [], + ], + false, + [ + [ + Repository::POSITION_KEY => -1, + ], + [ + Repository::POSITION_KEY => -2, + ], + ], + ]; + + yield [ + [ + [ + 'lorem' => 'ipsum', + 'dolor', + 'sit' => 1, + ], + [ + 'abc' => 'def', + 'ghi' => null, + 'jkl' => 10, + ], + ], + true, + [ + [ + 'lorem' => 'ipsum', + 'dolor', + 'sit' => 1, + Repository::POSITION_KEY => 1, + ], + [ + 'abc' => 'def', + 'ghi' => null, + 'jkl' => 10, + Repository::POSITION_KEY => 2, + ], + ], + ]; + + yield [ + [ + [ + 'lorem' => 'ipsum', + 'dolor', + 'sit' => 1, + ], + [ + 'abc' => 'def', + 'ghi' => null, + 'jkl' => 10, + ], + ], + false, + [ + [ + 'lorem' => 'ipsum', + 'dolor', + 'sit' => 1, + Repository::POSITION_KEY => -1, + ], + [ + 'abc' => 'def', + 'ghi' => null, + 'jkl' => 10, + Repository::POSITION_KEY => -2, + ], + ], + ]; + } + + /** + * Provides arrays without extreme position used to get extreme position + * + * @return Generator + */ + public function provideArraysWithoutExtremePositionToGetExtremePosition() + { + yield [ + [], + false, + null, + ]; + + yield [ + [], + true, + null, + ]; + + yield [ + [ + [ + 'lorem' => 'ipsum', + 'dolor', + 'sit' => 1, + ], + [ + 'abc' => 'def', + 'ghi' => null, + 'jkl' => 10, + ], + ], + true, + null, + ]; + + yield [ + [ + [ + 'lorem' => 'ipsum', + 'dolor', + 'sit' => 1, + ], + [ + 'abc' => 'def', + 'ghi' => null, + 'jkl' => 10, + ], + ], + false, + null, + ]; + } + + /** + * Provides objects with extreme position used to replenish positions of them + * + * @return Generator + */ + public function provideObjectsWithExtremePosition() + { + yield [ + [ + new Sortable(1), + new Sortable(), + new Sortable(), + ], + true, + [ + new Sortable(1), + new Sortable(2), + new Sortable(3), + ], + ]; + + yield [ + [ + new Sortable(), + new Sortable(1), + new Sortable(), + ], + true, + [ + new Sortable(2), + new Sortable(1), + new Sortable(3), + ], + ]; + + yield [ + [ + new Sortable(1), + new Sortable(), + new Sortable(), + ], + false, + [ + new Sortable(1), + new Sortable(0), + new Sortable(-1), + ], + ]; + } + + /** + * Provides objects with extreme position used to get extreme position + * + * @return Generator + */ + public function provideObjectsWithExtremePositionToGetExtremePosition() + { + yield [ + [ + new Sortable(1), + new Sortable(2), + new Sortable(3), + ], + true, + 3, + ]; + + yield [ + [ + new Sortable(1), + new Sortable(2), + new Sortable(3), + ], + false, + 1, + ]; + } + + /** + * Provides objects without extreme position used to replenish positions of them + * + * @return Generator + */ + public function provideObjectsWithoutExtremePosition() + { + yield [ + [ + new Sortable(), + new Sortable(), + new Sortable(), + ], + true, + [ + new Sortable(1), + new Sortable(2), + new Sortable(3), + ], + ]; + + yield [ + [ + new Sortable(), + new Sortable(), + new Sortable(), + ], + false, + [ + new Sortable(-1), + new Sortable(-2), + new Sortable(-3), + ], + ]; + } + + /** + * Provides objects without extreme position used to get extreme position + * + * @return Generator + */ + public function provideObjectsWithoutExtremePositionToGetExtremePosition() + { + yield [ + [], + false, + null, + ]; + + yield [ + [], + true, + null, + ]; + + yield [ + [ + new Sortable(), + new Sortable(), + new Sortable(), + ], + true, + null, + ]; + + yield [ + [ + new Sortable(), + new Sortable(), + new Sortable(), + ], + false, + null, + ]; + } + + /** + * Provide name of property, direction and expected ORDER BY clause used to get query builder + * + * @return Generator + */ + public function providePropertyAndDirectionToGetEntityOrderedQueryBuilder() + { + yield [ + null, + null, + '', + ]; + + yield [ + '', + '', + '', + ]; + + yield [ + 'first_name', + '', + 'qb.first_name ASC', + ]; + + yield [ + 'first_name', + 'asc', + 'qb.first_name asc', + ]; + + yield [ + 'first_name', + 'ASC', + 'qb.first_name ASC', + ]; + + yield [ + 'first_name', + 'desc', + 'qb.first_name desc', + ]; + + yield [ + 'first_name', + 'DESC', + 'qb.first_name DESC', + ]; + } + + public function provideSortedItems() + { + $sortable1 = new Sortable(); + $sortable1->setPosition(1); + + $sortable2 = new Sortable(); + $sortable2->setPosition(2); + + $sortable3 = new Sortable(); + $sortable3->setPosition(309); + + yield [ + 'An array with 1 item only', + [ + [ + 'test 1', + 'position' => 1, + ], + ], + [ + [ + 'test 1', + 'position' => 1, + ], + ], + ]; + + yield [ + 'An array with more than 1 item', + [ + [ + 'test 1', + 'position' => 1, + ], + [ + 'test 2', + 'position' => 2, + ], + [ + 'test 3', + 'position' => 309, + ], + ], + [ + [ + 'test 1', + 'position' => 1, + ], + [ + 'test 2', + 'position' => 2, + ], + [ + 'test 3', + 'position' => 309, + ], + ], + ]; + + yield [ + '1 object only', + [ + $sortable1, + ], + [ + $sortable1, + ], + ]; + + yield [ + 'More than 1 object', + [ + $sortable1, + $sortable2, + $sortable3, + ], + [ + $sortable1, + $sortable2, + $sortable3, + ], + ]; + } + public function testConstructor() { static::assertHasNoConstructor(Repository::class); } - public function testReplenishPositionsWithoutItems() + /** + * @param string $property Name of property used by the ORDER BY clause + * @param string $direction Direction used by the ORDER BY clause ("ASC" or "DESC") + * @param string $expectedOrderBy Expected ORDER BY clause + * + * @dataProvider providePropertyAndDirectionToGetEntityOrderedQueryBuilder + */ + public function testGetEntityOrderedQueryBuilder($property, $direction, $expectedOrderBy) { - $items = []; - Repository::replenishPositions($items); + $entityManager = $this->createMock(EntityManagerInterface::class); - static::assertSame([], $items); + $entityRepository = $this + ->getMockBuilder(EntityRepository::class) + ->disableOriginalConstructor() + ->setMethods([ + 'createQueryBuilder', + ]) + ->getMock(); + + $expectedQueryBuilder = new QueryBuilder($entityManager); + $expectedQueryBuilder->from('any_table_name', 'qb'); + + $entityRepository + ->expects(static::once()) + ->method('createQueryBuilder') + ->willReturn($expectedQueryBuilder) + ; + + $queryBuilder = Repository::getEntityOrderedQueryBuilder($entityRepository, $property, $direction); + $selectDQLPart = $queryBuilder->getDQLPart('select'); + $whereDQLPart = $queryBuilder->getDQLPart('where'); + $orderDQLPart = $queryBuilder->getDQLPart('orderBy'); + $rootAliases = $queryBuilder->getRootAliases(); + + static::assertInstanceOf(QueryBuilder::class, $queryBuilder); + static::assertArrayHasKey(0, $rootAliases); + static::assertSame('qb', $rootAliases[0]); + static::assertSame([], $selectDQLPart); + static::assertNull($whereDQLPart); + + if (empty($property)) { + static::assertSame([], $orderDQLPart); + } else { + /** @var OrderBy $orderBy */ + $orderBy = $orderDQLPart[0]; + + static::assertSame([$expectedOrderBy], $orderBy->getParts()); + } + } + + public function testGetEntityOrderedQueryBuilderUsingDefaults() + { + $entityManager = $this->createMock(EntityManagerInterface::class); + + $entityRepository = $this + ->getMockBuilder(EntityRepository::class) + ->disableOriginalConstructor() + ->setMethods([ + 'createQueryBuilder', + ]) + ->getMock(); + + $expectedQueryBuilder = new QueryBuilder($entityManager); + $expectedQueryBuilder->from('any_table_name', 'qb'); + + $entityRepository + ->expects(static::once()) + ->method('createQueryBuilder') + ->willReturn($expectedQueryBuilder) + ; + + $queryBuilder = Repository::getEntityOrderedQueryBuilder($entityRepository); + $selectDQLPart = $queryBuilder->getDQLPart('select'); + $whereDQLPart = $queryBuilder->getDQLPart('where'); + $orderDQLPart = $queryBuilder->getDQLPart('orderBy'); + $rootAliases = $queryBuilder->getRootAliases(); + + /** @var OrderBy $orderBy */ + $orderBy = $orderDQLPart[0]; + + static::assertInstanceOf(QueryBuilder::class, $queryBuilder); + static::assertArrayHasKey(0, $rootAliases); + static::assertSame('qb', $rootAliases[0]); + static::assertSame([], $selectDQLPart); + static::assertNull($whereDQLPart); + static::assertSame(['qb.name ASC'], $orderBy->getParts()); + } + + /** + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param bool $max If is set to true, maximum value is returned. Otherwise - minimum. + * @param int $expected Extreme position (max or min) of given items + * + * @dataProvider provideArraysWithExtremePositionToGetExtremePosition + */ + public function testGetExtremePositionUsingArraysWithExtremePosition(array $items, $max, $expected) + { + static::assertSame($expected, Repository::getExtremePosition($items, $max)); + } + + /** + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param bool $max If is set to true, maximum value is returned. Otherwise - minimum. + * @param int $expected Extreme position (max or min) of given items + * + * @dataProvider provideArraysWithoutExtremePositionToGetExtremePosition + */ + public function testGetExtremePositionUsingArraysWithoutExtremePosition(array $items, $max, $expected) + { + static::assertSame($expected, Repository::getExtremePosition($items, $max)); + } + + /** + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param bool $max If is set to true, maximum value is returned. Otherwise - minimum. + * @param int $expected Extreme position (max or min) of given items + * + * @dataProvider provideObjectsWithExtremePositionToGetExtremePosition + */ + public function testGetExtremePositionUsingObjectsWithExtremePosition(array $items, $max, $expected) + { + static::assertSame($expected, Repository::getExtremePosition($items, $max)); + } + + /** + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param bool $max If is set to true, maximum value is returned. Otherwise - minimum. + * @param int $expected Extreme position (max or min) of given items + * + * @dataProvider provideObjectsWithoutExtremePositionToGetExtremePosition + */ + public function testGetExtremePositionUsingObjectsWithoutExtremePosition(array $items, $max, $expected) + { + static::assertSame($expected, Repository::getExtremePosition($items, $max)); + } + + public function testGetExtremePositionWithoutItems() + { + static::assertNull(Repository::getExtremePosition([])); + static::assertNull(Repository::getExtremePosition([], false)); + } + + /** + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param bool $asLast If is set to true, items are placed at the end (default behaviour). Otherwise - at top. + * @param array $expected Items with replenished positions + * + * @dataProvider provideArraysWithExtremePosition + */ + public function testReplenishPositionsUsingArraysWithExtremePositionForce(array $items, $asLast, array $expected) + { + Repository::replenishPositions($items, $asLast, true); + static::assertSame($expected, $items); + } + + /** + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @dataProvider provideArraysWithoutExtremePosition + */ + public function testReplenishPositionsUsingArraysWithoutExtremePosition(array $items) + { + Repository::replenishPositions($items); + static::assertSame($items, $items); + + Repository::replenishPositions($items, false); + static::assertSame($items, $items); + } + + /** + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param bool $asLast If is set to true, items are placed at the end (default behaviour). Otherwise - at top. + * @param array $expected Items with replenished positions + * + * @dataProvider provideArraysWithoutExtremePosition + */ + public function testReplenishPositionsUsingArraysWithoutExtremePositionForce(array $items, $asLast, array $expected) + { + Repository::replenishPositions($items, $asLast, true); + static::assertSame($expected, $items); } public function testReplenishPositionsUsingNotSortableObjects() @@ -72,56 +869,17 @@ class RepositoryTest extends BaseTestCase static::assertEquals($before, $after); } - /** - * @param string $description Description of test - * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays - * @param array $expected Expected items with positions replenished - * - * @dataProvider provideSortedItems - */ - public function testReplenishPositionsUsingSortedItems(string $description, array $items, array $expected) - { - Repository::replenishPositions($items); - static::assertSame($expected, $items, $description); - } - - /** - * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays - * @dataProvider provideArraysWithoutExtremePosition - */ - public function testReplenishPositionsUsingArraysWithoutExtremePosition(array $items) - { - Repository::replenishPositions($items); - static::assertSame($items, $items); - - Repository::replenishPositions($items, false); - static::assertSame($items, $items); - } - /** * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays * @param bool $asLast If is set to true, items are placed at the end (default behaviour). Otherwise - at top. * @param array $expected Items with replenished positions * - * @dataProvider provideArraysWithoutExtremePosition + * @dataProvider provideObjectsWithExtremePosition */ - public function testReplenishPositionsUsingArraysWithoutExtremePositionForce(array $items, $asLast, array $expected) + public function testReplenishPositionsUsingObjectsWithExtremePositionForce(array $items, $asLast, array $expected) { Repository::replenishPositions($items, $asLast, true); - static::assertSame($expected, $items); - } - - /** - * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays - * @param bool $asLast If is set to true, items are placed at the end (default behaviour). Otherwise - at top. - * @param array $expected Items with replenished positions - * - * @dataProvider provideArraysWithExtremePosition - */ - public function testReplenishPositionsUsingArraysWithExtremePositionForce(array $items, $asLast, array $expected) - { - Repository::replenishPositions($items, $asLast, true); - static::assertSame($expected, $items); + static::assertEquals($expected, $items); } /** @@ -151,783 +909,23 @@ class RepositoryTest extends BaseTestCase } /** - * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays - * @param bool $asLast If is set to true, items are placed at the end (default behaviour). Otherwise - at top. - * @param array $expected Items with replenished positions + * @param string $description Description of test + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param array $expected Expected items with positions replenished * - * @dataProvider provideObjectsWithExtremePosition + * @dataProvider provideSortedItems */ - public function testReplenishPositionsUsingObjectsWithExtremePositionForce(array $items, $asLast, array $expected) + public function testReplenishPositionsUsingSortedItems(string $description, array $items, array $expected) { - Repository::replenishPositions($items, $asLast, true); - static::assertEquals($expected, $items); + Repository::replenishPositions($items); + static::assertSame($expected, $items, $description); } - public function testGetExtremePositionWithoutItems() + public function testReplenishPositionsWithoutItems() { - static::assertNull(Repository::getExtremePosition([])); - static::assertNull(Repository::getExtremePosition([], false)); - } + $items = []; + Repository::replenishPositions($items); - /** - * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays - * @param bool $max If is set to true, maximum value is returned. Otherwise - minimum. - * @param int $expected Extreme position (max or min) of given items - * - * @dataProvider provideArraysWithoutExtremePositionToGetExtremePosition - */ - public function testGetExtremePositionUsingArraysWithoutExtremePosition(array $items, $max, $expected) - { - static::assertSame($expected, Repository::getExtremePosition($items, $max)); - } - - /** - * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays - * @param bool $max If is set to true, maximum value is returned. Otherwise - minimum. - * @param int $expected Extreme position (max or min) of given items - * - * @dataProvider provideArraysWithExtremePositionToGetExtremePosition - */ - public function testGetExtremePositionUsingArraysWithExtremePosition(array $items, $max, $expected) - { - static::assertSame($expected, Repository::getExtremePosition($items, $max)); - } - - /** - * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays - * @param bool $max If is set to true, maximum value is returned. Otherwise - minimum. - * @param int $expected Extreme position (max or min) of given items - * - * @dataProvider provideObjectsWithoutExtremePositionToGetExtremePosition - */ - public function testGetExtremePositionUsingObjectsWithoutExtremePosition(array $items, $max, $expected) - { - static::assertSame($expected, Repository::getExtremePosition($items, $max)); - } - - /** - * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays - * @param bool $max If is set to true, maximum value is returned. Otherwise - minimum. - * @param int $expected Extreme position (max or min) of given items - * - * @dataProvider provideObjectsWithExtremePositionToGetExtremePosition - */ - public function testGetExtremePositionUsingObjectsWithExtremePosition(array $items, $max, $expected) - { - static::assertSame($expected, Repository::getExtremePosition($items, $max)); - } - - public function testGetEntityOrderedQueryBuilderUsingDefaults() - { - $entityManager = $this->createMock(EntityManagerInterface::class); - - $entityRepository = $this - ->getMockBuilder(EntityRepository::class) - ->disableOriginalConstructor() - ->setMethods([ - 'createQueryBuilder', - ]) - ->getMock() - ; - - $expectedQueryBuilder = new QueryBuilder($entityManager); - $expectedQueryBuilder->from('any_table_name', 'qb'); - - $entityRepository - ->expects(static::once()) - ->method('createQueryBuilder') - ->willReturn($expectedQueryBuilder) - ; - - $queryBuilder = Repository::getEntityOrderedQueryBuilder($entityRepository); - $selectDQLPart = $queryBuilder->getDQLPart('select'); - $whereDQLPart = $queryBuilder->getDQLPart('where'); - $orderDQLPart = $queryBuilder->getDQLPart('orderBy'); - $rootAliases = $queryBuilder->getRootAliases(); - - /** @var OrderBy $orderBy */ - $orderBy = $orderDQLPart[0]; - - static::assertInstanceOf(QueryBuilder::class, $queryBuilder); - static::assertArrayHasKey(0, $rootAliases); - static::assertSame('qb', $rootAliases[0]); - static::assertSame([], $selectDQLPart); - static::assertNull($whereDQLPart); - static::assertSame(['qb.name ASC'], $orderBy->getParts()); - } - - /** - * @param string $property Name of property used by the ORDER BY clause - * @param string $direction Direction used by the ORDER BY clause ("ASC" or "DESC") - * @param string $expectedOrderBy Expected ORDER BY clause - * - * @dataProvider providePropertyAndDirectionToGetEntityOrderedQueryBuilder - */ - public function testGetEntityOrderedQueryBuilder($property, $direction, $expectedOrderBy) - { - $entityManager = $this->createMock(EntityManagerInterface::class); - - $entityRepository = $this - ->getMockBuilder(EntityRepository::class) - ->disableOriginalConstructor() - ->setMethods([ - 'createQueryBuilder', - ]) - ->getMock() - ; - - $expectedQueryBuilder = new QueryBuilder($entityManager); - $expectedQueryBuilder->from('any_table_name', 'qb'); - - $entityRepository - ->expects(static::once()) - ->method('createQueryBuilder') - ->willReturn($expectedQueryBuilder) - ; - - $queryBuilder = Repository::getEntityOrderedQueryBuilder($entityRepository, $property, $direction); - $selectDQLPart = $queryBuilder->getDQLPart('select'); - $whereDQLPart = $queryBuilder->getDQLPart('where'); - $orderDQLPart = $queryBuilder->getDQLPart('orderBy'); - $rootAliases = $queryBuilder->getRootAliases(); - - static::assertInstanceOf(QueryBuilder::class, $queryBuilder); - static::assertArrayHasKey(0, $rootAliases); - static::assertSame('qb', $rootAliases[0]); - static::assertSame([], $selectDQLPart); - static::assertNull($whereDQLPart); - - if (empty($property)) { - static::assertSame([], $orderDQLPart); - } else { - /** @var OrderBy $orderBy */ - $orderBy = $orderDQLPart[0]; - - static::assertSame([$expectedOrderBy], $orderBy->getParts()); - } - } - - /** - * Provides arrays without extreme position used to replenish positions of them - * - * @return Generator - */ - public function provideArraysWithoutExtremePosition() - { - yield[ - [ - [], - [], - ], - true, - [ - [ - Repository::POSITION_KEY => 1, - ], - [ - Repository::POSITION_KEY => 2, - ], - ], - ]; - - yield[ - [ - [], - [], - ], - false, - [ - [ - Repository::POSITION_KEY => -1, - ], - [ - Repository::POSITION_KEY => -2, - ], - ], - ]; - - yield[ - [ - [ - 'lorem' => 'ipsum', - 'dolor', - 'sit' => 1, - ], - [ - 'abc' => 'def', - 'ghi' => null, - 'jkl' => 10, - ], - ], - true, - [ - [ - 'lorem' => 'ipsum', - 'dolor', - 'sit' => 1, - Repository::POSITION_KEY => 1, - ], - [ - 'abc' => 'def', - 'ghi' => null, - 'jkl' => 10, - Repository::POSITION_KEY => 2, - ], - ], - ]; - - yield[ - [ - [ - 'lorem' => 'ipsum', - 'dolor', - 'sit' => 1, - ], - [ - 'abc' => 'def', - 'ghi' => null, - 'jkl' => 10, - ], - ], - false, - [ - [ - 'lorem' => 'ipsum', - 'dolor', - 'sit' => 1, - Repository::POSITION_KEY => -1, - ], - [ - 'abc' => 'def', - 'ghi' => null, - 'jkl' => 10, - Repository::POSITION_KEY => -2, - ], - ], - ]; - } - - /** - * Provides arrays with extreme position used to replenish positions of them - * - * @return Generator - */ - public function provideArraysWithExtremePosition() - { - yield[ - [ - [ - Repository::POSITION_KEY => 1, - ], - [], - [], - ], - true, - [ - [ - Repository::POSITION_KEY => 1, - ], - [ - Repository::POSITION_KEY => 2, - ], - [ - Repository::POSITION_KEY => 3, - ], - ], - ]; - - yield[ - [ - [], - [], - [ - Repository::POSITION_KEY => 1, - ], - ], - true, - [ - [ - Repository::POSITION_KEY => 2, - ], - [ - Repository::POSITION_KEY => 3, - ], - [ - Repository::POSITION_KEY => 1, - ], - ], - ]; - - yield[ - [ - [ - Repository::POSITION_KEY => 1, - ], - [], - [], - ], - false, - [ - [ - Repository::POSITION_KEY => 1, - ], - [ - Repository::POSITION_KEY => 0, - ], - [ - Repository::POSITION_KEY => -1, - ], - ], - ]; - - yield[ - [ - [], - [], - [ - Repository::POSITION_KEY => 1, - ], - ], - false, - [ - [ - Repository::POSITION_KEY => 0, - ], - [ - Repository::POSITION_KEY => -1, - ], - [ - Repository::POSITION_KEY => 1, - ], - ], - ]; - } - - /** - * Provides objects without extreme position used to replenish positions of them - * - * @return Generator - */ - public function provideObjectsWithoutExtremePosition() - { - yield[ - [ - new Sortable(), - new Sortable(), - new Sortable(), - ], - true, - [ - new Sortable(1), - new Sortable(2), - new Sortable(3), - ], - ]; - - yield[ - [ - new Sortable(), - new Sortable(), - new Sortable(), - ], - false, - [ - new Sortable(-1), - new Sortable(-2), - new Sortable(-3), - ], - ]; - } - - /** - * Provides objects with extreme position used to replenish positions of them - * - * @return Generator - */ - public function provideObjectsWithExtremePosition() - { - yield[ - [ - new Sortable(1), - new Sortable(), - new Sortable(), - ], - true, - [ - new Sortable(1), - new Sortable(2), - new Sortable(3), - ], - ]; - - yield[ - [ - new Sortable(), - new Sortable(1), - new Sortable(), - ], - true, - [ - new Sortable(2), - new Sortable(1), - new Sortable(3), - ], - ]; - - yield[ - [ - new Sortable(1), - new Sortable(), - new Sortable(), - ], - false, - [ - new Sortable(1), - new Sortable(0), - new Sortable(-1), - ], - ]; - } - - /** - * Provides arrays without extreme position used to get extreme position - * - * @return Generator - */ - public function provideArraysWithoutExtremePositionToGetExtremePosition() - { - yield[ - [], - false, - null, - ]; - - yield[ - [], - true, - null, - ]; - - yield[ - [ - [ - 'lorem' => 'ipsum', - 'dolor', - 'sit' => 1, - ], - [ - 'abc' => 'def', - 'ghi' => null, - 'jkl' => 10, - ], - ], - true, - null, - ]; - - yield[ - [ - [ - 'lorem' => 'ipsum', - 'dolor', - 'sit' => 1, - ], - [ - 'abc' => 'def', - 'ghi' => null, - 'jkl' => 10, - ], - ], - false, - null, - ]; - } - - /** - * Provides arrays with extreme position used to get extreme position - * - * @return Generator - */ - public function provideArraysWithExtremePositionToGetExtremePosition() - { - yield[ - [ - [ - Repository::POSITION_KEY => 1, - ], - [], - [], - ], - true, - 1, - ]; - - yield[ - [ - [ - Repository::POSITION_KEY => 1, - ], - [], - [], - ], - false, - 1, - ]; - - yield[ - [ - [], - [], - [ - Repository::POSITION_KEY => 1, - ], - ], - true, - 1, - ]; - - yield[ - [ - [], - [], - [ - Repository::POSITION_KEY => 1, - ], - ], - false, - 1, - ]; - - yield[ - [ - [ - Repository::POSITION_KEY => 1, - ], - [], - [ - Repository::POSITION_KEY => 2, - ], - [], - ], - true, - 2, - ]; - - yield[ - [ - [ - Repository::POSITION_KEY => 1, - ], - [], - [ - Repository::POSITION_KEY => 2, - ], - [], - ], - false, - 1, - ]; - } - - /** - * Provides objects without extreme position used to get extreme position - * - * @return Generator - */ - public function provideObjectsWithoutExtremePositionToGetExtremePosition() - { - yield[ - [], - false, - null, - ]; - - yield[ - [], - true, - null, - ]; - - yield[ - [ - new Sortable(), - new Sortable(), - new Sortable(), - ], - true, - null, - ]; - - yield[ - [ - new Sortable(), - new Sortable(), - new Sortable(), - ], - false, - null, - ]; - } - - /** - * Provides objects with extreme position used to get extreme position - * - * @return Generator - */ - public function provideObjectsWithExtremePositionToGetExtremePosition() - { - yield[ - [ - new Sortable(1), - new Sortable(2), - new Sortable(3), - ], - true, - 3, - ]; - - yield[ - [ - new Sortable(1), - new Sortable(2), - new Sortable(3), - ], - false, - 1, - ]; - } - - /** - * Provide name of property, direction and expected ORDER BY clause used to get query builder - * - * @return Generator - */ - public function providePropertyAndDirectionToGetEntityOrderedQueryBuilder() - { - yield[ - null, - null, - '', - ]; - - yield[ - '', - '', - '', - ]; - - yield[ - 'first_name', - '', - 'qb.first_name ASC', - ]; - - yield[ - 'first_name', - 'asc', - 'qb.first_name asc', - ]; - - yield[ - 'first_name', - 'ASC', - 'qb.first_name ASC', - ]; - - yield[ - 'first_name', - 'desc', - 'qb.first_name desc', - ]; - - yield[ - 'first_name', - 'DESC', - 'qb.first_name DESC', - ]; - } - - public function provideSortedItems() - { - $sortable1 = new Sortable(); - $sortable1->setPosition(1); - - $sortable2 = new Sortable(); - $sortable2->setPosition(2); - - $sortable3 = new Sortable(); - $sortable3->setPosition(309); - - yield[ - 'An array with 1 item only', - [ - [ - 'test 1', - 'position' => 1, - ], - ], - [ - [ - 'test 1', - 'position' => 1, - ], - ], - ]; - - yield[ - 'An array with more than 1 item', - [ - [ - 'test 1', - 'position' => 1, - ], - [ - 'test 2', - 'position' => 2, - ], - [ - 'test 3', - 'position' => 309, - ], - ], - [ - [ - 'test 1', - 'position' => 1, - ], - [ - 'test 2', - 'position' => 2, - ], - [ - 'test 3', - 'position' => 309, - ], - ], - ]; - - yield[ - '1 object only', - [ - $sortable1, - ], - [ - $sortable1, - ], - ]; - - yield[ - 'More than 1 object', - [ - $sortable1, - $sortable2, - $sortable3, - ], - [ - $sortable1, - $sortable2, - $sortable3, - ], - ]; + static::assertSame([], $items); } } diff --git a/tests/Utilities/UriTest.php b/tests/Utilities/UriTest.php index 3739abb..da660ff 100644 --- a/tests/Utilities/UriTest.php +++ b/tests/Utilities/UriTest.php @@ -23,9 +23,174 @@ use Meritoo\Common\Utilities\Uri; */ class UriTest extends BaseTestCase { - public function testConstructor() + /** + * Provides data used to build secured url + * + * @return Generator + */ + public function provideDataForSecuredUrl() { - static::assertHasNoConstructor(Uri::class); + yield [ + '', + '', + '', + '', + ]; + + yield [ + '/', + '', + '', + 'http://lorem.com/', + ]; + + yield [ + 'contact', + '', + '', + 'http://lorem.com/contact', + ]; + + yield [ + 'contact', + 'john', + '', + 'http://lorem.com/contact', + ]; + + yield [ + 'contact', + '', + 'pass123', + 'http://lorem.com/contact', + ]; + + yield [ + 'contact', + 'john', + 'pass123', + 'http://john:pass123@lorem.com/contact', + ]; + } + + public function provideRootUrlAndUrlParts(): ?Generator + { + yield [ + '', + '', + ]; + + yield [ + '', + '', + '', + ]; + + yield [ + 'http://my.example', + 'http://my.example', + '', + ]; + + yield [ + 'http://my.example', + 'http://my.example', + '', + '', + ]; + + yield [ + 'http://my.example//test/12/test/', + 'http://my.example', + '', + 'test', + '12/test', + '', + ]; + + yield [ + 'http://my.example//test/12/test', + 'http://my.example', + '', + 'test/', + '12/test/', + ]; + + yield [ + 'http://my.example/test/12/test/', + 'http://my.example', + '/test/', + '/12/test', + '', + ]; + } + + /** + * Provides url to replenish protocol + * + * @return Generator + */ + public function provideUrlToReplenishProtocol() + { + yield [ + 'http://test', + 'test', + '', + ]; + + yield [ + 'ftp://lorem.ipsum', + 'lorem.ipsum', + 'ftp', + ]; + } + + /** + * Provides url used to verify if it's external, from another server / domain + * + * @return Generator + */ + public function provideUrlToVerifyIfIsExternal() + { + yield [ + '', + false, + ]; + + yield [ + '/', + false, + ]; + + yield [ + 'http://something.different/first-page', + true, + ]; + + yield [ + 'something.different/first-page', + true, + ]; + + yield [ + 'http://lorem.com', + false, + ]; + + yield [ + 'http://lorem.com/contact', + false, + ]; + + yield [ + 'lorem.com', + false, + ]; + + yield [ + 'lorem.com/contact', + false, + ]; } public function testAddProtocolToUrl() @@ -45,61 +210,20 @@ class UriTest extends BaseTestCase } /** - * @param mixed $url Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testReplenishProtocolEmptyUrl($url) - { - self::assertEquals('', Uri::replenishProtocol($url)); - } - - /** - * @param string $expected Expected result - * @param string $url The url to check and replenish - * @param string $protocol (optional) The protocol which is replenished. If is empty, protocol of current request - * is used. + * @param string $expected + * @param string $rootUrl + * @param string ...$urlParts * - * @dataProvider provideUrlToReplenishProtocol + * @dataProvider provideRootUrlAndUrlParts */ - public function testReplenishProtocol($expected, $url, $protocol = '') + public function testBuildUrl(string $expected, string $rootUrl, string ...$urlParts): void { - /* - * Required to get protocol when it's not provided and to void test failure: - * - * Failed asserting that two strings are identical. - * Expected :'://test' - * Actual :'http://test' - */ - $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; - - self::assertSame($expected, Uri::replenishProtocol($url, $protocol)); + static::assertSame($expected, Uri::buildUrl($rootUrl, ...$urlParts)); } - public function testGetServerNameOrIpWithoutProtocol() + public function testConstructor() { - $_SERVER['HTTP_HOST'] = ''; - self::assertEquals('', Uri::getServerNameOrIp()); - - $host = 'lorem.com'; - $_SERVER['HTTP_HOST'] = $host; - - self::assertEquals($host, Uri::getServerNameOrIp()); - } - - public function testGetServerNameOrIpWithProtocol() - { - $_SERVER['HTTP_HOST'] = ''; - $_SERVER['SERVER_PROTOCOL'] = ''; - - self::assertEquals('', Uri::getServerNameOrIp(true)); - - $host = 'lorem.com'; - $protocol = 'HTTP/1.1'; - - $_SERVER['HTTP_HOST'] = $host; - $_SERVER['SERVER_PROTOCOL'] = $protocol; - - self::assertEquals(sprintf('http://%s', $host), Uri::getServerNameOrIp(true)); + static::assertHasNoConstructor(Uri::class); } public function testGetFullUriWithHost() @@ -157,6 +281,49 @@ class UriTest extends BaseTestCase self::assertEquals($refererUrl, Uri::getRefererUri()); } + /** + * @param string $url A path / url to some resource, e.g. page, image, css file + * @param string $user User name used to log in + * @param string $password User password used to log in + * @param string $expectedUrl Expected, secured url + * + * @dataProvider provideDataForSecuredUrl + */ + public function testGetSecuredUrl($url, $user, $password, $expectedUrl) + { + $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; + $_SERVER['HTTP_HOST'] = 'lorem.com'; + + self::assertEquals($expectedUrl, Uri::getSecuredUrl($url, $user, $password)); + } + + public function testGetServerNameOrIpWithProtocol() + { + $_SERVER['HTTP_HOST'] = ''; + $_SERVER['SERVER_PROTOCOL'] = ''; + + self::assertEquals('', Uri::getServerNameOrIp(true)); + + $host = 'lorem.com'; + $protocol = 'HTTP/1.1'; + + $_SERVER['HTTP_HOST'] = $host; + $_SERVER['SERVER_PROTOCOL'] = $protocol; + + self::assertEquals(sprintf('http://%s', $host), Uri::getServerNameOrIp(true)); + } + + public function testGetServerNameOrIpWithoutProtocol() + { + $_SERVER['HTTP_HOST'] = ''; + self::assertEquals('', Uri::getServerNameOrIp()); + + $host = 'lorem.com'; + $_SERVER['HTTP_HOST'] = $host; + + self::assertEquals($host, Uri::getServerNameOrIp()); + } + public function testGetUserAddressIp() { $_SERVER['REMOTE_ADDR'] = ''; @@ -168,58 +335,49 @@ class UriTest extends BaseTestCase self::assertEquals($userAddressIp, Uri::getUserAddressIp()); } + public function testGetUserOperatingSystemName() + { + $_SERVER['HTTP_USER_AGENT'] = ''; + self::assertEquals('', Uri::getUserOperatingSystemName()); + + $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like' + .' Gecko) Version/8.0.2 Safari/600.2.5'; + + self::assertEquals('Mac OS', Uri::getUserOperatingSystemName()); + } + public function testGetUserWebBrowserInfo() { $_SERVER['HTTP_USER_AGENT'] = ''; self::assertEquals('', Uri::getUserWebBrowserInfo()); $browserInfo = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko)' - . ' Version/8.0.2 Safari/600.2.5'; + .' Version/8.0.2 Safari/600.2.5'; $_SERVER['HTTP_USER_AGENT'] = $browserInfo; self::assertEquals($browserInfo, Uri::getUserWebBrowserInfo()); } - public function testGetUserWebBrowserNameWithoutVersion() - { - $_SERVER['HTTP_USER_AGENT'] = ''; - self::assertEquals('', Uri::getUserWebBrowserName()); - - $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like' - . ' Gecko) Version/8.0.2 Safari/600.2.5'; - - self::assertEquals('Apple Safari', Uri::getUserWebBrowserName()); - } - public function testGetUserWebBrowserNameWithVersion() { $_SERVER['HTTP_USER_AGENT'] = ''; self::assertEquals('', Uri::getUserWebBrowserName(true)); $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like' - . ' Gecko) Version/8.0.2 Safari/600.2.5'; + .' Gecko) Version/8.0.2 Safari/600.2.5'; self::assertEquals('Apple Safari 600.2.5', Uri::getUserWebBrowserName(true)); } - public function testGetUserOperatingSystemName() + public function testGetUserWebBrowserNameWithoutVersion() { $_SERVER['HTTP_USER_AGENT'] = ''; - self::assertEquals('', Uri::getUserOperatingSystemName()); + self::assertEquals('', Uri::getUserWebBrowserName()); $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like' - . ' Gecko) Version/8.0.2 Safari/600.2.5'; + .' Gecko) Version/8.0.2 Safari/600.2.5'; - self::assertEquals('Mac OS', Uri::getUserOperatingSystemName()); - } - - public function testIsServerLocalhost() - { - $_SERVER['HTTP_HOST'] = ''; - self::assertFalse(Uri::isServerLocalhost()); - - $_SERVER['HTTP_HOST'] = '127.0.0.1'; - self::assertTrue(Uri::isServerLocalhost()); + self::assertEquals('Apple Safari', Uri::getUserWebBrowserName()); } /** @@ -239,201 +397,43 @@ class UriTest extends BaseTestCase self::assertEquals($expected, Uri::isExternalUrl($url)); } - /** - * @param string $url A path / url to some resource, e.g. page, image, css file - * @param string $user User name used to log in - * @param string $password User password used to log in - * @param string $expectedUrl Expected, secured url - * - * @dataProvider provideDataForSecuredUrl - */ - public function testGetSecuredUrl($url, $user, $password, $expectedUrl) + public function testIsServerLocalhost() { + $_SERVER['HTTP_HOST'] = ''; + self::assertFalse(Uri::isServerLocalhost()); + + $_SERVER['HTTP_HOST'] = '127.0.0.1'; + self::assertTrue(Uri::isServerLocalhost()); + } + + /** + * @param string $expected Expected result + * @param string $url The url to check and replenish + * @param string $protocol (optional) The protocol which is replenished. If is empty, protocol of current request + * is used. + * + * @dataProvider provideUrlToReplenishProtocol + */ + public function testReplenishProtocol($expected, $url, $protocol = '') + { + /* + * Required to get protocol when it's not provided and to void test failure: + * + * Failed asserting that two strings are identical. + * Expected :'://test' + * Actual :'http://test' + */ $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; - $_SERVER['HTTP_HOST'] = 'lorem.com'; - self::assertEquals($expectedUrl, Uri::getSecuredUrl($url, $user, $password)); + self::assertSame($expected, Uri::replenishProtocol($url, $protocol)); } /** - * @param string $expected - * @param string $rootUrl - * @param string ...$urlParts - * - * @dataProvider provideRootUrlAndUrlParts + * @param mixed $url Empty value, e.g. "" + * @dataProvider provideEmptyValue */ - public function testBuildUrl(string $expected, string $rootUrl, string ...$urlParts): void + public function testReplenishProtocolEmptyUrl($url) { - static::assertSame($expected, Uri::buildUrl($rootUrl, ...$urlParts)); - } - - /** - * Provides url to replenish protocol - * - * @return Generator - */ - public function provideUrlToReplenishProtocol() - { - yield[ - 'http://test', - 'test', - '', - ]; - - yield[ - 'ftp://lorem.ipsum', - 'lorem.ipsum', - 'ftp', - ]; - } - - /** - * Provides url used to verify if it's external, from another server / domain - * - * @return Generator - */ - public function provideUrlToVerifyIfIsExternal() - { - yield[ - '', - false, - ]; - - yield[ - '/', - false, - ]; - - yield[ - 'http://something.different/first-page', - true, - ]; - - yield[ - 'something.different/first-page', - true, - ]; - - yield[ - 'http://lorem.com', - false, - ]; - - yield[ - 'http://lorem.com/contact', - false, - ]; - - yield[ - 'lorem.com', - false, - ]; - - yield[ - 'lorem.com/contact', - false, - ]; - } - - /** - * Provides data used to build secured url - * - * @return Generator - */ - public function provideDataForSecuredUrl() - { - yield[ - '', - '', - '', - '', - ]; - - yield[ - '/', - '', - '', - 'http://lorem.com/', - ]; - - yield[ - 'contact', - '', - '', - 'http://lorem.com/contact', - ]; - - yield[ - 'contact', - 'john', - '', - 'http://lorem.com/contact', - ]; - - yield[ - 'contact', - '', - 'pass123', - 'http://lorem.com/contact', - ]; - - yield[ - 'contact', - 'john', - 'pass123', - 'http://john:pass123@lorem.com/contact', - ]; - } - - public function provideRootUrlAndUrlParts(): ?Generator - { - yield[ - '', - '', - ]; - - yield[ - '', - '', - '', - ]; - - yield[ - 'http://my.example', - 'http://my.example', - '', - ]; - - yield[ - 'http://my.example', - 'http://my.example', - '', - '', - ]; - - yield[ - 'http://my.example//test/12/test/', - 'http://my.example', - '', - 'test', - '12/test', - '', - ]; - - yield[ - 'http://my.example//test/12/test', - 'http://my.example', - '', - 'test/', - '12/test/', - ]; - - yield[ - 'http://my.example/test/12/test/', - 'http://my.example', - '/test/', - '/12/test', - '', - ]; + self::assertEquals('', Uri::replenishProtocol($url)); } } diff --git a/tests/Utilities/XmlTest.php b/tests/Utilities/XmlTest.php index 90bd348..1683bc1 100644 --- a/tests/Utilities/XmlTest.php +++ b/tests/Utilities/XmlTest.php @@ -19,7 +19,7 @@ use SimpleXMLElement; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\Utilities\Xml + * @covers \Meritoo\Common\Utilities\Xml */ class XmlTest extends BaseTestCase { @@ -38,14 +38,14 @@ class XmlTest extends BaseTestCase $element2 = new SimpleXMLElement(''); $merged = Xml::mergeNodes($element1, $element2); - self::assertEquals('', (string)$merged); + self::assertEquals('', (string) $merged); // XMLs with data $element1 = new SimpleXMLElement($this->simpleXml); $element2 = new SimpleXMLElement($this->advancedXml); $merged = Xml::mergeNodes($element1, $element2); - self::assertEquals('John', (string)$merged->author[0]->first_name); + self::assertEquals('John', (string) $merged->author[0]->first_name); } /** diff --git a/tests/ValueObject/AddressTest.php b/tests/ValueObject/AddressTest.php index acee74c..63981e7 100644 --- a/tests/ValueObject/AddressTest.php +++ b/tests/ValueObject/AddressTest.php @@ -19,7 +19,7 @@ use Meritoo\Common\ValueObject\Address; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\ValueObject\Address + * @covers \Meritoo\Common\ValueObject\Address */ class AddressTest extends BaseTestCase { @@ -48,13 +48,6 @@ class AddressTest extends BaseTestCase ); } - public function testGetFlatNumber() - { - static::assertSame('200', $this->address->getFlatNumber()); - static::assertSame('', $this->addressWithoutFlat->getFlatNumber()); - static::assertSame('300', $this->addressWithoutStreet->getFlatNumber()); - } - public function testGetBuildingNumber() { static::assertSame('10', $this->address->getBuildingNumber()); @@ -62,11 +55,18 @@ class AddressTest extends BaseTestCase static::assertSame('1', $this->addressWithoutStreet->getBuildingNumber()); } - public function testGetStreet() + public function testGetCity() { - static::assertSame('4th Avenue', $this->address->getStreet()); - static::assertSame('Green Street', $this->addressWithoutFlat->getStreet()); - static::assertSame('', $this->addressWithoutStreet->getStreet()); + static::assertSame('New York', $this->address->getCity()); + static::assertSame('San Francisco', $this->addressWithoutFlat->getCity()); + static::assertSame('Saint Louis', $this->addressWithoutStreet->getCity()); + } + + public function testGetFlatNumber() + { + static::assertSame('200', $this->address->getFlatNumber()); + static::assertSame('', $this->addressWithoutFlat->getFlatNumber()); + static::assertSame('300', $this->addressWithoutStreet->getFlatNumber()); } public function testGetFullStreet() @@ -76,11 +76,11 @@ class AddressTest extends BaseTestCase static::assertSame('', $this->addressWithoutStreet->getFullStreet()); } - public function testGetCity() + public function testGetStreet() { - static::assertSame('New York', $this->address->getCity()); - static::assertSame('San Francisco', $this->addressWithoutFlat->getCity()); - static::assertSame('Saint Louis', $this->addressWithoutStreet->getCity()); + static::assertSame('4th Avenue', $this->address->getStreet()); + static::assertSame('Green Street', $this->addressWithoutFlat->getStreet()); + static::assertSame('', $this->addressWithoutStreet->getStreet()); } public function testGetZipCode() @@ -92,9 +92,9 @@ class AddressTest extends BaseTestCase public function testToString() { - static::assertSame('4th Avenue 10/200, 00123, New York', (string)$this->address); - static::assertSame('Green Street 22, 00456, San Francisco', (string)$this->addressWithoutFlat); - static::assertSame('00111, Saint Louis', (string)$this->addressWithoutStreet); + static::assertSame('4th Avenue 10/200, 00123, New York', (string) $this->address); + static::assertSame('Green Street 22, 00456, San Francisco', (string) $this->addressWithoutFlat); + static::assertSame('00111, Saint Louis', (string) $this->addressWithoutStreet); } protected function setUp(): void diff --git a/tests/ValueObject/BankAccountTest.php b/tests/ValueObject/BankAccountTest.php index 436d3e0..52277be 100644 --- a/tests/ValueObject/BankAccountTest.php +++ b/tests/ValueObject/BankAccountTest.php @@ -19,7 +19,7 @@ use Meritoo\Common\ValueObject\BankAccount; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\ValueObject\BankAccount + * @covers \Meritoo\Common\ValueObject\BankAccount */ class BankAccountTest extends BaseTestCase { @@ -57,8 +57,8 @@ class BankAccountTest extends BaseTestCase public function testToString() { - static::assertSame('', (string)$this->emptyBankAccount); - static::assertSame('Bank of America, 1234567890', (string)$this->bankAccount); + static::assertSame('', (string) $this->emptyBankAccount); + static::assertSame('Bank of America, 1234567890', (string) $this->bankAccount); } /** diff --git a/tests/ValueObject/CompanyTest.php b/tests/ValueObject/CompanyTest.php index b63dac0..dcd66c7 100644 --- a/tests/ValueObject/CompanyTest.php +++ b/tests/ValueObject/CompanyTest.php @@ -21,7 +21,7 @@ use Meritoo\Common\ValueObject\Company; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\ValueObject\Company + * @covers \Meritoo\Common\ValueObject\Company */ class CompanyTest extends BaseTestCase { @@ -45,12 +45,6 @@ class CompanyTest extends BaseTestCase ); } - public function testGetName() - { - static::assertSame('Test 1', $this->company->getName()); - static::assertSame('Test 2', $this->companyWithoutBankAccount->getName()); - } - public function testGetAddress() { static::assertEquals( @@ -74,10 +68,16 @@ class CompanyTest extends BaseTestCase static::assertNull($this->companyWithoutBankAccount->getBankAccount()); } + public function testGetName() + { + static::assertSame('Test 1', $this->company->getName()); + static::assertSame('Test 2', $this->companyWithoutBankAccount->getName()); + } + public function testToString() { - static::assertSame('Test 1, 4th Avenue 10/200, 00123, New York, Bank 1, 12345', (string)$this->company); - static::assertSame('Test 2, Green Street 22, 00456, San Francisco', (string)$this->companyWithoutBankAccount); + static::assertSame('Test 1, 4th Avenue 10/200, 00123, New York, Bank 1, 12345', (string) $this->company); + static::assertSame('Test 2, Green Street 22, 00456, San Francisco', (string) $this->companyWithoutBankAccount); } /** diff --git a/tests/ValueObject/HumanTest.php b/tests/ValueObject/HumanTest.php index c5ddbee..63e39d3 100644 --- a/tests/ValueObject/HumanTest.php +++ b/tests/ValueObject/HumanTest.php @@ -8,6 +8,7 @@ namespace Meritoo\Test\Common\ValueObject; +use DateTime; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; use Meritoo\Common\ValueObject\Human; @@ -19,10 +20,37 @@ use Meritoo\Common\ValueObject\Human; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\ValueObject\Human + * @covers \Meritoo\Common\ValueObject\Human */ class HumanTest extends BaseTestCase { + public function provideHuman() + { + yield [ + 'Without any data (an empty human)', + new Human('', ''), + '', + ]; + + yield [ + 'With first and last name only', + new Human('John', 'Scott'), + 'John Scott', + ]; + + yield [ + 'With first name, last name and email', + new Human('John', 'Scott', 'john@scott.com'), + 'John Scott ', + ]; + + yield [ + 'With whole/complete data', + new Human('John', 'Scott', 'john@scott.com', new DateTime('2001-01-01')), + 'John Scott ', + ]; + } + public function testConstructor() { static::assertConstructorVisibilityAndArguments( @@ -33,52 +61,13 @@ class HumanTest extends BaseTestCase ); } - /** - * @param string $description Description of test - * @param Human $human Human to verify - * @param string $expected Expected string - * - * @dataProvider provideHuman - */ - public function testToString($description, Human $human, $expected) - { - static::assertSame($expected, (string)$human, $description); - } - - public function testGetFirstName() - { - $empty = new Human('', ''); - static::assertSame('', $empty->getFirstName()); - - $human = new Human('John', 'Scott'); - static::assertSame('John', $human->getFirstName()); - } - - public function testGetLastName() - { - $empty = new Human('', ''); - static::assertSame('', $empty->getLastName()); - - $human = new Human('John', 'Scott'); - static::assertSame('Scott', $human->getLastName()); - } - public function testGetBirthDate() { $empty = new Human('', ''); static::assertNull($empty->getBirthDate()); - $human = new Human('John', 'Scott', '', new \DateTime('2001-01-01')); - static::assertEquals(new \DateTime('2001-01-01'), $human->getBirthDate()); - } - - public function testGetFullName() - { - $empty = new Human('', ''); - static::assertSame('', $empty->getFullName()); - - $human = new Human('John', 'Scott', '', new \DateTime('2001-01-01')); - static::assertSame('John Scott', $human->getFullName()); + $human = new Human('John', 'Scott', '', new DateTime('2001-01-01')); + static::assertEquals(new DateTime('2001-01-01'), $human->getBirthDate()); } public function testGetEmail() @@ -90,30 +79,42 @@ class HumanTest extends BaseTestCase static::assertSame('john@scott.com', $human->getEmail()); } - public function provideHuman() + public function testGetFirstName() { - yield[ - 'Without any data (an empty human)', - new Human('', ''), - '', - ]; + $empty = new Human('', ''); + static::assertSame('', $empty->getFirstName()); - yield[ - 'With first and last name only', - new Human('John', 'Scott'), - 'John Scott', - ]; + $human = new Human('John', 'Scott'); + static::assertSame('John', $human->getFirstName()); + } - yield[ - 'With first name, last name and email', - new Human('John', 'Scott', 'john@scott.com'), - 'John Scott ', - ]; + public function testGetFullName() + { + $empty = new Human('', ''); + static::assertSame('', $empty->getFullName()); - yield[ - 'With whole/complete data', - new Human('John', 'Scott', 'john@scott.com', new \DateTime('2001-01-01')), - 'John Scott ', - ]; + $human = new Human('John', 'Scott', '', new DateTime('2001-01-01')); + static::assertSame('John Scott', $human->getFullName()); + } + + public function testGetLastName() + { + $empty = new Human('', ''); + static::assertSame('', $empty->getLastName()); + + $human = new Human('John', 'Scott'); + static::assertSame('Scott', $human->getLastName()); + } + + /** + * @param string $description Description of test + * @param Human $human Human to verify + * @param string $expected Expected string + * + * @dataProvider provideHuman + */ + public function testToString($description, Human $human, $expected) + { + static::assertSame($expected, (string) $human, $description); } } diff --git a/tests/ValueObject/SizeTest.php b/tests/ValueObject/SizeTest.php index 0a75b30..37044f2 100644 --- a/tests/ValueObject/SizeTest.php +++ b/tests/ValueObject/SizeTest.php @@ -8,6 +8,7 @@ namespace Meritoo\Test\Common\ValueObject; +use Generator; use Meritoo\Common\Exception\ValueObject\InvalidSizeDimensionsException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; @@ -20,10 +21,918 @@ use Meritoo\Common\ValueObject\Size; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\ValueObject\Size + * @covers \Meritoo\Common\ValueObject\Size */ class SizeTest extends BaseTestCase { + /** + * Provides invalid size (as an array) + * + * @return Generator + */ + public function provideInvalidSizeAsArray() + { + yield [ + [ + 10, + -1, + ], + ]; + + yield [ + [ + -1, + 10, + ], + ]; + + yield [ + [ + -1, + -1, + ], + ]; + } + + public function provideSizeForConvertingToString() + { + yield [ + 'Created using an empty array', + Size::fromArray([]), + '', + ]; + + yield [ + 'Created using an empty string', + Size::fromString(''), + '', + ]; + + yield [ + 'Created using an array with integers', + Size::fromArray([ + 200, + 100, + ]), + '200 x 100', + ]; + + yield [ + 'Created using an array with strings', + Size::fromArray([ + '200', + '100', + ]), + '200 x 100', + ]; + + yield [ + 'Created using simple string', + Size::fromString('200x100', '', 'x'), + '200x100', + ]; + + yield [ + 'Created using string with too much spaces everywhere', + Size::fromString(' 200 x 100 '), + '200 x 100', + ]; + } + + public function provideSizeForFromArray() + { + yield [ + 'An empty array', + [], + '', + null, + ]; + + yield [ + 'One number only', + [ + 200, + ], + '', + null, + ]; + + yield [ + 'One number only as string', + [ + '200', + ], + '', + null, + ]; + + yield [ + '0 as dimensions', + [ + 0, + 0, + ], + 'px', + Size::fromString('0 x 0'), + ]; + + yield [ + 'Simple, valid size', + [ + 200, + 100, + ], + 'px', + Size::fromString('200 x 100'), + ]; + + yield [ + 'Simple, valid size (using strings)', + [ + '200', + '100', + ], + 'mm', + Size::fromString('200 x 100', 'mm'), + ]; + } + + public function provideSizeForFromString() + { + yield [ + 'One number only', + 200, + '', + ' x ', + null, + ]; + + yield [ + 'One number only as string', + '200', + '', + ' x ', + null, + ]; + + yield [ + 'The " " as invalid separator', + '200 100', + '', + ' x ', + null, + ]; + + yield [ + 'The "|" as separator (invalid separator)', + '200 | 100', + '', + ' x ', + null, + ]; + + yield [ + 'The "|" as invalid separator and no spaces around separator', + '200|100', + '', + ' x ', + null, + ]; + + yield [ + 'The "X" as invalid separator', + '200 X 100', + '', + ' x ', + null, + ]; + + yield [ + 'Simple, valid size', + '200 x 100', + 'px', + ' x ', + Size::fromArray([ + 200, + 100, + ]), + ]; + + yield [ + 'Simple, valid size using custom separator', + '200 X 100', + 'px', + ' X ', + Size::fromArray([ + 200, + 100, + ])->setSeparator(' X '), + ]; + + yield [ + 'Too much spaces at the right of separator', + '200 x 100', + 'px', + ' x ', + Size::fromArray([ + 200, + 100, + ]), + ]; + + yield [ + 'Too much spaces at the left of separator', + '200 x 100', + 'px', + ' x ', + Size::fromArray([ + 200, + 100, + ]), + ]; + + yield [ + 'Too much spaces around separator', + '200 x 100', + 'px', + ' x ', + Size::fromArray([ + 200, + 100, + ]), + ]; + + yield [ + 'Too much spaces before width (1st)', + ' 200 x 100', + 'px', + ' x ', + Size::fromArray([ + 200, + 100, + ]), + ]; + + yield [ + 'Too much spaces before width (2nd) and custom separator', + ' 200 X 100', + 'px', + ' X ', + Size::fromArray([ + 200, + 100, + ])->setSeparator(' X '), + ]; + + yield [ + 'Too much spaces after height (1st)', + '200 x 100 ', + 'px', + ' x ', + Size::fromArray([ + 200, + 100, + ]), + ]; + + yield [ + 'Too much spaces after height (2nd) and custom separator', + '200 X 100 ', + 'px', + ' X ', + Size::fromArray([ + 200, + 100, + ])->setSeparator(' X '), + ]; + + yield [ + 'Too much spaces before width and after height (1st)', + ' 200 x 100 ', + 'km', + ' x ', + Size::fromArray( + [ + 200, + 100, + ], + 'km' + ), + ]; + + yield [ + 'Too much spaces before width and after height (2nd) and custom separator', + ' 200 X 100 ', + 'px', + ' X ', + Size::fromArray([ + 200, + 100, + ])->setSeparator(' X '), + ]; + + yield [ + 'Too much spaces everywhere (1st)', + ' 200 x 100 ', + 'px', + ' x ', + Size::fromArray([ + 200, + 100, + ]), + ]; + + yield [ + 'Too much spaces everywhere (2nd) and custom separator', + ' 200 X 100 ', + 'px', + ' X ', + Size::fromArray([ + 200, + 100, + ])->setSeparator(' X '), + ]; + + yield [ + 'Too much spaces everywhere (3rd)', + ' 200 x 100 ', + 'px', + ' x ', + Size::fromArray([ + 200, + 100, + ]), + ]; + + yield [ + 'Too much spaces everywhere (4th) and custom separator', + ' 200 : 100 ', + 'px', + ' : ', + Size::fromArray([ + 200, + 100, + ])->setSeparator(' : '), + ]; + + yield [ + 'Too much spaces everywhere (5th)', + ' 200 x 100 ', + 'mm', + ' x ', + Size::fromArray( + [ + 200, + 100, + ], + 'mm' + ), + ]; + } + + public function provideSizeForToArray() + { + yield [ + 'Created using an array with integers', + Size::fromArray([ + 200, + 100, + ]), + false, + [ + 200, + 100, + ], + ]; + + yield [ + 'Created using an array with integers (converting with unit)', + Size::fromArray([ + 200, + 100, + ]), + true, + [ + '200 px', + '100 px', + ], + ]; + + yield [ + 'Created using an array with strings', + Size::fromArray([ + '200', + '100', + ]), + false, + [ + 200, + 100, + ], + ]; + + yield [ + 'Created using an array with strings (converting with unit)', + Size::fromArray([ + '200', + '100', + ]), + true, + [ + '200 px', + '100 px', + ], + ]; + + yield [ + 'Created using simple string', + Size::fromString('200 x 100'), + false, + [ + 200, + 100, + ], + ]; + + yield [ + 'Created using simple string and custom separator', + Size::fromString('200 X 100', '', ' X '), + false, + [ + 200, + 100, + ], + ]; + + yield [ + 'Created using simple string, custom separator and custom unit (with unit)', + Size::fromString('200 : 100', 'mm', ' : '), + true, + [ + '200 mm', + '100 mm', + ], + ]; + + yield [ + 'Created using simple string (converting with unit)', + Size::fromString('200 x 100'), + true, + [ + '200 px', + '100 px', + ], + ]; + + yield [ + 'Created using string with too much spaces everywhere', + Size::fromString(' 200 x 100 '), + false, + [ + 200, + 100, + ], + ]; + + yield [ + 'Created using string with too much spaces everywhere (converting with unit)', + Size::fromString(' 200 x 100 '), + true, + [ + '200 px', + '100 px', + ], + ]; + } + + public function provideSizeForToString() + { + yield [ + 'With unknown dimensions', + Size::fromArray([ + null, + null, + ]), + false, + '0 x 0', + ]; + + yield [ + 'With unknown dimensions (converting with unit)', + Size::fromArray([ + null, + null, + ]), + true, + '0 px x 0 px', + ]; + + yield [ + 'Created using an array with integers', + Size::fromArray([ + 200, + 100, + ]), + false, + '200 x 100', + ]; + + yield [ + 'Created using an array with integers (converting with unit)', + Size::fromArray([ + 200, + 100, + ]), + true, + '200 px x 100 px', + ]; + + yield [ + 'Created using an array with strings', + Size::fromArray([ + '200', + '100', + ]), + false, + '200 x 100', + ]; + + yield [ + 'Created using an array with strings (converting with unit)', + Size::fromArray([ + '200', + '100', + ]), + true, + '200 px x 100 px', + ]; + + yield [ + 'Created using simple string', + Size::fromString('200 x 100'), + false, + '200 x 100', + ]; + + yield [ + 'Created using simple string', + Size::fromString('200 x 100'), + false, + '200 x 100', + ]; + + yield [ + 'Created using simple string and custom separator', + Size::fromString('200 X 100', '', ' X '), + false, + '200 X 100', + ]; + + yield [ + 'Created using simple string, custom separator and custom unit (with unit)', + Size::fromString('200 : 100', 'mm', ' : '), + true, + '200 mm : 100 mm', + ]; + + yield [ + 'Created using simple string (converting with unit)', + Size::fromString('200 x 100'), + true, + '200 px x 100 px', + ]; + + yield [ + 'Created using string with too much spaces everywhere', + Size::fromString(' 200 x 100 '), + false, + '200 x 100', + ]; + + yield [ + 'Created using string with too much spaces everywhere (converting with unit)', + Size::fromString(' 200 x 100 '), + true, + '200 px x 100 px', + ]; + } + + public function provideSizeToGetHeight() + { + yield [ + 'Created using an array with integers', + Size::fromArray([ + 200, + 100, + ]), + false, + 100, + ]; + + yield [ + 'Created using an array with integers (with unit)', + Size::fromArray([ + 200, + 100, + ]), + true, + '100 px', + ]; + + yield [ + 'Created using an array with strings', + Size::fromArray([ + '200', + '100', + ]), + false, + 100, + ]; + + yield [ + 'Created using an array with strings (with unit)', + Size::fromArray([ + '200', + '100', + ]), + true, + '100 px', + ]; + + yield [ + 'Created using simple string', + Size::fromString('200 x 100'), + false, + 100, + ]; + + yield [ + 'Created using simple string (with unit)', + Size::fromString('200 x 100'), + true, + '100 px', + ]; + + yield [ + 'Created using simple string and custom separator', + Size::fromString('200 X 100', '', ' X '), + false, + 100, + ]; + + yield [ + 'Created using simple string, custom separator and custom unit (with unit)', + Size::fromString('200 : 100', 'mm', ' : '), + true, + '100 mm', + ]; + + yield [ + 'Created using string with too much spaces everywhere', + Size::fromString(' 200 x 100 '), + false, + 100, + ]; + + yield [ + 'Created using string with too much spaces everywhere (with unit)', + Size::fromString(' 200 x 100 '), + true, + '100 px', + ]; + } + + public function provideSizeToGetWidth() + { + yield [ + 'Created using an array with integers', + Size::fromArray([ + 200, + 100, + ]), + false, + 200, + ]; + + yield [ + 'Created using an array with integers (with unit)', + Size::fromArray([ + 200, + 100, + ]), + true, + '200 px', + ]; + + yield [ + 'Created using an array with strings', + Size::fromArray([ + '200', + '100', + ]), + false, + 200, + ]; + + yield [ + 'Created using an array with strings (with unit)', + Size::fromArray([ + '200', + '100', + ]), + true, + '200 px', + ]; + + yield [ + 'Created using simple string', + Size::fromString('200 x 100'), + false, + 200, + ]; + + yield [ + 'Created using simple string (with unit)', + Size::fromString('200 x 100'), + true, + '200 px', + ]; + + yield [ + 'Created using simple string and custom separator', + Size::fromString('200 X 100', '', ' X '), + false, + 200, + ]; + + yield [ + 'Created using simple string, custom separator and custom unit (with unit)', + Size::fromString('200 : 100', 'mm', ' : '), + true, + '200 mm', + ]; + + yield [ + 'Created using string with too much spaces everywhere', + Size::fromString(' 200 x 100 '), + false, + 200, + ]; + + yield [ + 'Created using string with too much spaces everywhere (with unit)', + Size::fromString(' 200 x 100 '), + true, + '200 px', + ]; + } + + public function provideSizeToSetHeight() + { + yield [ + 'Null as height', + Size::fromArray([ + 200, + 100, + ]), + null, + 0, + ]; + + yield [ + 'An empty string', + Size::fromArray([ + 200, + 100, + ]), + '', + 0, + ]; + + yield [ + 'Negative value', + Size::fromArray([ + 200, + 100, + ]), + -1, + -1, + ]; + + yield [ + 'Negative value as string', + Size::fromArray([ + 200, + 100, + ]), + '-1', + -1, + ]; + + yield [ + '0 as height', + Size::fromArray([ + 200, + 100, + ]), + 0, + 0, + ]; + + yield [ + 'Positive value', + Size::fromArray([ + 200, + 100, + ]), + 300, + 300, + ]; + + yield [ + 'Positive value as string', + Size::fromArray([ + 200, + 100, + ]), + '300', + 300, + ]; + } + + public function provideSizeToSetWidth() + { + yield [ + 'Null as width', + Size::fromArray([ + 200, + 100, + ]), + null, + 0, + ]; + + yield [ + 'An empty string', + Size::fromArray([ + 200, + 100, + ]), + '', + 0, + ]; + + yield [ + 'Negative value', + Size::fromArray([ + 200, + 100, + ]), + -1, + -1, + ]; + + yield [ + 'Negative value as string', + Size::fromArray([ + 200, + 100, + ]), + '-1', + -1, + ]; + + yield [ + '0 as width', + Size::fromArray([ + 200, + 100, + ]), + 0, + 0, + ]; + + yield [ + 'Positive value', + Size::fromArray([ + 200, + 100, + ]), + 300, + 300, + ]; + + yield [ + 'Positive value as string', + Size::fromArray([ + 200, + 100, + ]), + '300', + 300, + ]; + } + public function testConstructor() { static::assertConstructorVisibilityAndArguments( @@ -33,111 +942,6 @@ class SizeTest extends BaseTestCase ); } - /** - * @param string $description Description of test - * @param null|Size $size Size to convert - * @param string $expected Expected result - * - * @dataProvider provideSizeForConvertingToString - */ - public function testToStringConverting($description, $size, $expected) - { - static::assertEquals($expected, (string)$size, $description); - } - - public function testSetSeparator() - { - $size = Size::fromArray([ - 200, - 100, - ]); - - static::assertInstanceOf(Size::class, $size->setSeparator(' / ')); - static::assertSame('200 / 100', $size->toString()); - } - - /** - * @param string $description Description of test - * @param Size $size Size to get width - * @param bool $withUnit If is set to true, width is returned with unit ("px"). Otherwise - without. - * @param int|string $expected Expected width - * - * @dataProvider provideSizeToGetWidth - */ - public function testGetWidth($description, Size $size, $withUnit, $expected) - { - static::assertSame($expected, $size->getWidth($withUnit), $description); - } - - /** - * @param string $description Description of test - * @param Size $size Size to set width - * @param int|string $width The width - * @param int|string $expected Expected width - * - * @dataProvider provideSizeToSetWidth - */ - public function testSetWidth($description, Size $size, $width, $expected) - { - $result = $size->setWidth($width); - - static::assertInstanceOf(Size::class, $result, $description); - static::assertSame($expected, $size->getWidth(), $description); - } - - /** - * @param string $description Description of test - * @param Size $size Size to get width - * @param bool $withUnit If is set to true, width is returned with unit ("px"). Otherwise - without. - * @param int|string $expected Expected width - * - * @dataProvider provideSizeToGetHeight - */ - public function testGetHeight($description, Size $size, $withUnit, $expected) - { - static::assertSame($expected, $size->getHeight($withUnit), $description); - } - - /** - * @param string $description Description of test - * @param Size $size Size to set height - * @param int|string $height The height - * @param int|string $expected Expected height - * - * @dataProvider provideSizeToSetHeight - */ - public function testSetHeight($description, Size $size, $height, $expected) - { - $result = $size->setHeight($height); - - static::assertInstanceOf(Size::class, $result, $description); - static::assertSame($expected, $size->getHeight(), $description); - } - - /** - * @param string $description Description of test - * @param Size $size Size to convert - * @param bool $withUnit If is set to true, width and height are returned with unit ("px"). Otherwise - - * without. - * @param string $expected Expected result - * - * @dataProvider provideSizeForToString - */ - public function testToString($description, Size $size, $withUnit, $expected) - { - static::assertSame($expected, $size->toString($withUnit), $description); - } - - /** - * @param array $size Invalid size - * @dataProvider provideInvalidSizeAsArray - */ - public function testFromArrayUsingInvalidSizeAsArray(array $size) - { - $this->expectException(InvalidSizeDimensionsException::class); - Size::fromArray($size); - } - /** * @param string $description Description of test * @param array $size The size represented as array @@ -152,17 +956,13 @@ class SizeTest extends BaseTestCase } /** - * @param string $description Description of test - * @param Size $size Size to convert - * @param bool $withUnit If is set to true, width and height are returned with unit ("px"). Otherwise - - * without. - * @param array $expected Expected result - * - * @dataProvider provideSizeForToArray + * @param array $size Invalid size + * @dataProvider provideInvalidSizeAsArray */ - public function testToArray($description, Size $size, $withUnit, array $expected) + public function testFromArrayUsingInvalidSizeAsArray(array $size) { - static::assertSame($expected, $size->toArray($withUnit), $description); + $this->expectException(InvalidSizeDimensionsException::class); + Size::fromArray($size); } /** @@ -188,911 +988,112 @@ class SizeTest extends BaseTestCase static::assertNull(Size::fromString($emptySize)); } - public function provideSizeForConvertingToString() + /** + * @param string $description Description of test + * @param Size $size Size to get width + * @param bool $withUnit If is set to true, width is returned with unit ("px"). Otherwise - without. + * @param int|string $expected Expected width + * + * @dataProvider provideSizeToGetHeight + */ + public function testGetHeight($description, Size $size, $withUnit, $expected) { - yield[ - 'Created using an empty array', - Size::fromArray([]), - '', - ]; - - yield[ - 'Created using an empty string', - Size::fromString(''), - '', - ]; - - yield[ - 'Created using an array with integers', - Size::fromArray([ - 200, - 100, - ]), - '200 x 100', - ]; - - yield[ - 'Created using an array with strings', - Size::fromArray([ - '200', - '100', - ]), - '200 x 100', - ]; - - yield[ - 'Created using simple string', - Size::fromString('200x100', '', 'x'), - '200x100', - ]; - - yield[ - 'Created using string with too much spaces everywhere', - Size::fromString(' 200 x 100 '), - '200 x 100', - ]; + static::assertSame($expected, $size->getHeight($withUnit), $description); } /** - * Provides invalid size (as an array) + * @param string $description Description of test + * @param Size $size Size to get width + * @param bool $withUnit If is set to true, width is returned with unit ("px"). Otherwise - without. + * @param int|string $expected Expected width * - * @return \Generator + * @dataProvider provideSizeToGetWidth */ - public function provideInvalidSizeAsArray() + public function testGetWidth($description, Size $size, $withUnit, $expected) { - yield[ - [ - 10, - -1, - ], - ]; - - yield[ - [ - -1, - 10, - ], - ]; - - yield[ - [ - -1, - -1, - ], - ]; + static::assertSame($expected, $size->getWidth($withUnit), $description); } - public function provideSizeToGetWidth() + /** + * @param string $description Description of test + * @param Size $size Size to set height + * @param int|string $height The height + * @param int|string $expected Expected height + * + * @dataProvider provideSizeToSetHeight + */ + public function testSetHeight($description, Size $size, $height, $expected) { - yield[ - 'Created using an array with integers', - Size::fromArray([ - 200, - 100, - ]), - false, - 200, - ]; + $result = $size->setHeight($height); - yield[ - 'Created using an array with integers (with unit)', - Size::fromArray([ - 200, - 100, - ]), - true, - '200 px', - ]; - - yield[ - 'Created using an array with strings', - Size::fromArray([ - '200', - '100', - ]), - false, - 200, - ]; - - yield[ - 'Created using an array with strings (with unit)', - Size::fromArray([ - '200', - '100', - ]), - true, - '200 px', - ]; - - yield[ - 'Created using simple string', - Size::fromString('200 x 100'), - false, - 200, - ]; - - yield[ - 'Created using simple string (with unit)', - Size::fromString('200 x 100'), - true, - '200 px', - ]; - - yield[ - 'Created using simple string and custom separator', - Size::fromString('200 X 100', '', ' X '), - false, - 200, - ]; - - yield[ - 'Created using simple string, custom separator and custom unit (with unit)', - Size::fromString('200 : 100', 'mm', ' : '), - true, - '200 mm', - ]; - - yield[ - 'Created using string with too much spaces everywhere', - Size::fromString(' 200 x 100 '), - false, - 200, - ]; - - yield[ - 'Created using string with too much spaces everywhere (with unit)', - Size::fromString(' 200 x 100 '), - true, - '200 px', - ]; + static::assertInstanceOf(Size::class, $result, $description); + static::assertSame($expected, $size->getHeight(), $description); } - public function provideSizeToGetHeight() + public function testSetSeparator() { - yield[ - 'Created using an array with integers', - Size::fromArray([ - 200, - 100, - ]), - false, + $size = Size::fromArray([ + 200, 100, - ]; + ]); - yield[ - 'Created using an array with integers (with unit)', - Size::fromArray([ - 200, - 100, - ]), - true, - '100 px', - ]; - - yield[ - 'Created using an array with strings', - Size::fromArray([ - '200', - '100', - ]), - false, - 100, - ]; - - yield[ - 'Created using an array with strings (with unit)', - Size::fromArray([ - '200', - '100', - ]), - true, - '100 px', - ]; - - yield[ - 'Created using simple string', - Size::fromString('200 x 100'), - false, - 100, - ]; - - yield[ - 'Created using simple string (with unit)', - Size::fromString('200 x 100'), - true, - '100 px', - ]; - - yield[ - 'Created using simple string and custom separator', - Size::fromString('200 X 100', '', ' X '), - false, - 100, - ]; - - yield[ - 'Created using simple string, custom separator and custom unit (with unit)', - Size::fromString('200 : 100', 'mm', ' : '), - true, - '100 mm', - ]; - - yield[ - 'Created using string with too much spaces everywhere', - Size::fromString(' 200 x 100 '), - false, - 100, - ]; - - yield[ - 'Created using string with too much spaces everywhere (with unit)', - Size::fromString(' 200 x 100 '), - true, - '100 px', - ]; + static::assertInstanceOf(Size::class, $size->setSeparator(' / ')); + static::assertSame('200 / 100', $size->toString()); } - public function provideSizeToSetWidth() + /** + * @param string $description Description of test + * @param Size $size Size to set width + * @param int|string $width The width + * @param int|string $expected Expected width + * + * @dataProvider provideSizeToSetWidth + */ + public function testSetWidth($description, Size $size, $width, $expected) { - yield[ - 'Null as width', - Size::fromArray([ - 200, - 100, - ]), - null, - 0, - ]; + $result = $size->setWidth($width); - yield[ - 'An empty string', - Size::fromArray([ - 200, - 100, - ]), - '', - 0, - ]; - - yield[ - 'Negative value', - Size::fromArray([ - 200, - 100, - ]), - -1, - -1, - ]; - - yield[ - 'Negative value as string', - Size::fromArray([ - 200, - 100, - ]), - '-1', - -1, - ]; - - yield[ - '0 as width', - Size::fromArray([ - 200, - 100, - ]), - 0, - 0, - ]; - - yield[ - 'Positive value', - Size::fromArray([ - 200, - 100, - ]), - 300, - 300, - ]; - - yield[ - 'Positive value as string', - Size::fromArray([ - 200, - 100, - ]), - '300', - 300, - ]; + static::assertInstanceOf(Size::class, $result, $description); + static::assertSame($expected, $size->getWidth(), $description); } - public function provideSizeToSetHeight() + /** + * @param string $description Description of test + * @param Size $size Size to convert + * @param bool $withUnit If is set to true, width and height are returned with unit ("px"). Otherwise - + * without. + * @param array $expected Expected result + * + * @dataProvider provideSizeForToArray + */ + public function testToArray($description, Size $size, $withUnit, array $expected) { - yield[ - 'Null as height', - Size::fromArray([ - 200, - 100, - ]), - null, - 0, - ]; - - yield[ - 'An empty string', - Size::fromArray([ - 200, - 100, - ]), - '', - 0, - ]; - - yield[ - 'Negative value', - Size::fromArray([ - 200, - 100, - ]), - -1, - -1, - ]; - - yield[ - 'Negative value as string', - Size::fromArray([ - 200, - 100, - ]), - '-1', - -1, - ]; - - yield[ - '0 as height', - Size::fromArray([ - 200, - 100, - ]), - 0, - 0, - ]; - - yield[ - 'Positive value', - Size::fromArray([ - 200, - 100, - ]), - 300, - 300, - ]; - - yield[ - 'Positive value as string', - Size::fromArray([ - 200, - 100, - ]), - '300', - 300, - ]; + static::assertSame($expected, $size->toArray($withUnit), $description); } - public function provideSizeForToString() + /** + * @param string $description Description of test + * @param Size $size Size to convert + * @param bool $withUnit If is set to true, width and height are returned with unit ("px"). Otherwise - + * without. + * @param string $expected Expected result + * + * @dataProvider provideSizeForToString + */ + public function testToString($description, Size $size, $withUnit, $expected) { - yield[ - 'With unknown dimensions', - Size::fromArray([ - null, - null, - ]), - false, - '0 x 0', - ]; - - yield[ - 'With unknown dimensions (converting with unit)', - Size::fromArray([ - null, - null, - ]), - true, - '0 px x 0 px', - ]; - - yield[ - 'Created using an array with integers', - Size::fromArray([ - 200, - 100, - ]), - false, - '200 x 100', - ]; - - yield[ - 'Created using an array with integers (converting with unit)', - Size::fromArray([ - 200, - 100, - ]), - true, - '200 px x 100 px', - ]; - - yield[ - 'Created using an array with strings', - Size::fromArray([ - '200', - '100', - ]), - false, - '200 x 100', - ]; - - yield[ - 'Created using an array with strings (converting with unit)', - Size::fromArray([ - '200', - '100', - ]), - true, - '200 px x 100 px', - ]; - - yield[ - 'Created using simple string', - Size::fromString('200 x 100'), - false, - '200 x 100', - ]; - - yield[ - 'Created using simple string', - Size::fromString('200 x 100'), - false, - '200 x 100', - ]; - - yield[ - 'Created using simple string and custom separator', - Size::fromString('200 X 100', '', ' X '), - false, - '200 X 100', - ]; - - yield[ - 'Created using simple string, custom separator and custom unit (with unit)', - Size::fromString('200 : 100', 'mm', ' : '), - true, - '200 mm : 100 mm', - ]; - - yield[ - 'Created using simple string (converting with unit)', - Size::fromString('200 x 100'), - true, - '200 px x 100 px', - ]; - - yield[ - 'Created using string with too much spaces everywhere', - Size::fromString(' 200 x 100 '), - false, - '200 x 100', - ]; - - yield[ - 'Created using string with too much spaces everywhere (converting with unit)', - Size::fromString(' 200 x 100 '), - true, - '200 px x 100 px', - ]; + static::assertSame($expected, $size->toString($withUnit), $description); } - public function provideSizeForToArray() + /** + * @param string $description Description of test + * @param null|Size $size Size to convert + * @param string $expected Expected result + * + * @dataProvider provideSizeForConvertingToString + */ + public function testToStringConverting($description, $size, $expected) { - yield[ - 'Created using an array with integers', - Size::fromArray([ - 200, - 100, - ]), - false, - [ - 200, - 100, - ], - ]; - - yield[ - 'Created using an array with integers (converting with unit)', - Size::fromArray([ - 200, - 100, - ]), - true, - [ - '200 px', - '100 px', - ], - ]; - - yield[ - 'Created using an array with strings', - Size::fromArray([ - '200', - '100', - ]), - false, - [ - 200, - 100, - ], - ]; - - yield[ - 'Created using an array with strings (converting with unit)', - Size::fromArray([ - '200', - '100', - ]), - true, - [ - '200 px', - '100 px', - ], - ]; - - yield[ - 'Created using simple string', - Size::fromString('200 x 100'), - false, - [ - 200, - 100, - ], - ]; - - yield[ - 'Created using simple string and custom separator', - Size::fromString('200 X 100', '', ' X '), - false, - [ - 200, - 100, - ], - ]; - - yield[ - 'Created using simple string, custom separator and custom unit (with unit)', - Size::fromString('200 : 100', 'mm', ' : '), - true, - [ - '200 mm', - '100 mm', - ], - ]; - - yield[ - 'Created using simple string (converting with unit)', - Size::fromString('200 x 100'), - true, - [ - '200 px', - '100 px', - ], - ]; - - yield[ - 'Created using string with too much spaces everywhere', - Size::fromString(' 200 x 100 '), - false, - [ - 200, - 100, - ], - ]; - - yield[ - 'Created using string with too much spaces everywhere (converting with unit)', - Size::fromString(' 200 x 100 '), - true, - [ - '200 px', - '100 px', - ], - ]; - } - - public function provideSizeForFromString() - { - yield[ - 'One number only', - 200, - '', - ' x ', - null, - ]; - - yield[ - 'One number only as string', - '200', - '', - ' x ', - null, - ]; - - yield[ - 'The " " as invalid separator', - '200 100', - '', - ' x ', - null, - ]; - - yield[ - 'The "|" as separator (invalid separator)', - '200 | 100', - '', - ' x ', - null, - ]; - - yield[ - 'The "|" as invalid separator and no spaces around separator', - '200|100', - '', - ' x ', - null, - ]; - - yield[ - 'The "X" as invalid separator', - '200 X 100', - '', - ' x ', - null, - ]; - - yield[ - 'Simple, valid size', - '200 x 100', - 'px', - ' x ', - Size::fromArray([ - 200, - 100, - ]), - ]; - - yield[ - 'Simple, valid size using custom separator', - '200 X 100', - 'px', - ' X ', - Size::fromArray([ - 200, - 100, - ])->setSeparator(' X '), - ]; - - yield[ - 'Too much spaces at the right of separator', - '200 x 100', - 'px', - ' x ', - Size::fromArray([ - 200, - 100, - ]), - ]; - - yield[ - 'Too much spaces at the left of separator', - '200 x 100', - 'px', - ' x ', - Size::fromArray([ - 200, - 100, - ]), - ]; - - yield[ - 'Too much spaces around separator', - '200 x 100', - 'px', - ' x ', - Size::fromArray([ - 200, - 100, - ]), - ]; - - yield[ - 'Too much spaces before width (1st)', - ' 200 x 100', - 'px', - ' x ', - Size::fromArray([ - 200, - 100, - ]), - ]; - - yield[ - 'Too much spaces before width (2nd) and custom separator', - ' 200 X 100', - 'px', - ' X ', - Size::fromArray([ - 200, - 100, - ])->setSeparator(' X '), - ]; - - yield[ - 'Too much spaces after height (1st)', - '200 x 100 ', - 'px', - ' x ', - Size::fromArray([ - 200, - 100, - ]), - ]; - - yield[ - 'Too much spaces after height (2nd) and custom separator', - '200 X 100 ', - 'px', - ' X ', - Size::fromArray([ - 200, - 100, - ])->setSeparator(' X '), - ]; - - yield[ - 'Too much spaces before width and after height (1st)', - ' 200 x 100 ', - 'km', - ' x ', - Size::fromArray( - [ - 200, - 100, - ], - 'km' - ), - ]; - - yield[ - 'Too much spaces before width and after height (2nd) and custom separator', - ' 200 X 100 ', - 'px', - ' X ', - Size::fromArray([ - 200, - 100, - ])->setSeparator(' X '), - ]; - - yield[ - 'Too much spaces everywhere (1st)', - ' 200 x 100 ', - 'px', - ' x ', - Size::fromArray([ - 200, - 100, - ]), - ]; - - yield[ - 'Too much spaces everywhere (2nd) and custom separator', - ' 200 X 100 ', - 'px', - ' X ', - Size::fromArray([ - 200, - 100, - ])->setSeparator(' X '), - ]; - - yield[ - 'Too much spaces everywhere (3rd)', - ' 200 x 100 ', - 'px', - ' x ', - Size::fromArray([ - 200, - 100, - ]), - ]; - - yield[ - 'Too much spaces everywhere (4th) and custom separator', - ' 200 : 100 ', - 'px', - ' : ', - Size::fromArray([ - 200, - 100, - ])->setSeparator(' : '), - ]; - - yield[ - 'Too much spaces everywhere (5th)', - ' 200 x 100 ', - 'mm', - ' x ', - Size::fromArray( - [ - 200, - 100, - ], - 'mm' - ), - ]; - } - - public function provideSizeForFromArray() - { - yield[ - 'An empty array', - [], - '', - null, - ]; - - yield[ - 'One number only', - [ - 200, - ], - '', - null, - ]; - - yield[ - 'One number only as string', - [ - '200', - ], - '', - null, - ]; - - yield[ - '0 as dimensions', - [ - 0, - 0, - ], - 'px', - Size::fromString('0 x 0'), - ]; - - yield[ - 'Simple, valid size', - [ - 200, - 100, - ], - 'px', - Size::fromString('200 x 100'), - ]; - - yield[ - 'Simple, valid size (using strings)', - [ - '200', - '100', - ], - 'mm', - Size::fromString('200 x 100', 'mm'), - ]; + static::assertEquals($expected, (string) $size, $description); } } diff --git a/tests/ValueObject/TemplateTest.php b/tests/ValueObject/TemplateTest.php index 0c97067..8dc8f7c 100644 --- a/tests/ValueObject/TemplateTest.php +++ b/tests/ValueObject/TemplateTest.php @@ -27,6 +27,183 @@ use Meritoo\Common\ValueObject\Template; */ class TemplateTest extends BaseTestCase { + public function provideInvalidContent(): ?Generator + { + $template = 'Content of template \'%s\' is invalid. Did you use string with 1 placeholder at least?'; + + yield [ + 'An empty string' => '', + sprintf($template, ''), + ]; + + yield [ + 'Without placeholders' => 'test', + sprintf($template, 'test'), + ]; + + yield [ + 'With starting tag only (invalid placeholder)' => 'This is %test', + sprintf($template, 'This is %test'), + ]; + + yield [ + 'With ending tag only (invalid placeholder)' => 'This is test%', + sprintf($template, 'This is test%'), + ]; + } + + public function provideTemplateToFill(): ?Generator + { + yield [ + 'Template with 1 placeholder', + new Template('%test%'), + [ + 'test' => 123, + ], + '123', + ]; + + yield [ + 'Template with 1 placeholder, but more values', + new Template('%test%'), + [ + 'test' => 123, + 'anotherTest' => 456, + ], + '123', + ]; + + yield [ + 'Template with 2 placeholders', + new Template('My name is %name% and I am %profession%'), + [ + 'name' => 'Jane', + 'profession' => 'photographer', + ], + 'My name is Jane and I am photographer', + ]; + + yield [ + 'Template with 2 placeholders, but more values', + new Template('My name is %name% and I am %profession%'), + [ + 'name' => 'Jane', + 'test-test' => 123, + 'profession' => 'photographer', + 'anotherTest' => 456, + ], + 'My name is Jane and I am photographer', + ]; + + yield [ + 'Template with 2 placeholders that contains space', + new Template('My name is %first name% %last name% and I live in %current location%'), + [ + 'first name' => 'Jane', + 'last name' => 'Brown', + 'current location' => 'NY, USA', + ], + 'My name is Jane Brown and I live in NY, USA', + ]; + + yield [ + 'Template with 2 placeholders that contains space, but more values', + new Template('My name is %first name% %last name% and I live in %current location%'), + [ + 'first name' => 'Jane', + 'profession' => 'photographer', + 'last name' => 'Brown', + 'test-test' => 123, + 'anotherTest' => 456, + 'current location' => 'NY, USA', + ], + 'My name is Jane Brown and I live in NY, USA', + ]; + } + + public function provideTemplateToFillUsingIncorrectValues(): ?Generator + { + $template = 'Cannot fill template \'%s\', because of missing values for placeholder(s): %s. Did you provide all' + .' required values?'; + + yield [ + new Template('%test%'), + [ + 'something' => 123, + ], + sprintf( + $template, + '%test%', + 'test' + ), + ]; + + yield [ + new Template('%test%'), + [], + sprintf( + $template, + '%test%', + 'test' + ), + ]; + + yield [ + new Template('%test1% - %test2%'), + [ + 'test1' => 123, + ], + sprintf( + $template, + '%test1% - %test2%', + 'test2' + ), + ]; + + yield [ + new Template('%test1% - %test2%'), + [ + 'test1' => 123, + 'test3' => 456, + ], + sprintf( + $template, + '%test1% - %test2%', + 'test2' + ), + ]; + + yield [ + new Template('%test1% / %test2% / %test3%'), + [ + 'test1' => 123, + ], + sprintf( + $template, + '%test1% / %test2% / %test3%', + 'test2, test3' + ), + ]; + } + + public function provideValidContent(): ?Generator + { + yield [ + 'Template with 1 placeholder', + '%test%', + ]; + + yield [ + 'Template with 2 placeholders', + 'My name is %name% and I am %profession%', + ]; + + yield [ + 'Template with 2 placeholders that contains space', + 'My name is %first name% %last name% and I live in %current location%', + ]; + } + public function testConstructor(): void { static::assertConstructorVisibilityAndArguments( @@ -37,6 +214,36 @@ class TemplateTest extends BaseTestCase ); } + /** + * @param string $description Description of test + * @param Template $template Template to fill + * @param array $values Pairs of key-value where: key - name of placeholder, value - value of the + * placeholder + * @param string $expected Expected result + * + * @dataProvider provideTemplateToFill + */ + public function testFill(string $description, Template $template, array $values, string $expected): void + { + static::assertSame($expected, $template->fill($values), $description); + } + + /** + * @param Template $template Template to fill + * @param array $values Pairs of key-value where: key - name of placeholder, value - value of the + * placeholder + * @param string $exceptionMessage Expected message of exception + * + * @dataProvider provideTemplateToFillUsingIncorrectValues + */ + public function testFillUsingIncorrectValues(Template $template, array $values, string $exceptionMessage): void + { + $this->expectException(MissingPlaceholdersInValuesException::class); + $this->expectExceptionMessage($exceptionMessage); + + $template->fill($values); + } + /** * @param string $content Raw string with placeholders (content of the template) * @param string $exceptionMessage Expected message of exception @@ -62,211 +269,4 @@ class TemplateTest extends BaseTestCase $template = new Template($content); static::assertSame($content, Reflection::getPropertyValue($template, 'content', true), $description); } - - /** - * @param Template $template Template to fill - * @param array $values Pairs of key-value where: key - name of placeholder, value - value of the - * placeholder - * @param string $exceptionMessage Expected message of exception - * - * @dataProvider provideTemplateToFillUsingIncorrectValues - */ - public function testFillUsingIncorrectValues(Template $template, array $values, string $exceptionMessage): void - { - $this->expectException(MissingPlaceholdersInValuesException::class); - $this->expectExceptionMessage($exceptionMessage); - - $template->fill($values); - } - - /** - * @param string $description Description of test - * @param Template $template Template to fill - * @param array $values Pairs of key-value where: key - name of placeholder, value - value of the - * placeholder - * @param string $expected Expected result - * - * @dataProvider provideTemplateToFill - */ - public function testFill(string $description, Template $template, array $values, string $expected): void - { - static::assertSame($expected, $template->fill($values), $description); - } - - public function provideInvalidContent(): ?Generator - { - $template = 'Content of template \'%s\' is invalid. Did you use string with 1 placeholder at least?'; - - yield[ - 'An empty string' => '', - sprintf($template, ''), - ]; - - yield[ - 'Without placeholders' => 'test', - sprintf($template, 'test'), - ]; - - yield[ - 'With starting tag only (invalid placeholder)' => 'This is %test', - sprintf($template, 'This is %test'), - ]; - - yield[ - 'With ending tag only (invalid placeholder)' => 'This is test%', - sprintf($template, 'This is test%'), - ]; - } - - public function provideTemplateToFillUsingIncorrectValues(): ?Generator - { - $template = 'Cannot fill template \'%s\', because of missing values for placeholder(s): %s. Did you provide all' - . ' required values?'; - - yield[ - new Template('%test%'), - [ - 'something' => 123, - ], - sprintf( - $template, - '%test%', - 'test' - ), - ]; - - yield[ - new Template('%test%'), - [], - sprintf( - $template, - '%test%', - 'test' - ), - ]; - - yield[ - new Template('%test1% - %test2%'), - [ - 'test1' => 123, - ], - sprintf( - $template, - '%test1% - %test2%', - 'test2' - ), - ]; - - yield[ - new Template('%test1% - %test2%'), - [ - 'test1' => 123, - 'test3' => 456, - ], - sprintf( - $template, - '%test1% - %test2%', - 'test2' - ), - ]; - - yield[ - new Template('%test1% / %test2% / %test3%'), - [ - 'test1' => 123, - ], - sprintf( - $template, - '%test1% / %test2% / %test3%', - 'test2, test3' - ), - ]; - } - - public function provideTemplateToFill(): ?Generator - { - yield[ - 'Template with 1 placeholder', - new Template('%test%'), - [ - 'test' => 123, - ], - '123', - ]; - - yield[ - 'Template with 1 placeholder, but more values', - new Template('%test%'), - [ - 'test' => 123, - 'anotherTest' => 456, - ], - '123', - ]; - - yield[ - 'Template with 2 placeholders', - new Template('My name is %name% and I am %profession%'), - [ - 'name' => 'Jane', - 'profession' => 'photographer', - ], - 'My name is Jane and I am photographer', - ]; - - yield[ - 'Template with 2 placeholders, but more values', - new Template('My name is %name% and I am %profession%'), - [ - 'name' => 'Jane', - 'test-test' => 123, - 'profession' => 'photographer', - 'anotherTest' => 456, - ], - 'My name is Jane and I am photographer', - ]; - - yield[ - 'Template with 2 placeholders that contains space', - new Template('My name is %first name% %last name% and I live in %current location%'), - [ - 'first name' => 'Jane', - 'last name' => 'Brown', - 'current location' => 'NY, USA', - ], - 'My name is Jane Brown and I live in NY, USA', - ]; - - yield[ - 'Template with 2 placeholders that contains space, but more values', - new Template('My name is %first name% %last name% and I live in %current location%'), - [ - 'first name' => 'Jane', - 'profession' => 'photographer', - 'last name' => 'Brown', - 'test-test' => 123, - 'anotherTest' => 456, - 'current location' => 'NY, USA', - ], - 'My name is Jane Brown and I live in NY, USA', - ]; - } - - public function provideValidContent(): ?Generator - { - yield[ - 'Template with 1 placeholder', - '%test%', - ]; - - yield[ - 'Template with 2 placeholders', - 'My name is %name% and I am %profession%', - ]; - - yield[ - 'Template with 2 placeholders that contains space', - 'My name is %first name% %last name% and I live in %current location%', - ]; - } } diff --git a/tests/ValueObject/VersionTest.php b/tests/ValueObject/VersionTest.php index 4bcdbfb..210374f 100644 --- a/tests/ValueObject/VersionTest.php +++ b/tests/ValueObject/VersionTest.php @@ -21,15 +21,153 @@ use Meritoo\Common\ValueObject\Version; * @copyright Meritoo * * @internal - * @covers \Meritoo\Common\ValueObject\Version + * @covers \Meritoo\Common\ValueObject\Version */ class VersionTest extends BaseTestCase { + /** + * Provide version as array and expected instance of version + * + * @return Generator + */ + public function provideAsArray() + { + yield [ + [], + null, + ]; + + yield [ + [ + 1, + 0, + ], + null, + ]; + + yield [ + [ + 10, + ], + null, + ]; + + yield [ + [ + 0, + 0, + 0, + ], + new Version(0, 0, 0), + ]; + + yield [ + [ + 1, + 0, + 2, + ], + new Version(1, 0, 2), + ]; + + yield [ + [ + 10, + 5, + 41, + ], + new Version(10, 5, 41), + ]; + } + + /** + * Provide version as string and expected instance of version + * + * @return Generator + */ + public function provideAsString() + { + yield [ + '', + null, + ]; + + yield [ + '1.0', + null, + ]; + + yield [ + '10', + null, + ]; + + yield [ + '0.0.0', + new Version(0, 0, 0), + ]; + + yield [ + '1.0.2', + new Version(1, 0, 2), + ]; + + yield [ + '10.5.41', + new Version(10, 5, 41), + ]; + } + + /** + * Provide instance of version and expected version converted to string + * + * @return Generator + */ + public function provideConvertedToString() + { + yield [ + new Version(0, 0, 0), + '0.0.0', + ]; + + yield [ + new Version(1, 0, 2), + '1.0.2', + ]; + + yield [ + new Version(10, 5, 41), + '10.5.41', + ]; + } + public function testConstructor() { static::assertConstructorVisibilityAndArguments(Version::class, OopVisibilityType::IS_PUBLIC, 3, 3); } + /** + * @param array $version The version + * @param Version $expected (optional) Expected version + * + * @dataProvider provideAsArray + */ + public function testFromArray(array $version, Version $expected = null) + { + static::assertEquals($expected, Version::fromArray($version)); + } + + /** + * @param string $version The version + * @param Version $expected (optional) Expected version + * + * @dataProvider provideAsString + */ + public function testFromString($version, Version $expected = null) + { + static::assertEquals($expected, Version::fromString($version)); + } + public function testNewInstance() { $version = new Version(1, 0, 2); @@ -48,144 +186,6 @@ class VersionTest extends BaseTestCase */ public function testToString(Version $version, $expected) { - static::assertSame($expected, (string)$version); - } - - /** - * @param string $version The version - * @param Version $expected (optional) Expected version - * - * @dataProvider provideAsString - */ - public function testFromString($version, Version $expected = null) - { - static::assertEquals($expected, Version::fromString($version)); - } - - /** - * @param array $version The version - * @param Version $expected (optional) Expected version - * - * @dataProvider provideAsArray - */ - public function testFromArray(array $version, Version $expected = null) - { - static::assertEquals($expected, Version::fromArray($version)); - } - - /** - * Provide instance of version and expected version converted to string - * - * @return Generator - */ - public function provideConvertedToString() - { - yield[ - new Version(0, 0, 0), - '0.0.0', - ]; - - yield[ - new Version(1, 0, 2), - '1.0.2', - ]; - - yield[ - new Version(10, 5, 41), - '10.5.41', - ]; - } - - /** - * Provide version as string and expected instance of version - * - * @return Generator - */ - public function provideAsString() - { - yield[ - '', - null, - ]; - - yield[ - '1.0', - null, - ]; - - yield[ - '10', - null, - ]; - - yield[ - '0.0.0', - new Version(0, 0, 0), - ]; - - yield[ - '1.0.2', - new Version(1, 0, 2), - ]; - - yield[ - '10.5.41', - new Version(10, 5, 41), - ]; - } - - /** - * Provide version as array and expected instance of version - * - * @return Generator - */ - public function provideAsArray() - { - yield[ - [], - null, - ]; - - yield[ - [ - 1, - 0, - ], - null, - ]; - - yield[ - [ - 10, - ], - null, - ]; - - yield[ - [ - 0, - 0, - 0, - ], - new Version(0, 0, 0), - ]; - - yield[ - [ - 1, - 0, - 2, - ], - new Version(1, 0, 2), - ]; - - yield[ - [ - 10, - 5, - 41, - ], - new Version(10, 5, 41), - ]; + static::assertSame($expected, (string) $version); } } From 41ef088ffe058b4c93a9a98012d7f3bfd67415ec Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 10 Sep 2022 13:01:10 +0200 Subject: [PATCH 132/137] Upgrade all dev packages (to the latest, stable versions for PHP 7.4) --- composer.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 89009ba..93eaba0 100644 --- a/composer.json +++ b/composer.json @@ -21,14 +21,14 @@ "gedmo/doctrine-extensions": "^3.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.14", - "infection/infection": "^0.11.4", - "php-coveralls/php-coveralls": "^2.1", - "phpstan/phpstan": "^0.11.1", - "phpunit/phpunit": "^8.0", - "sebastian/phpcpd": "^4.1", - "squizlabs/php_codesniffer": "^3.4", - "vimeo/psalm": "^3.0" + "friendsofphp/php-cs-fixer": "^3.11", + "infection/infection": "^0.26", + "php-coveralls/php-coveralls": "^2.5", + "phpstan/phpstan": "^1.8", + "phpunit/phpunit": "^9", + "sebastian/phpcpd": "^6.0", + "squizlabs/php_codesniffer": "^3.7", + "vimeo/psalm": "^4.0" }, "autoload": { "psr-4": { From bbc5f6a43d8b4ec30e70772f0087969e06286620 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 10 Sep 2022 13:02:02 +0200 Subject: [PATCH 133/137] Bump PHP version to 7.4 (from 7.2) --- composer.json | 2 +- docker-compose.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 93eaba0..45a63f6 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "php": "^7.2", + "php": "^7.4", "ext-dom": "*", "ext-fileinfo": "*", "ext-intl": "*", diff --git a/docker-compose.yml b/docker-compose.yml index d725bfa..98a0357 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ services: # Required to run project # php: - image: meritoo/php + image: meritoo/php:7.4 container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-php entrypoint: php command: -S 0.0.0.0:9999 @@ -14,7 +14,7 @@ services: volumes: - .:/var/www/application:cached composer: - image: meritoo/php + image: meritoo/php:7.4 container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-composer entrypoint: php -d memory_limit=-1 /usr/local/bin/composer volumes: @@ -23,7 +23,7 @@ services: # Required to run PHPUnit's tests # phpunit: - image: meritoo/php + image: meritoo/php:7.4 container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-phpunit entrypoint: ./vendor/bin/phpunit command: --version From 5ebf624b7b3ac9752ce68d968cf1412e5dc7075d Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 10 Sep 2022 13:09:08 +0200 Subject: [PATCH 134/137] Replace deprecated assertRegExp() function with assertMatchesRegularExpression() in PHPUnit tests (after upgrade of PHPUnit 8.x -> 9.x) --- tests/Utilities/DateTest.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/Utilities/DateTest.php b/tests/Utilities/DateTest.php index 8bd70d0..5821e88 100644 --- a/tests/Utilities/DateTest.php +++ b/tests/Utilities/DateTest.php @@ -376,17 +376,17 @@ class DateTest extends BaseTestCase public function testGenerateRandomTimeCustomFormat(): void { - self::assertRegExp('/^0[1-9]{1}|1[0-2]{1}$/', Date::generateRandomTime('h')); // 01 through 12 - self::assertRegExp('/^[0-5]?[0-9]$/', Date::generateRandomTime('i')); // 00 through 59 - self::assertRegExp('/^[0-5]?[0-9]$/', Date::generateRandomTime('s')); // 00 through 59 + self::assertMatchesRegularExpression('/^0[1-9]{1}|1[0-2]{1}$/', Date::generateRandomTime('h')); // 01 through 12 + self::assertMatchesRegularExpression('/^[0-5]?[0-9]$/', Date::generateRandomTime('i')); // 00 through 59 + self::assertMatchesRegularExpression('/^[0-5]?[0-9]$/', Date::generateRandomTime('s')); // 00 through 59 - self::assertRegExp('/^\d{2}:\d{2}$/', Date::generateRandomTime('H:i')); - self::assertRegExp('/^[1-9]|1[0-2]:\d{2}$/', Date::generateRandomTime('g:i')); + self::assertMatchesRegularExpression('/^\d{2}:\d{2}$/', Date::generateRandomTime('H:i')); + self::assertMatchesRegularExpression('/^[1-9]|1[0-2]:\d{2}$/', Date::generateRandomTime('g:i')); } public function testGenerateRandomTimeDefaultFormat(): void { - self::assertRegExp('/\d{2}:\d{2}:\d{2}/', Date::generateRandomTime()); + self::assertMatchesRegularExpression('/\d{2}:\d{2}:\d{2}/', Date::generateRandomTime()); } /** @@ -408,7 +408,7 @@ class DateTest extends BaseTestCase public function testGetCurrentDayOfWeek(): void { - self::assertRegExp('/^[0-6]{1}$/', (string) Date::getCurrentDayOfWeek()); + self::assertMatchesRegularExpression('/^[0-6]{1}$/', (string) Date::getCurrentDayOfWeek()); } public function testGetCurrentDayOfWeekName(): void @@ -431,7 +431,7 @@ class DateTest extends BaseTestCase $pattern = sprintf('/^%s$/', implode('|', $days)); - self::assertRegExp($pattern, Date::getCurrentDayOfWeekName()); + self::assertMatchesRegularExpression($pattern, Date::getCurrentDayOfWeekName()); } /** @@ -886,7 +886,7 @@ class DateTest extends BaseTestCase */ public function testGetDayOfWeek(int $year, int $month, int $day): void { - self::assertRegExp('/^[0-6]{1}$/', (string) Date::getDayOfWeek($year, $month, $day)); + self::assertMatchesRegularExpression('/^[0-6]{1}$/', (string) Date::getDayOfWeek($year, $month, $day)); } /** From d4cb732096686ebcdb6ed6682982e480e745890b Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 10 Sep 2022 13:40:33 +0200 Subject: [PATCH 135/137] Migrate PHPUnit configuration file to current format --- phpunit.xml.dist | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 3e849fb..7e7cc7a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -2,7 +2,7 @@ + + + src + + + + + + + - tests @@ -22,17 +31,7 @@ tests/Collection - - - - src - - - - - - - + From 08a2d0878f7627ac7134698dd1b4f73e72d26722 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 10 Sep 2022 18:06:25 +0200 Subject: [PATCH 136/137] Interfaces of different types of collections. May be used to build specific collections. --- src/Collection/BaseCollection.php | 103 +++++++++--------- .../Collection/AddableCollectionInterface.php | 55 ++++++++++ .../ClearableCollectionInterface.php | 27 +++++ .../Collection/CollectionInterface.php | 42 ++----- .../CountableCollectionInterface.php | 23 ++++ .../GettableCollectionInterface.php | 58 ++++++++++ .../ReducibleCollectionInterface.php | 29 +++++ .../RemovableCollectionInterface.php | 28 +++++ .../VerifiableCollectionInterface.php | 51 +++++++++ tests/Collection/BaseCollectionTest.php | 15 +++ 10 files changed, 344 insertions(+), 87 deletions(-) create mode 100644 src/Contract/Collection/AddableCollectionInterface.php create mode 100644 src/Contract/Collection/ClearableCollectionInterface.php create mode 100644 src/Contract/Collection/CountableCollectionInterface.php create mode 100644 src/Contract/Collection/GettableCollectionInterface.php create mode 100644 src/Contract/Collection/ReducibleCollectionInterface.php create mode 100644 src/Contract/Collection/RemovableCollectionInterface.php create mode 100644 src/Contract/Collection/VerifiableCollectionInterface.php diff --git a/src/Collection/BaseCollection.php b/src/Collection/BaseCollection.php index f97c4fc..f6ff521 100644 --- a/src/Collection/BaseCollection.php +++ b/src/Collection/BaseCollection.php @@ -27,12 +27,12 @@ abstract class BaseCollection implements CollectionInterface * * @var array */ - private $elements; + private array $elements; /** * Class constructor * - * @param array $elements (optional) The elements of collection + * @param array $elements (optional) Elements of collection */ public function __construct(array $elements = []) { @@ -41,10 +41,7 @@ abstract class BaseCollection implements CollectionInterface } /** - * Adds given element (at the end of collection) - * - * @param mixed $element The element to add - * @param mixed $index (optional) Index / key of the element + * {@inheritdoc} */ public function add($element, $index = null): void { @@ -62,11 +59,7 @@ abstract class BaseCollection implements CollectionInterface } /** - * Adds given elements (at the end of collection) - * - * @param array|CollectionInterface $elements The elements to add - * @param bool $useIndexes (optional) If is set to true, indexes of given elements will be - * used in this collection. Otherwise - not. + * {@inheritdoc} */ public function addMultiple($elements, bool $useIndexes = false): void { @@ -87,21 +80,32 @@ abstract class BaseCollection implements CollectionInterface } } + /** + * {@inheritdoc} + */ + public function append($element): void + { + $this->elements[] = $element; + } + + /** + * {@inheritdoc} + */ public function clear(): void { $this->elements = []; } + /** + * {@inheritdoc} + */ public function count(): int { return count($this->elements); } /** - * Returns element with given index - * - * @param mixed $index Index / key of the element - * @return null|mixed + * {@inheritdoc} */ public function getByIndex($index) { @@ -109,24 +113,23 @@ abstract class BaseCollection implements CollectionInterface } /** - * Returns the first element in the collection - * - * @return mixed + * {@inheritdoc} */ public function getFirst() { return Arrays::getFirstElement($this->elements); } + /** + * {@inheritdoc} + */ public function getIterator(): ArrayIterator { return new ArrayIterator($this->elements); } /** - * Returns the last element in the collection - * - * @return mixed + * {@inheritdoc} */ public function getLast() { @@ -134,10 +137,7 @@ abstract class BaseCollection implements CollectionInterface } /** - * Returns next element for given element - * - * @param mixed $element The element to verify - * @return null|mixed + * {@inheritdoc} */ public function getNext($element) { @@ -145,10 +145,7 @@ abstract class BaseCollection implements CollectionInterface } /** - * Returns previous element for given element - * - * @param mixed $element The element to verify - * @return null|mixed + * {@inheritdoc} */ public function getPrevious($element) { @@ -156,10 +153,7 @@ abstract class BaseCollection implements CollectionInterface } /** - * Returns information if the collection has given element, iow. if given element exists in the collection - * - * @param mixed $element The element to verify - * @return bool + * {@inheritdoc} */ public function has($element): bool { @@ -169,9 +163,7 @@ abstract class BaseCollection implements CollectionInterface } /** - * Returns information if collection is empty - * - * @return bool + * {@inheritdoc} */ public function isEmpty(): bool { @@ -179,10 +171,7 @@ abstract class BaseCollection implements CollectionInterface } /** - * Returns information if given element is first in the collection - * - * @param mixed $element The element to verify - * @return bool + * {@inheritdoc} */ public function isFirst($element): bool { @@ -190,17 +179,17 @@ abstract class BaseCollection implements CollectionInterface } /** - * Returns information if given element is last in the collection - * - * @param mixed $element The element to verify - * @return bool + * {@inheritdoc} */ public function isLast($element): bool { return end($this->elements) === $element; } - public function limit(int $max, int $offset = 0): CollectionInterface + /** + * {@inheritdoc} + */ + public function limit(int $max, int $offset = 0): self { $result = clone $this; @@ -230,11 +219,17 @@ abstract class BaseCollection implements CollectionInterface return $result; } + /** + * {@inheritdoc} + */ public function offsetExists($offset): bool { return $this->exists($offset); } + /** + * {@inheritdoc} + */ public function offsetGet($offset) { if ($this->exists($offset)) { @@ -244,11 +239,17 @@ abstract class BaseCollection implements CollectionInterface return null; } + /** + * {@inheritdoc} + */ public function offsetSet($offset, $value): void { $this->elements[$offset] = $value; } + /** + * {@inheritdoc} + */ public function offsetUnset($offset): void { if ($this->exists($offset)) { @@ -257,9 +258,7 @@ abstract class BaseCollection implements CollectionInterface } /** - * Prepends given element (adds given element at the beginning of collection) - * - * @param mixed $element The element to prepend + * {@inheritdoc} */ public function prepend($element): void { @@ -267,9 +266,7 @@ abstract class BaseCollection implements CollectionInterface } /** - * Removes given element - * - * @param mixed $element The element to remove + * {@inheritdoc} */ public function remove($element): void { @@ -287,9 +284,7 @@ abstract class BaseCollection implements CollectionInterface } /** - * Returns representation of object as array - * - * @return array + * {@inheritdoc} */ public function toArray(): array { diff --git a/src/Contract/Collection/AddableCollectionInterface.php b/src/Contract/Collection/AddableCollectionInterface.php new file mode 100644 index 0000000..e3e30cb --- /dev/null +++ b/src/Contract/Collection/AddableCollectionInterface.php @@ -0,0 +1,55 @@ + + * @copyright Meritoo + */ +interface AddableCollectionInterface +{ + /** + * Adds given element (at the end of collection) + * + * @param mixed $element The element to add + * @param mixed $index (optional) Index / key of the element + * @return void + */ + public function add($element, $index = null): void; + + /** + * Adds given elements (at the end of collection) + * + * @param array|CollectionInterface $elements The elements to add + * @param bool $useIndexes (optional) If is set to true, indexes of given elements will be + * used in this collection. Otherwise - not. + * @return void + */ + public function addMultiple(array $elements, bool $useIndexes = false): void; + + /** + * Appends given element (adds given element at the end of collection) + * + * @param mixed $element The element to add at the end + * @return void + */ + public function append($element): void; + + /** + * Prepends given element (adds given element at the beginning of collection) + * + * @param mixed $element The element to add at the beginning + * @return void + */ + public function prepend($element): void; +} diff --git a/src/Contract/Collection/ClearableCollectionInterface.php b/src/Contract/Collection/ClearableCollectionInterface.php new file mode 100644 index 0000000..96b6186 --- /dev/null +++ b/src/Contract/Collection/ClearableCollectionInterface.php @@ -0,0 +1,27 @@ + + * @copyright Meritoo + */ +interface ClearableCollectionInterface +{ + /** + * Removes all elements of the collection + * + * @return void + */ + public function clear(): void; +} diff --git a/src/Contract/Collection/CollectionInterface.php b/src/Contract/Collection/CollectionInterface.php index 855a01c..e97ec1e 100644 --- a/src/Contract/Collection/CollectionInterface.php +++ b/src/Contract/Collection/CollectionInterface.php @@ -11,46 +11,22 @@ declare(strict_types=1); namespace Meritoo\Common\Contract\Collection; use ArrayAccess; -use Countable; use IteratorAggregate; /** - * Interface/Contract of collection of elements with the same type + * Contract for collection of elements with the same type * * @author Meritoo * @copyright Meritoo */ -interface CollectionInterface extends Countable, ArrayAccess, IteratorAggregate +interface CollectionInterface extends ArrayAccess, IteratorAggregate, AddableCollectionInterface, + RemovableCollectionInterface, CountableCollectionInterface, ClearableCollectionInterface, + GettableCollectionInterface, VerifiableCollectionInterface, ReducibleCollectionInterface { - public function add($element, $index = null): void; - - public function addMultiple($elements, bool $useIndexes = false): void; - - public function clear(): void; - - public function getByIndex($index); - - public function getFirst(); - - public function getLast(); - - public function getNext($element); - - public function getPrevious($element); - - public function has($element): bool; - - public function isEmpty(): bool; - - public function isFirst($element): bool; - - public function isLast($element): bool; - - public function limit(int $max, int $offset = 0): self; - - public function prepend($element): void; - - public function remove($element): void; - + /** + * Returns representation of object as array + * + * @return array + */ public function toArray(): array; } diff --git a/src/Contract/Collection/CountableCollectionInterface.php b/src/Contract/Collection/CountableCollectionInterface.php new file mode 100644 index 0000000..063cf07 --- /dev/null +++ b/src/Contract/Collection/CountableCollectionInterface.php @@ -0,0 +1,23 @@ + + * @copyright Meritoo + */ +interface CountableCollectionInterface extends Countable +{ +} diff --git a/src/Contract/Collection/GettableCollectionInterface.php b/src/Contract/Collection/GettableCollectionInterface.php new file mode 100644 index 0000000..5b2ca54 --- /dev/null +++ b/src/Contract/Collection/GettableCollectionInterface.php @@ -0,0 +1,58 @@ + + * @copyright Meritoo + */ +interface GettableCollectionInterface +{ + /** + * Returns element with given index + * + * @param mixed $index Index / key of element to return + * @return mixed + */ + public function getByIndex($index); + + /** + * Returns first element + * + * @return mixed + */ + public function getFirst(); + + /** + * Returns last element + * + * @return mixed + */ + public function getLast(); + + /** + * Returns element next after given element + * + * @param mixed $element The element whose next element should be returned + * @return mixed + */ + public function getNext($element); + + /** + * Returns element preceding given element + * + * @param mixed $element The element whose previous element should be returned + * @return mixed + */ + public function getPrevious($element); +} diff --git a/src/Contract/Collection/ReducibleCollectionInterface.php b/src/Contract/Collection/ReducibleCollectionInterface.php new file mode 100644 index 0000000..d2b2584 --- /dev/null +++ b/src/Contract/Collection/ReducibleCollectionInterface.php @@ -0,0 +1,29 @@ + + * @copyright Meritoo + */ +interface ReducibleCollectionInterface +{ + /** + * Returns new instance of this collection with limited elements + * + * @param int $max Maximum elements to return + * @param int $offset (optional) Position of element from which limitation should start + * @return $this + */ + public function limit(int $max, int $offset = 0): self; +} diff --git a/src/Contract/Collection/RemovableCollectionInterface.php b/src/Contract/Collection/RemovableCollectionInterface.php new file mode 100644 index 0000000..d0a95fa --- /dev/null +++ b/src/Contract/Collection/RemovableCollectionInterface.php @@ -0,0 +1,28 @@ + + * @copyright Meritoo + */ +interface RemovableCollectionInterface +{ + /** + * Removes given element + * + * @param mixed $element The element to remove + * @return void + */ + public function remove($element): void; +} diff --git a/src/Contract/Collection/VerifiableCollectionInterface.php b/src/Contract/Collection/VerifiableCollectionInterface.php new file mode 100644 index 0000000..98e7a67 --- /dev/null +++ b/src/Contract/Collection/VerifiableCollectionInterface.php @@ -0,0 +1,51 @@ + + * @copyright Meritoo + */ +interface VerifiableCollectionInterface +{ + /** + * Returns information if given element exists in collection + * + * @param mixed $element The element to verify + * @return bool + */ + public function has($element): bool; + + /** + * Returns information if collection is empty (has not any element) + * + * @return bool + */ + public function isEmpty(): bool; + + /** + * Returns information if given element is the first element in collection + * + * @param mixed $element The element to verify + * @return bool + */ + public function isFirst($element): bool; + + /** + * Returns information if given element is the last element in collection + * + * @param mixed $element The element to verify + * @return bool + */ + public function isLast($element): bool; +} diff --git a/tests/Collection/BaseCollectionTest.php b/tests/Collection/BaseCollectionTest.php index 5d6eab9..77c7170 100644 --- a/tests/Collection/BaseCollectionTest.php +++ b/tests/Collection/BaseCollectionTest.php @@ -721,6 +721,21 @@ class BaseCollectionTest extends BaseTestCase static::assertSame(5, $this->simpleCollection->count()); } + public function testAppend(): void + { + $this->emptyCollection->append('lorem-ipsum'); + + static::assertFalse($this->emptyCollection->isEmpty()); + static::assertSame(1, $this->emptyCollection->count()); + static::assertSame('lorem-ipsum', $this->emptyCollection[0]); + + $this->simpleCollection->append('lorem-ipsum'); + + static::assertFalse($this->simpleCollection->isEmpty()); + static::assertSame(8, $this->simpleCollection->count()); + static::assertSame('lorem-ipsum', $this->simpleCollection[347]); + } + public function testPrepend() { $this->emptyCollection->prepend('lorem-ipsum'); From cddafc3604e4971c2394439bf83ece8363d42c94 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 10 Sep 2022 18:10:51 +0200 Subject: [PATCH 137/137] Update Changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d04411f..f7ee8f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ Common and useful classes, methods, exceptions etc. # 1.1.8 -1. +1. [Composer] Upgrade all dev packages (to the latest, stable versions for PHP `7.4`) +2. [BaseCollection] Interfaces of different types of collections. May be used to build specific collections. # 1.1.7