├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── composer.json └── src ├── ArrayAssertions.php ├── CountryAssertions.php ├── EmailAssertions.php ├── GeographicAssertions.php ├── HashidAssertions.php ├── LanguageAssertions.php ├── Laravel ├── BladeAssertions.php ├── CollectionAssertions.php ├── HashidAssertions.php └── ModelAssertions.php ├── NullableTypeAssertions.php ├── PathAssertions.php ├── PhoneNumberAssertions.php ├── StringLengthAssertions.php ├── UrlAssertions.php └── UuidAssertions.php /.gitattributes: -------------------------------------------------------------------------------- 1 | /.github export-ignore 2 | /.styleci.yml export-ignore 3 | /phpunit.xml.dist export-ignore 4 | /tests export-ignore -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /composer.lock 3 | /.phpunit.result.cache -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Astrotomic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHPUnit Assertions 2 | 3 | [![Latest Version](http://img.shields.io/packagist/v/astrotomic/phpunit-assertions.svg?label=Release&style=for-the-badge)](https://packagist.org/packages/astrotomic/phpunit-assertions) 4 | [![MIT License](https://img.shields.io/github/license/Astrotomic/phpunit-assertions.svg?label=License&color=blue&style=for-the-badge)](https://github.com/Astrotomic/phpunit-assertions/blob/master/LICENSE) 5 | [![Offset Earth](https://img.shields.io/badge/Treeware-%F0%9F%8C%B3-green?style=for-the-badge)](https://forest.astrotomic.info) 6 | [![Larabelles](https://img.shields.io/badge/Larabelles-%F0%9F%A6%84-lightpink?style=for-the-badge)](https://larabelles.com) 7 | 8 | [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/Astrotomic/phpunit-assertions/phpunit.yml?style=flat-square&logoColor=white&logo=github&label=Tests)](https://github.com/Astrotomic/phpunit-assertions/actions?query=workflow%3Aphpunit) 9 | [![Total Downloads](https://img.shields.io/packagist/dt/astrotomic/phpunit-assertions.svg?label=Downloads&style=flat-square)](https://packagist.org/packages/astrotomic/phpunit-assertions) 10 | [![Trees](https://img.shields.io/ecologi/trees/astrotomic?style=flat-square)](https://forest.astrotomic.info) 11 | [![Carbon](https://img.shields.io/ecologi/carbon/astrotomic?style=flat-square)](https://forest.astrotomic.info) 12 | 13 | This package provides a set of common [PHPUnit](https://phpunit.de/) custom assertions. 14 | Some require optional packages - check the `composer.json[suggest]` section for more details. 15 | 16 | ## Installation 17 | 18 | ```bash 19 | composer require --dev astrotomic/phpunit-assertions 20 | ``` 21 | 22 | ## Usage 23 | 24 | Even if all assertions are in `trait`s I highly recommend you to don't `use` these traits in your test classes. 25 | Instead you can access all assertions as static methods on the traits. 26 | 27 | ```php 28 | \Astrotomic\PhpunitAssertions\StringLengthAssertions::assertSame(10, 'Astrotomic'); 29 | ``` 30 | 31 | This will prevent any method name conflicts with core, your custom or other trait assertions. 32 | 33 | ## Assertions 34 | 35 | ### Array 36 | 37 | ```php 38 | \Astrotomic\PhpunitAssertions\ArrayAssertions::assertIndexed(['foo', 'bar']); 39 | \Astrotomic\PhpunitAssertions\ArrayAssertions::assertAssociative(['foo' => 'bar']); 40 | \Astrotomic\PhpunitAssertions\ArrayAssertions::assertEquals(['foo', 'bar'], ['bar', 'foo']); 41 | \Astrotomic\PhpunitAssertions\ArrayAssertions::assertSubset(['foo' => 'bar'], ['baz' => 'foo', 'foo' => 'bar']); 42 | \Astrotomic\PhpunitAssertions\ArrayAssertions::assertContainsAll(['foo', 'bar'], ['baz', 'foo', 'lorem', 'ipsum', 'bar']); 43 | ``` 44 | 45 | ### Country 46 | 47 | `composer require --dev league/iso3166:^3.0` 48 | 49 | ```php 50 | \Astrotomic\PhpunitAssertions\CountryAssertions::assertName('Germany'); 51 | \Astrotomic\PhpunitAssertions\CountryAssertions::assertAlpha2('DE'); 52 | \Astrotomic\PhpunitAssertions\CountryAssertions::assertAlpha3('DEU'); 53 | \Astrotomic\PhpunitAssertions\CountryAssertions::assertNumeric('276'); 54 | ``` 55 | 56 | ### Email 57 | 58 | `composer require --dev egulias/email-validator:^3.0` 59 | 60 | ```php 61 | \Astrotomic\PhpunitAssertions\EmailAssertions::assertValidLoose('gummibeer@astrotomic.info'); 62 | \Astrotomic\PhpunitAssertions\EmailAssertions::assertValidStrict('gummibeer@astrotomic.info'); 63 | \Astrotomic\PhpunitAssertions\EmailAssertions::assertDomain('astrotomic.info', 'gummibeer@astrotomic.info'); 64 | \Astrotomic\PhpunitAssertions\EmailAssertions::assertLocalPart('gummibeer', 'gummibeer@astrotomic.info'); 65 | \Astrotomic\PhpunitAssertions\EmailAssertions::assertPlusMailbox('gummibeer', 'gummibeer+news@astrotomic.info'); 66 | \Astrotomic\PhpunitAssertions\EmailAssertions::assertPlusAlias('news', 'gummibeer+news@astrotomic.info'); 67 | ``` 68 | 69 | ### Geographic 70 | 71 | ```php 72 | \Astrotomic\PhpunitAssertions\GeographicAssertions::assertLatitude(53.551085); 73 | \Astrotomic\PhpunitAssertions\GeographicAssertions::assertLongitude(9.993682); 74 | \Astrotomic\PhpunitAssertions\GeographicAssertions::assertCoordinates([ 75 | 'lat' => 53.551085, 76 | 'lng' => 9.993682, 77 | ]); 78 | ``` 79 | 80 | ### HashID 81 | 82 | `composer require --dev hashids/hashids:^4.0` 83 | 84 | ```php 85 | \Astrotomic\PhpunitAssertions\HashidAssertions::assertHashIds('3kTMd', 2, 'this is my salt'); 86 | \Astrotomic\PhpunitAssertions\HashidAssertions::assertHashId('yr8', 'this is my salt'); 87 | ``` 88 | 89 | ### Language 90 | 91 | `composer require --dev astrotomic/iso639:^1.0` 92 | 93 | ```php 94 | \Astrotomic\PhpunitAssertions\LanguageAssertions::assertName('German'); 95 | \Astrotomic\PhpunitAssertions\LanguageAssertions::assertAlpha2('de'); 96 | ``` 97 | 98 | ### Nullable Type 99 | 100 | ```php 101 | \Astrotomic\PhpunitAssertions\NullableTypeAssertions::assertIsNullableString('Astrotomic'); 102 | \Astrotomic\PhpunitAssertions\NullableTypeAssertions::assertIsNullableInt(42); 103 | \Astrotomic\PhpunitAssertions\NullableTypeAssertions::assertIsNullableFloat(42.5); 104 | \Astrotomic\PhpunitAssertions\NullableTypeAssertions::assertIsNullableArray(['Astrotomic' => 'Gummibeer']); 105 | \Astrotomic\PhpunitAssertions\NullableTypeAssertions::assertIsNullableBool(true); 106 | ``` 107 | 108 | ### Phone Number 109 | 110 | `composer require --dev giggsey/libphonenumber-for-php:^8.12` 111 | 112 | ```php 113 | \Astrotomic\PhpunitAssertions\PhoneNumberAssertions::assertE164('+498001110550'); 114 | \Astrotomic\PhpunitAssertions\PhoneNumberAssertions::assertValid('+49 800 - 111 0 550'); 115 | \Astrotomic\PhpunitAssertions\PhoneNumberAssertions::assertValidForRegion('+49 800 - 111 0 550', 'DE'); 116 | ``` 117 | 118 | ### String 119 | 120 | ```php 121 | \Astrotomic\PhpunitAssertions\StringLengthAssertions::assertSame(10, 'Astrotomic'); 122 | \Astrotomic\PhpunitAssertions\StringLengthAssertions::assertNotSame(8, 'Astrotomic'); 123 | \Astrotomic\PhpunitAssertions\StringLengthAssertions::assertLessThan(11, 'Astrotomic'); 124 | \Astrotomic\PhpunitAssertions\StringLengthAssertions::assertLessThanOrEqual(10, 'Astrotomic'); 125 | \Astrotomic\PhpunitAssertions\StringLengthAssertions::assertGreaterThan(9, 'Astrotomic'); 126 | \Astrotomic\PhpunitAssertions\StringLengthAssertions::assertGreaterThanOrEqual(10, 'Astrotomic'); 127 | ``` 128 | 129 | ### URL 130 | 131 | ```php 132 | \Astrotomic\PhpunitAssertions\UrlAssertions::assertValidLoose('https://astrotomic.info'); 133 | \Astrotomic\PhpunitAssertions\UrlAssertions::assertScheme('https', 'https://astrotomic.info'); 134 | \Astrotomic\PhpunitAssertions\UrlAssertions::assertHost('astrotomic.info', 'https://astrotomic.info'); 135 | \Astrotomic\PhpunitAssertions\UrlAssertions::assertPath('/contributor/gummibeer/', 'https://astrotomic.info/contributor/gummibeer/'); 136 | \Astrotomic\PhpunitAssertions\UrlAssertions::assertQuery(['_' => '123', 'q' => 'search'], 'https://astrotomic.info?q=search&_=123'); 137 | \Astrotomic\PhpunitAssertions\UrlAssertions::assertComponent('gummibeer', 'https://gummibeer@astrotomic.info', PHP_URL_USER); 138 | ``` 139 | 140 | ### Path 141 | 142 | ```php 143 | \Astrotomic\PhpunitAssertions\PathAssertions::assertDirname('/foo/bar', '/foo/bar/image.jpg'); 144 | \Astrotomic\PhpunitAssertions\PathAssertions::assertBasename('image.jpg', '/foo/bar/image.jpg'); 145 | \Astrotomic\PhpunitAssertions\PathAssertions::assertFilename('image', '/foo/bar/image.jpg'); 146 | \Astrotomic\PhpunitAssertions\PathAssertions::assertExtension('jpg', '/foo/bar/image.jpg'); 147 | ``` 148 | 149 | ### UUID 150 | 151 | `composer require --dev ramsey/uuid:^4.0` 152 | 153 | ```php 154 | \Astrotomic\PhpunitAssertions\UuidAssertions::assertUuid('52d08e38-ad24-4960-af02-22e0f7e0db8d'); 155 | ``` 156 | 157 | ## Laravel Assertions 158 | 159 | ### Collection 160 | 161 | ```php 162 | \Astrotomic\PhpunitAssertions\Laravel\CollectionAssertions::assertContains($collection, 'Astrotomic'); 163 | ``` 164 | 165 | ### HashID 166 | 167 | `composer require --dev vinkla/hashids:^9.0` 168 | 169 | ```php 170 | \Astrotomic\PhpunitAssertions\Laravel\HashidAssertions::assertHashIds('3kTMd', 2); 171 | \Astrotomic\PhpunitAssertions\Laravel\HashidAssertions::assertHashId('yr8'); 172 | ``` 173 | 174 | ### Model 175 | 176 | ```php 177 | \Astrotomic\PhpunitAssertions\Laravel\ModelAssertions::assertExists($model); 178 | \Astrotomic\PhpunitAssertions\Laravel\ModelAssertions::assertSame($model, \App\Models\User::first()); 179 | \Astrotomic\PhpunitAssertions\Laravel\ModelAssertions::assertRelated($post, 'comments', $comment); 180 | \Astrotomic\PhpunitAssertions\Laravel\ModelAssertions::assertRelated( 181 | $post, 182 | 'comments', 183 | \App\Models\Comment::class, 184 | \Illuminate\Database\Eloquent\Relations\HasMany::class 185 | ); 186 | ``` 187 | 188 | ### Blade 189 | 190 | `composer require --dev gajus/dindent:^2.0` 191 | 192 | ```php 193 | \Astrotomic\PhpunitAssertions\Laravel\BladeAssertions::assertRenderEquals( 194 | "

Price: 99.99 €

", 195 | '

Price: {{ number_format($price, 2) }} €

', 196 | ['price' => 99.99] 197 | ); 198 | ``` 199 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "astrotomic/phpunit-assertions", 3 | "description": "Set of common PHPUnit custom assertions.", 4 | "license": "MIT", 5 | "keywords": [ 6 | "phpunit", 7 | "assertions" 8 | ], 9 | "authors": [ 10 | { 11 | "name": "Tom Witkowski", 12 | "email": "gummibeer@astrotomic.info", 13 | "homepage": "https://astrotomic.info", 14 | "role": "Developer" 15 | } 16 | ], 17 | "homepage": "https://github.com/Astrotomic/phpunit-assertions", 18 | "require": { 19 | "php": "^8.0", 20 | "phpunit/phpunit": "^9.1 || ^10.0 || ^11.0" 21 | }, 22 | "require-dev": { 23 | "astrotomic/iso639": "^1.0", 24 | "egulias/email-validator": "^2.1 || ^3.0 || ^4.0", 25 | "gajus/dindent": "^2.0", 26 | "giggsey/libphonenumber-for-php": "^8.12 || ^9.0", 27 | "hashids/hashids": "^4.0 || ^5.0", 28 | "laravel/pint": "^1.0", 29 | "league/iso3166": "^2.1 || ^3.0 || ^4.0", 30 | "orchestra/testbench": "^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0", 31 | "ramsey/uuid": "^4.0", 32 | "vinkla/hashids": "^9.0 || ^10.0 || ^11.0 || ^12.0 || ^13.0" 33 | }, 34 | "suggest": { 35 | "astrotomic/iso639": "\\Astrotomic\\PhpunitAssertions\\LanguageAssertions (^1.0)", 36 | "egulias/email-validator": "\\Astrotomic\\PhpunitAssertions\\EmailAssertions (^2.1 || ^3.0 || ^4.0)", 37 | "gajus/dindent": "\\Astrotomic\\PhpunitAssertions\\Laravel\\BladeAssertions (^2.0)", 38 | "giggsey/libphonenumber-for-php": "\\Astrotomic\\PhpunitAssertions\\PhoneNumberAssertions (^8.12 || ^9.0)", 39 | "hashids/hashids": "\\Astrotomic\\PhpunitAssertions\\HashidAssertions (^4.0 || ^5.0)", 40 | "league/iso3166": "\\Astrotomic\\PhpunitAssertions\\CountryAssertions (^2.1 || ^3.0 || ^4.0)", 41 | "ramsey/uuid": "\\Astrotomic\\PhpunitAssertions\\UuidAssertions (^4.0)", 42 | "vinkla/hashids": "\\Astrotomic\\PhpunitAssertions\\Laravel\\HashidAssertions (^9.0 || ^10.0 || ^11.0 || ^12.0 || ^13.0)" 43 | }, 44 | "minimum-stability": "dev", 45 | "prefer-stable": true, 46 | "autoload": { 47 | "psr-4": { 48 | "Astrotomic\\PhpunitAssertions\\": "src" 49 | } 50 | }, 51 | "autoload-dev": { 52 | "psr-4": { 53 | "Astrotomic\\PhpunitAssertions\\Tests\\": "tests" 54 | } 55 | }, 56 | "config": { 57 | "sort-packages": true 58 | }, 59 | "scripts": { 60 | "post-autoload-dump": [ 61 | "@composer validate --strict --ansi --no-interaction --quiet", 62 | "@composer normalize --ansi --no-interaction --quiet", 63 | "@composer thanks --ansi --no-interaction --quiet" 64 | ], 65 | "fix": "@php vendor/bin/pint", 66 | "normalize": "echo 'composer global require ergebnis/composer-normalize'", 67 | "test": "@php vendor/bin/phpunit", 68 | "thanks": "echo 'composer global require symfony/thanks'" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/ArrayAssertions.php: -------------------------------------------------------------------------------- 1 | $value) { 47 | PHPUnit::assertArrayHasKey($key, $actual); 48 | PHPUnit::assertEquals($value, $actual[$key]); 49 | } 50 | } 51 | 52 | public static function assertContainsAll(array $expected, $actual): void 53 | { 54 | PHPUnit::assertIsArray($actual); 55 | 56 | foreach ($expected as $value) { 57 | PHPUnit::assertContains($value, $actual); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/CountryAssertions.php: -------------------------------------------------------------------------------- 1 | name($actual); 14 | PHPUnit::assertIsArray($country); 15 | } 16 | 17 | public static function assertAlpha2($actual): void 18 | { 19 | PHPUnit::assertIsString($actual); 20 | StringLengthAssertions::assertSame(2, $actual); 21 | $country = (new ISO3166)->alpha2($actual); 22 | PHPUnit::assertIsArray($country); 23 | } 24 | 25 | public static function assertAlpha3($actual): void 26 | { 27 | PHPUnit::assertIsString($actual); 28 | StringLengthAssertions::assertSame(3, $actual); 29 | $country = (new ISO3166)->alpha3($actual); 30 | PHPUnit::assertIsArray($country); 31 | } 32 | 33 | public static function assertNumeric($actual): void 34 | { 35 | PHPUnit::assertIsString($actual); 36 | StringLengthAssertions::assertSame(3, $actual); 37 | $country = (new ISO3166)->numeric($actual); 38 | PHPUnit::assertIsArray($country); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/EmailAssertions.php: -------------------------------------------------------------------------------- 1 | isValid($actual, new RFCValidation)); 21 | } 22 | 23 | public static function assertDomain(string $expected, $actual): void 24 | { 25 | PHPUnit::assertIsString($actual); 26 | [, $domain] = explode('@', $actual, 2); 27 | PHPUnit::assertSame($expected, $domain); 28 | } 29 | 30 | public static function assertLocalPart(string $expected, $actual): void 31 | { 32 | PHPUnit::assertIsString($actual); 33 | [$localPart] = explode('@', $actual, 2); 34 | PHPUnit::assertSame($expected, $localPart); 35 | } 36 | 37 | public static function assertPlusMailbox(string $expected, $actual): void 38 | { 39 | PHPUnit::assertIsString($actual); 40 | [$localPart] = explode('@', $actual, 2); 41 | [$mailbox] = explode('+', $localPart, 2); 42 | PHPUnit::assertSame($expected, $mailbox); 43 | } 44 | 45 | public static function assertPlusAlias(string $expected, $actual): void 46 | { 47 | PHPUnit::assertIsString($actual); 48 | [$localPart] = explode('@', $actual, 2); 49 | [, $alias] = explode('+', $localPart, 2); 50 | PHPUnit::assertSame($expected, $alias); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/GeographicAssertions.php: -------------------------------------------------------------------------------- 1 | decode($actual); 26 | PHPUnit::assertIsArray($ids); 27 | 28 | if ($count !== null) { 29 | PHPUnit::assertCount($count, $ids); 30 | } 31 | 32 | foreach ($ids as $id) { 33 | PHPUnit::assertIsInt($id); 34 | PHPUnit::assertGreaterThanOrEqual(0, $id); 35 | } 36 | } 37 | 38 | public static function assertHashId( 39 | $actual, 40 | ?string $salt = null, 41 | int $minHashLength = 0, 42 | ?string $alphabet = null 43 | ): void { 44 | self::assertHashIds($actual, 1, $salt, $minHashLength, $alphabet); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/LanguageAssertions.php: -------------------------------------------------------------------------------- 1 | name($actual); 14 | PHPUnit::assertIsArray($language); 15 | } 16 | 17 | public static function assertAlpha2($actual): void 18 | { 19 | PHPUnit::assertIsString($actual); 20 | StringLengthAssertions::assertSame(2, $actual); 21 | $language = (new ISO639)->alpha2($actual); 22 | PHPUnit::assertIsArray($language); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Laravel/BladeAssertions.php: -------------------------------------------------------------------------------- 1 | indent($expected), 18 | $indenter->indent((string) self::render($template, $data)) 19 | ); 20 | } 21 | 22 | protected static function render(string $template, array $data = []): string 23 | { 24 | $tempDirectory = sys_get_temp_dir(); 25 | 26 | if (! in_array($tempDirectory, View::getFinder()->getPaths())) { 27 | View::addLocation($tempDirectory); 28 | } 29 | 30 | $tempFile = tempnam($tempDirectory, 'laravel-blade').'.blade.php'; 31 | 32 | file_put_contents($tempFile, $template); 33 | 34 | return View::make(Str::before(basename($tempFile), '.blade.php'), $data)->render(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Laravel/CollectionAssertions.php: -------------------------------------------------------------------------------- 1 | contains($expected)); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Laravel/HashidAssertions.php: -------------------------------------------------------------------------------- 1 | getTable(); 22 | $connection = $model->getConnectionName(); 23 | $data = [ 24 | $model->getKeyName() => $model->getKey(), 25 | ]; 26 | } 27 | 28 | PHPUnit::assertThat( 29 | $table, 30 | new HasInDatabase(DB::connection($connection), $data) 31 | ); 32 | } 33 | 34 | /** 35 | * @param \Illuminate\Database\Eloquent\Model|mixed $actual 36 | */ 37 | public static function assertSame(Model $expected, $actual): void 38 | { 39 | PHPUnit::assertInstanceOf(get_class($expected), $actual); 40 | PHPUnit::assertSame($expected->exists, $actual->exists); 41 | PHPUnit::assertTrue($expected->is($actual)); 42 | } 43 | 44 | /** 45 | * @param string|\Illuminate\Database\Eloquent\Model|mixed $actual 46 | */ 47 | public static function assertRelated(Model $model, string $relation, $actual, ?string $type = null) 48 | { 49 | PHPUnit::assertTrue(method_exists($model, $relation)); 50 | PHPUnit::assertInstanceOf(Relation::class, $model->$relation()); 51 | 52 | if ($type) { 53 | PHPUnit::assertInstanceOf($type, $model->$relation()); 54 | } 55 | 56 | $related = $model->$relation()->getRelated(); 57 | PHPUnit::assertInstanceOf(Model::class, $related); 58 | 59 | if (is_string($actual)) { 60 | PHPUnit::assertInstanceOf($actual, $related); 61 | } else { 62 | PHPUnit::assertInstanceOf(get_class($actual), $related); 63 | self::assertSame( 64 | $actual, 65 | $model->$relation()->whereKey($actual->getKey())->first() 66 | ); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/NullableTypeAssertions.php: -------------------------------------------------------------------------------- 1 | isValidNumber( 23 | self::getPhoneNumber($actual) 24 | ) 25 | ); 26 | } 27 | 28 | public static function assertValidForRegion($actual, string $regionCode): void 29 | { 30 | PHPUnit::assertTrue( 31 | PhoneNumberUtil::getInstance()->isValidNumberForRegion( 32 | self::getPhoneNumber($actual), 33 | $regionCode 34 | ), 35 | $regionCode.' // '.$actual 36 | ); 37 | } 38 | 39 | protected static function getPhoneNumber($actual): PhoneNumber 40 | { 41 | if (is_string($actual)) { 42 | try { 43 | $actual = PhoneNumberUtil::getInstance()->parse($actual); 44 | } catch (Throwable $ex) { 45 | } 46 | } 47 | 48 | PHPUnit::assertInstanceOf(PhoneNumber::class, $actual); 49 | 50 | return $actual; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/StringLengthAssertions.php: -------------------------------------------------------------------------------- 1 |