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); } }