├── .github └── workflows │ └── main.yml ├── LICENSE ├── composer.json └── src └── Codeception └── Module ├── AbstractAsserts.php └── Asserts.php /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | tests: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | matrix: 11 | php: [8.2, 8.3, 8.4] 12 | 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v4 16 | 17 | - name: Setup PHP 18 | uses: shivammathur/setup-php@v2 19 | with: 20 | php-version: ${{ matrix.php }} 21 | coverage: none 22 | tools: phpstan, phpcs 23 | 24 | - name: Validate composer.json and composer.lock 25 | run: composer validate 26 | 27 | - name: Install dependencies 28 | run: composer install --prefer-dist --no-progress --no-interaction --no-suggest 29 | 30 | - name: Run PHPStan 31 | run: phpstan analyse src 32 | 33 | - name: Run PHPCS 34 | run: phpcs --standard=PSR12 src 35 | 36 | - name: Run test suite 37 | run: php vendor/bin/codecept run 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011 Michael Bodnarchuk and contributors 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codeception/module-asserts", 3 | "description": "Codeception module containing various assertions", 4 | "license": "MIT", 5 | "type": "library", 6 | "keywords": [ 7 | "codeception", 8 | "asserts", 9 | "assertions" 10 | ], 11 | "authors": [ 12 | { 13 | "name": "Michael Bodnarchuk" 14 | }, 15 | { 16 | "name": "Gintautas Miselis" 17 | }, 18 | { 19 | "name": "Gustavo Nieves", 20 | "homepage": "https://medium.com/@ganieves" 21 | } 22 | ], 23 | "homepage": "https://codeception.com/", 24 | "require": { 25 | "php": "^8.2", 26 | "codeception/codeception": "*@dev", 27 | "codeception/lib-asserts": "^2.2" 28 | }, 29 | "conflict": { 30 | "codeception/codeception": "<5.0" 31 | }, 32 | "minimum-stability": "dev", 33 | "autoload": { 34 | "classmap": [ 35 | "src/" 36 | ] 37 | }, 38 | "config": { 39 | "classmap-authoritative": true 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Codeception/Module/AbstractAsserts.php: -------------------------------------------------------------------------------- 1 | expectThrowable(MyThrowable::class, function() { 23 | * $this->doSomethingBad(); 24 | * }); 25 | * 26 | * $I->expectThrowable(new MyException(), function() { 27 | * $this->doSomethingBad(); 28 | * }); 29 | * ``` 30 | * 31 | * If you want to check message or throwable code, you can pass them with throwable instance: 32 | * ```php 33 | * expectThrowable(new MyError("Don't do bad things"), function() { 36 | * $this->doSomethingBad(); 37 | * }); 38 | * ``` 39 | */ 40 | public function expectThrowable(string|Throwable $throwable, callable $callback): void 41 | { 42 | if (is_object($throwable)) { 43 | $class = get_class($throwable); 44 | $msg = $throwable->getMessage(); 45 | $code = (int) $throwable->getCode(); 46 | } else { 47 | $class = $throwable; 48 | $msg = null; 49 | $code = null; 50 | } 51 | 52 | try { 53 | $callback(); 54 | } catch (Throwable $t) { 55 | $this->checkThrowable($t, $class, $msg, $code); 56 | return; 57 | } 58 | 59 | $this->fail("Expected throwable of class '{$class}' to be thrown, but nothing was caught"); 60 | } 61 | 62 | /** 63 | * Check if the given throwable matches the expected data, 64 | * fail (throws an exception) if it does not. 65 | */ 66 | protected function checkThrowable( 67 | Throwable $throwable, 68 | string $expectedClass, 69 | ?string $expectedMsg, 70 | int|null $expectedCode = null 71 | ): void { 72 | if (!($throwable instanceof $expectedClass)) { 73 | $this->fail(sprintf( 74 | "Exception of class '%s' expected to be thrown, but class '%s' was caught", 75 | $expectedClass, 76 | get_debug_type($throwable) 77 | )); 78 | } 79 | 80 | if (null !== $expectedMsg && $throwable->getMessage() !== $expectedMsg) { 81 | $this->fail(sprintf( 82 | "Exception of class '%s' expected to have message '%s', but actual message was '%s'", 83 | $expectedClass, 84 | $expectedMsg, 85 | $throwable->getMessage() 86 | )); 87 | } 88 | 89 | if (null !== $expectedCode && $throwable->getCode() !== $expectedCode) { 90 | $this->fail(sprintf( 91 | "Exception of class '%s' expected to have code '%s', but actual code was '%s'", 92 | $expectedClass, 93 | $expectedCode, 94 | $throwable->getCode() 95 | )); 96 | } 97 | 98 | $this->assertTrue(true); // increment assertion counter 99 | } 100 | } 101 | --------------------------------------------------------------------------------