diff --git a/.travis.yml b/.travis.yml index eff6130..f1bd310 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ before_install: - composer global require hirak/prestissimo install: -- travis_wait 30 composer install + - travis_wait 30 composer install -v script: - php ./vendor/bin/phpunit diff --git a/CHANGELOG.md b/CHANGELOG.md index 65d5b3c..7dca1b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ Common and useful classes, methods, exceptions etc. +# 0.1.4 + +1. Phing > update configuration +2. Utilities > Date > update descriptions of methods +3. Docker > docker-compose.yml > add "phpunit" service > used to run PHPUnit's tests +4. Reflection > setPropertiesValues() method > sets values of properties in given object + # 0.1.3 1. Tests > refactoring & minor improvements diff --git a/README.md b/README.md index 94a0f44..bcc9fc0 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Common and useful classes, methods, exceptions etc. -[![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 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) # Installation diff --git a/VERSION b/VERSION index b1e80bb..845639e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.3 +0.1.4 diff --git a/build.xml b/build.xml index d65367b..594cf4b 100644 --- a/build.xml +++ b/build.xml @@ -1,46 +1,30 @@ + - + - + - + + depends="build:app, + build:tests" + /> - - + + - - - - + + diff --git a/docker-compose.yml b/docker-compose.yml index e13bca3..6224f02 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,9 @@ version: '3' services: + # + # Required to run project + # php: image: ${DOCKER_CONTAINER_OWNER}/${DOCKER_CONTAINER_PROJECT}-php container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-php @@ -9,12 +12,22 @@ services: build: context: ./docker/config args: - - TIMEZONE=${TIMEZONE} + - TIMEZONE=${TIMEZONE} volumes: - - .:/project:cached + - .:/project:cached composer: image: ${DOCKER_CONTAINER_OWNER}/${DOCKER_CONTAINER_PROJECT}-php container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-composer - entrypoint: composer + entrypoint: php -d memory_limit=-1 /usr/local/bin/composer volumes: - - .:/project:cached + - .:/project:cached + # + # Required to run PHPUnit's tests + # + phpunit: + image: ${DOCKER_CONTAINER_OWNER}/${DOCKER_CONTAINER_PROJECT}-php + container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-phpunit + entrypoint: ./vendor/bin/phpunit + command: --version + volumes: + - .:/project:cached diff --git a/docker/config/Dockerfile b/docker/config/Dockerfile index df4b0f8..277e672 100644 --- a/docker/config/Dockerfile +++ b/docker/config/Dockerfile @@ -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') === \ - '544e09ee996cdf60ece3804abc52599c22b1f40f4323403c44d44fdfdd586475ca9813a858088ffbc1f233e9b180f061') { echo \ + '93b54496392c062774670ac18b134c3b3a95e5a5e5c8f1a9f115f203b75bf9a129d5daa8ba6a13e2cc8a1da0806388a8') { 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');" \ diff --git a/docs/Development.md b/docs/Development.md index f8165a8..7f60fb0 100644 --- a/docs/Development.md +++ b/docs/Development.md @@ -15,11 +15,11 @@ Development-related information docker-compose up -d ``` -2. Install packages by running command: +2. Rebuild project by running command (installs packages, prepares required directories and runs tests): - ```bash - docker-compose run composer install - ``` + ```bash + docker-compose exec php phing + ``` > [What is Docker?](https://www.docker.com/what-docker) @@ -28,7 +28,7 @@ Development-related information Available as `composer` service. You can run any Composer's command using the `composer` service: ```bash -docker-compose run composer +docker-compose run --rm composer [command] ``` Examples below. @@ -36,25 +36,25 @@ Examples below. ##### Install packages ```bash -docker-compose run composer install +docker-compose run --rm composer install ``` ##### Update packages ```bash -docker-compose run composer update +docker-compose run --rm composer update ``` ##### Add package ```bash -docker-compose run composer require / +docker-compose run --rm composer require [vendor]/[package] ``` ##### Remove package ```bash -docker-compose run composer remove / +docker-compose run --rm composer remove [vendor]/[package] ``` # Coding Standards Fixer @@ -65,6 +65,12 @@ Fix coding standard by running command: docker-compose exec php php-cs-fixer fix ``` +or + +```bash +docker-compose exec php phing -f phing/tests.xml build:fix-coding-standards +``` + Omit cache and run the Fixer from scratch by running command: ```bash @@ -77,37 +83,35 @@ docker-compose exec php rm .php_cs.cache && docker-compose exec php php-cs-fixer ### Prerequisites -Install required packages by running command: `docker-compose run composer install`. +Install required packages by running command: `docker-compose run --rm composer install`. -### Running tests +### Running [PHPUnit](https://phpunit.de) tests -#### Simply & quick, without code coverage - -Tests are running using Docker and `php` service defined in `docker-compose.yml`. Example: +##### Easy (with code coverage) ```bash -docker-compose exec php phpunit --no-coverage +docker-compose run --rm phpunit --verbose ``` -You can also run them in container. In this case you have to run 2 commands: -1. Enter container: - - ```bash - docker-compose exec php bash - ``` - -2. Run tests: - - ```bash - phpunit --no-coverage - ``` - -#### With code coverage +or ```bash -docker-compose exec php phpunit +docker-compose exec php phing -f phing/tests.xml test:phpunit ``` +##### Quick (without code coverage) + +```bash +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). + # Other Rebuild project and run tests by running command: diff --git a/phing/app.xml b/phing/app.xml index 23852ba..5688569 100644 --- a/phing/app.xml +++ b/phing/app.xml @@ -1,98 +1,184 @@ - + + - + - + - + + + + + /> - - - - + depends="app:clean, + app:composer:self-update, + app:composer:install, + app:composer:validate, + app:checkout" + /> + + - + + + - - - - + - + - + - + - - - - - + + - - - + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - + + + diff --git a/phing/composer-install.sh b/phing/composer-install.sh new file mode 100644 index 0000000..1a951a2 --- /dev/null +++ b/phing/composer-install.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +EXPECTED_SIGNATURE="$(curl -L https://composer.github.io/installer.sig)" +# Original line (with wget): +# EXPECTED_SIGNATURE="$(wget -q -O - https://composer.github.io/installer.sig)" + +php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" +ACTUAL_SIGNATURE="$(php -r "echo hash_file('SHA384', 'composer-setup.php');")" + +if [ "$EXPECTED_SIGNATURE" != "$ACTUAL_SIGNATURE" ] +then + >&2 echo 'ERROR: Invalid installer signature' + rm composer-setup.php + exit 1 +fi + +php composer-setup.php --quiet +RESULT=$? +rm composer-setup.php +exit $RESULT diff --git a/phing/filesets.xml b/phing/filesets.xml new file mode 100644 index 0000000..c3aea0c --- /dev/null +++ b/phing/filesets.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/phing/properties.dist b/phing/properties.dist index dc0463c..bcb2fb5 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -1,19 +1,3 @@ -# -------------------------------------------------------------------------------- -# Information -# -------------------------------------------------------------------------------- - -# Property files contain key/value pairs -# key = value -# -# Property keys may contain alphanumeric chars and colons, but -# not special chars. This way you can create pseudo-namespaces -# -# You can refer to values of other properties by enclosing their keys in "${}". -# Example: dir.js = ${dir.web}/js -# -# Everything behind the equal sign is the value, you do -# not have to enclose strings: text=This is some text, Your OS is ${php.os} - # -------------------------------------------------------------------------------- # Common, e.g. default environment # -------------------------------------------------------------------------------- @@ -22,10 +6,6 @@ # env = dev -# Install assets using symlinks -# -assets.installWithSymlink = true - # Clear cache with the "warmup" option # # The cache:clear command should always be called with the --no-warmup option. Warmup should be done via the cache:warmup command. @@ -40,67 +20,63 @@ cache.clearWithWarmup = false # Composer # -------------------------------------------------------------------------------- -composer.download_command = php -r "eval('?>'.file_get_contents('https://getcomposer.org/installer'));" - -# Path to composer executable or composer.phar file +# Command used to download Composer # -composer.path = composer.phar -#composer.path = /usr/local/bin/composer +composer.download_command = bash ${project.basedir}/phing/composer-install.sh + +# Path to composer executable or downloaded composer.phar file +# +composer.path = ${project.basedir}/composer.phar # Path to php executable used by composer # composer.php = php -# Self update of the composer -# -composer.self-update = false - -# Validate the composer.json file -# -composer.validate = false - # -------------------------------------------------------------------------------- # Directories # -------------------------------------------------------------------------------- # System directories # -dir.data = ${project.basedir}/data 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 -# -------------------------------------------------------------------------------- # Build directories -# -------------------------------------------------------------------------------- - +# dir.build = ${project.basedir}/build -dir.reports = ${dir.build}/logs +dir.reports = ${dir.build}/reports dir.reports.pdepend = ${dir.reports}/pdepend dir.reports.coverage = ${dir.reports}/phpunit_coverage -# -# Disabled, because unnecessary right now -# phpdocumentor/phpdocumentor cannot be installed via Composer -# -# Meritoo -# 2017-02-22 -# -#dir.docs = ${dir.build}/docs -#dir.docs.phpdoc2 = ${dir.docs}/phpdoc2 -# -------------------------------------------------------------------------------- # Data directories -# -------------------------------------------------------------------------------- - +# +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 + # -------------------------------------------------------------------------------- # Testing # -------------------------------------------------------------------------------- -# Path of the framework used to run unit tests -# -tests.framework.path = ./vendor/bin/phpunit --verbose --no-coverage --testdox - # Path of the PHP Coding Standards Fixer (http://cs.sensiolabs.org) # -phpCsFixer.path = ./vendor/bin/php-cs-fixer +tests.cs_fixer.command = ./vendor/bin/php-cs-fixer fix --verbose + +# Test database path +# +tests.database = ${dir.data.temporary}/database.sqlite + +# Paths of frameworks used to run tests: +# - PHPUnit (unit tests) +# +tests.phpunit.command = ./vendor/bin/phpunit --verbose diff --git a/phing/tests.xml b/phing/tests.xml index edd288b..92f6190 100644 --- a/phing/tests.xml +++ b/phing/tests.xml @@ -1,230 +1,133 @@ - - - + + - + - + - + - - - - - - + + + + + + - + - + depends="build:fix-coding-standards, + build:check, + build:test, + app:checkout" + /> - - - - - - + + - - - - - - + depends="check:cs, + check:md, + check:cpd, + check:depend, + check:loc" + /> - - - - - - - - - - - - - - - - - - - - + depends="test:phpunit" + /> - - - + - - - - + + + + - - + - - + + - - - - + - - - + + + - - + - - - - + + + + - - + - + - - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - + + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index b6d38e5..f54393f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,28 +1,11 @@ + @@ -31,23 +14,17 @@ - ./tests/ + tests/ - ./src/ + src/ - - - performance - - - - + diff --git a/src/Exception/Base/UnknownTypeException.php b/src/Exception/Base/UnknownTypeException.php index ea860ca..43abda2 100644 --- a/src/Exception/Base/UnknownTypeException.php +++ b/src/Exception/Base/UnknownTypeException.php @@ -23,9 +23,9 @@ abstract class UnknownTypeException extends Exception /** * Creates exception * - * @param string|int $unknownType The unknown type of something (value of constant) - * @param BaseType $typeInstance An instance of class that contains type of the something - * @param string $typeName Name of the something + * @param mixed $unknownType The unknown type of something (value of constant) + * @param BaseType $typeInstance An instance of class that contains type of the something + * @param string $typeName Name of the something * @return UnknownTypeException */ public static function create($unknownType, BaseType $typeInstance, $typeName) @@ -35,7 +35,7 @@ abstract class UnknownTypeException extends Exception $allTypes = $typeInstance->getAll(); $types = Arrays::values2string($allTypes, '', ', '); - $message = sprintf(sprintf($template, $unknownType, $typeName, $types)); + $message = sprintf($template, $unknownType, $typeName, $types); return new static($message); } diff --git a/src/Traits/Test/Base/BaseTestCaseTrait.php b/src/Traits/Test/Base/BaseTestCaseTrait.php index 2ca9539..74eea20 100644 --- a/src/Traits/Test/Base/BaseTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTestCaseTrait.php @@ -14,13 +14,11 @@ use Meritoo\Common\Exception\Type\UnknownOopVisibilityTypeException; use Meritoo\Common\Type\OopVisibilityType; use Meritoo\Common\Utilities\Miscellaneous; use ReflectionClass; -use ReflectionException; use ReflectionMethod; use stdClass; /** - * BaseTestCaseTrait - * Created on 2017-11-02 + * Trait for the base test case * * @author Meritoo * @copyright Meritoo @@ -173,7 +171,6 @@ trait BaseTestCaseTrait * @param int $requiredArgumentsCount (optional) Expected count/amount of required arguments * of the verified method * @throws UnknownOopVisibilityTypeException - * @throws ReflectionException * * Attention. 2nd argument, the $method, may be: * - string - name of the method @@ -230,8 +227,6 @@ trait BaseTestCaseTrait * @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 ReflectionException - * @throws UnknownOopVisibilityTypeException */ protected static function assertConstructorVisibilityAndArguments( $classNamespace, @@ -245,14 +240,19 @@ trait BaseTestCaseTrait $reflection = new ReflectionClass($classNamespace); $method = $reflection->getConstructor(); - static::assertMethodVisibilityAndArguments($classNamespace, $method, $visibilityType, $argumentsCount, $requiredArgumentsCount); + static::assertMethodVisibilityAndArguments( + $classNamespace, + $method, + $visibilityType, + $argumentsCount, + $requiredArgumentsCount + ); } /** * Asserts that class with given namespace has no constructor * * @param string $classNamespace Namespace of class that contains constructor to verify - * @throws ReflectionException */ protected static function assertHasNoConstructor($classNamespace) { diff --git a/src/Type/Base/BaseType.php b/src/Type/Base/BaseType.php index 73ec524..ec8dafa 100644 --- a/src/Type/Base/BaseType.php +++ b/src/Type/Base/BaseType.php @@ -43,7 +43,7 @@ abstract class BaseType /** * Returns information if given type is correct * - * @param string $type The type to check + * @param mixed $type The type to check * @return bool */ public function isCorrectType($type) diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index 40b76db..99293eb 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -64,8 +64,7 @@ class Date const DATE_DIFFERENCE_UNIT_YEARS = 'years'; /** - * Returns start and end date for given period. - * The dates are returned in an array with indexes 'start' and 'end'. + * 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 @@ -531,11 +530,15 @@ class Date /** * Returns random date based on given start date * - * @param DateTime $startDate The start date. Start of the random date. - * @param int $start (optional) Start of random partition - * @param int $end (optional) End of random partition + * @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. + * with next, iterated value. If not provided, "P%sD" will be used (default + * behaviour). * @throws Exception * @return DateTime */ @@ -569,10 +572,11 @@ class Date * @param mixed $value The value which maybe is a date * @param bool $allowCompoundFormats (optional) If is set to true, the compound formats used to create an * instance of DateTime class are allowed (e.g. "now", "last day of next - * month", "yyyy"). Otherwise - not and every incorrect value is refused. + * month", "yyyy"). Otherwise - not and every incorrect value is refused + * (default behaviour). * @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. + * "2015-01-01 10:00" value. Default: "Y-m-d". * @return DateTime|bool */ public static function getDateTime($value, $allowCompoundFormats = false, $dateFormat = 'Y-m-d') diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index b03a0bd..c3fbafe 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -662,7 +662,7 @@ class Reflection } /** - * Sets value of given property + * Sets value of given property in given object * * @param mixed $object Object that should contains given property * @param string $property Name of the property @@ -692,4 +692,25 @@ class Reflection $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) + { + /* + * No properties? + * Nothing to do + */ + if (empty($propertiesValues)) { + return; + } + + foreach ($propertiesValues as $property => $value) { + static::setPropertyValue($object, $property, $value); + } + } } diff --git a/src/Utilities/Repository.php b/src/Utilities/Repository.php index fbc8d12..32dc95c 100644 --- a/src/Utilities/Repository.php +++ b/src/Utilities/Repository.php @@ -177,10 +177,13 @@ class Repository $direction = 'ASC' ) { $alias = 'qb'; + $queryBuilder = $repository->createQueryBuilder($alias); - return $repository - ->createQueryBuilder($alias) - ->orderBy(sprintf('%s.%s', $alias, $property), $direction); + if (empty($property)) { + return $queryBuilder; + } + + return $queryBuilder->orderBy(sprintf('%s.%s', $alias, $property), $direction); } /** diff --git a/tests/Resources/var/cache/.gitkeep b/tests/Resources/var/cache/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/Resources/var/log/.gitkeep b/tests/Resources/var/log/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/Resources/var/sessions/.gitkeep b/tests/Resources/var/sessions/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 69ce170..8763716 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -82,8 +82,15 @@ class ReflectionTest extends BaseTestCase * 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('SecurityBundle', Reflection::getClassName('Symfony\Bundle\SecurityBundle\SecurityBundle', true)); + self::assertEquals( + 'Symfony\Bundle\SecurityBundle\SecurityBundle', + Reflection::getClassName('Symfony\Bundle\SecurityBundle\SecurityBundle') + ); + + self::assertEquals( + 'SecurityBundle', + Reflection::getClassName('Symfony\Bundle\SecurityBundle\SecurityBundle', true) + ); } } @@ -115,7 +122,10 @@ class ReflectionTest extends BaseTestCase * 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( + 'Symfony\Bundle\SecurityBundle', + Reflection::getClassNamespace('Symfony\Bundle\SecurityBundle\SecurityBundle') + ); } } @@ -183,11 +193,11 @@ class ReflectionTest extends BaseTestCase public function testGetMethods() { - self::assertEquals(1, count(Reflection::getMethods(B::class, true))); - self::assertEquals(3, count(Reflection::getMethods(B::class))); - self::assertEquals(2, count(Reflection::getMethods(A::class))); - self::assertEquals(2, count(Reflection::getMethods(C::class, true))); - self::assertEquals(5, count(Reflection::getMethods(C::class))); + 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)); } /** @@ -235,9 +245,20 @@ class ReflectionTest extends BaseTestCase public function testGetPropertiesUsingFilter() { - self::assertCount(1, Reflection::getProperties(B::class, ReflectionProperty::IS_PROTECTED)); - self::assertCount(0, Reflection::getProperties(B::class, ReflectionProperty::IS_PRIVATE)); - self::assertCount(1, Reflection::getProperties(B::class, ReflectionProperty::IS_PRIVATE, true)); + self::assertCount( + 1, + Reflection::getProperties(B::class, ReflectionProperty::IS_PROTECTED) + ); + + self::assertCount( + 0, + Reflection::getProperties(B::class, ReflectionProperty::IS_PRIVATE) + ); + + self::assertCount( + 1, + Reflection::getProperties(B::class, ReflectionProperty::IS_PRIVATE, true) + ); } public function testGetPropertiesWithParents() @@ -484,9 +505,7 @@ class ReflectionTest extends BaseTestCase public function testSetPropertyValueUsingNotExistingProperty($object, $property) { $this->setExpectedException(NotExistingPropertyException::class); - - $object = new \stdClass(); - Reflection::setPropertyValue($object, 'test', 'test test test'); + Reflection::setPropertyValue($object, $property, 'test test test'); } /** @@ -506,6 +525,43 @@ class ReflectionTest extends BaseTestCase static::assertSame($newValue, $value); } + public function testSetPropertiesValuesWithoutProperties() + { + $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 + * + * @dataProvider provideObjectAndNotExistingProperties + */ + public function testSetPropertiesValuesUsingNotExistingProperties($object, array $propertiesValues) + { + $this->setExpectedException(NotExistingPropertyException::class); + Reflection::setPropertiesValues($object, $propertiesValues); + } + + /** + * @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 provideObjectAndPropertiesValues + */ + public function testSetPropertiesValues($object, array $propertiesValues) + { + Reflection::setPropertiesValues($object, $propertiesValues); + + foreach ($propertiesValues as $property => $value) { + $realValue = Reflection::getPropertyValue($object, $property); + static::assertSame($value, $realValue); + } + } + /** * Provides invalid class and trait * @@ -588,4 +644,104 @@ class ReflectionTest extends BaseTestCase 'Smith', ]; } + + /** + * Provides object and not existing properties + * + * @return Generator + */ + public function provideObjectAndNotExistingProperties() + { + yield[ + new \stdClass(), + [ + 'test' => 1, + ], + ]; + + yield[ + new A(), + [ + 'test' => 2, + ], + ]; + + yield[ + new B(), + [ + 'firstName' => '', + ], + ]; + } + + /** + * Provides object and its new values of properties + * + * @return Generator + */ + public function provideObjectAndPropertiesValues() + { + 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' + ), + [ + 'gInstance' => new G(), + ], + ]; + + yield[ + new F( + 123, + 'New York', + 'USA', + 'UnKnown', + 'Mary', + 'Brown' + ), + [ + 'country' => 'Canada', + 'accountBalance' => 456, + ], + ]; + } } diff --git a/tests/Utilities/RepositoryTest.php b/tests/Utilities/RepositoryTest.php index aafeadb..0ccedd4 100644 --- a/tests/Utilities/RepositoryTest.php +++ b/tests/Utilities/RepositoryTest.php @@ -8,6 +8,10 @@ namespace Meritoo\Common\Test\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; use Meritoo\Common\Test\Utilities\Repository\Sortable; @@ -160,7 +164,7 @@ class RepositoryTest extends BaseTestCase /** * @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. + * @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 @@ -170,12 +174,122 @@ class RepositoryTest extends BaseTestCase static::assertEquals($expected, Repository::getExtremePosition($items, $max)); } - public function testGetExtremePositionUsingObjects() + /** + * @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::assertEquals($expected, Repository::getExtremePosition($items, $max)); } - public function testGetEntityOrderedQueryBuilder() + /** + * @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::assertEquals($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::assertEquals($expected, Repository::getExtremePosition($items, $max)); + } + + public function testGetEntityOrderedQueryBuilderUsingDefaults() + { + $entityManager = $this->getMock(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'); + + /* @var OrderBy $orderBy */ + $orderBy = $orderDQLPart[0]; + + static::assertInstanceOf(QueryBuilder::class, $queryBuilder); + static::assertArraySubset(['qb'], $queryBuilder->getRootAliases()); + 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->getMock(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'); + + static::assertInstanceOf(QueryBuilder::class, $queryBuilder); + static::assertArraySubset(['qb'], $queryBuilder->getRootAliases()); + static::assertSame([], $selectDQLPart); + static::assertNull($whereDQLPart); + + if (empty($property)) { + static::assertSame([], $orderDQLPart); + } else { + /* @var OrderBy $orderBy */ + $orderBy = $orderDQLPart[0]; + + static::assertSame([$expectedOrderBy], $orderBy->getParts()); + } } /** @@ -581,7 +695,7 @@ class RepositoryTest extends BaseTestCase [], ], true, - 1, + 2, ]; yield[ @@ -596,7 +710,125 @@ class RepositoryTest extends BaseTestCase [], ], false, - 2, + 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', ]; } }