first commit
This commit is contained in:
32
vendor/codeception/stub/.github/workflows/main.yml
vendored
Normal file
32
vendor/codeception/stub/.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches-ignore:
|
||||
- master
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php: [8.1, 8.2, 8.3, 8.4]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
|
||||
- name: Validate composer.json
|
||||
run: composer validate
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer update --prefer-source
|
||||
|
||||
- name: Run test suite
|
||||
run: php vendor/bin/phpunit tests
|
||||
53
vendor/codeception/stub/.github/workflows/release.yml
vendored
Normal file
53
vendor/codeception/stub/.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php: [8.1, 8.2, 8.3, 8.4]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
|
||||
- name: Validate composer.json
|
||||
run: composer validate
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer update --prefer-source
|
||||
|
||||
- name: Run test suite
|
||||
run: php vendor/bin/phpunit tests
|
||||
release:
|
||||
name: Automated release
|
||||
needs: [ tests ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 22
|
||||
- run: >
|
||||
npx
|
||||
-p "@semantic-release/commit-analyzer"
|
||||
-p "@semantic-release/release-notes-generator"
|
||||
-p conventional-changelog-conventionalcommits
|
||||
-p semantic-release
|
||||
-- semantic-release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
permissions:
|
||||
packages: write
|
||||
contents: write
|
||||
pull-requests: write
|
||||
3
vendor/codeception/stub/.gitignore
vendored
Normal file
3
vendor/codeception/stub/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.idea/
|
||||
/vendor/
|
||||
composer.lock
|
||||
11
vendor/codeception/stub/.releaserc.json
vendored
Normal file
11
vendor/codeception/stub/.releaserc.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"tagFormat": "${version}",
|
||||
"branches": ["master"],
|
||||
"plugins": [
|
||||
["@semantic-release/commit-analyzer", {
|
||||
"preset": "conventionalcommits"
|
||||
}],
|
||||
"@semantic-release/release-notes-generator",
|
||||
"@semantic-release/github"
|
||||
]
|
||||
}
|
||||
21
vendor/codeception/stub/LICENSE
vendored
Normal file
21
vendor/codeception/stub/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Codeception
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
89
vendor/codeception/stub/Readme.md
vendored
Normal file
89
vendor/codeception/stub/Readme.md
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
# Codeception\Stub
|
||||
|
||||

|
||||
[](https://packagist.org/packages/codeception/stub)
|
||||
[](https://packagist.org/packages/codeception/stub)
|
||||
[](https://packagist.org/packages/codeception/stub)
|
||||
|
||||
Library on top of PHPUnit's mock builder providing a highly simplified syntax:
|
||||
|
||||
## Reference
|
||||
|
||||
* [Stub](https://github.com/Codeception/Stub/blob/master/docs/Stub.md) - creating stub classes using static methods
|
||||
* [Stub Trait](https://github.com/Codeception/Stub/blob/master/docs/StubTrait.md) - creating stubs and mocks using trait
|
||||
* [Expected](https://github.com/Codeception/Stub/blob/master/docs/Expected.md) - defining expectations for mocks
|
||||
|
||||
## Install
|
||||
|
||||
Enabled by default in Codeception.
|
||||
For PHPUnit install this package:
|
||||
|
||||
```
|
||||
composer require codeception/stub --dev
|
||||
```
|
||||
|
||||
## Stubs
|
||||
|
||||
Stubs can be constructed with `Codeception\Stub` static calls:
|
||||
|
||||
```php
|
||||
<?php
|
||||
// create a stub with find method replaced
|
||||
$userRepository = Stub::make(UserRepository::class, ['find' => new User]);
|
||||
$userRepository->find(1); // => User
|
||||
|
||||
// create a dummy
|
||||
$userRepository = Stub::makeEmpty(UserRepository::class);
|
||||
|
||||
// create a stub with all methods replaced except one
|
||||
$user = Stub::makeEmptyExcept(User::class, 'validate');
|
||||
$user->validate($data);
|
||||
|
||||
// create a stub by calling constructor and replacing a method
|
||||
$user = Stub::construct(User::class, ['name' => 'davert'], ['save' => false]);
|
||||
|
||||
// create a stub by calling constructor with empty methods
|
||||
$user = Stub::constructEmpty(User::class, ['name' => 'davert']);
|
||||
|
||||
// create a stub by calling constructor with empty methods
|
||||
$user = Stub::constructEmptyExcept(User::class, 'getName', ['name' => 'davert']);
|
||||
$user->getName(); // => davert
|
||||
$user->setName('jane'); // => this method is empty
|
||||
$user->getName(); // => davert
|
||||
```
|
||||
|
||||
[See complete reference](https://github.com/Codeception/Stub/blob/master/docs/Stub.md)
|
||||
|
||||
Alternatively, stubs can be created by using [`Codeception\Test\Feature\Stub` trait](https://github.com/Codeception/Stub/blob/master/docs/StubTrait.md):
|
||||
|
||||
```php
|
||||
<?php
|
||||
$this->make(UserRepositry::class);
|
||||
$this->makeEmpty(UserRepositry::class);
|
||||
$this->construct(UserRepositry::class);
|
||||
$this->constructEmpty(UserRepositry::class);
|
||||
// ...
|
||||
```
|
||||
|
||||
## Mocks
|
||||
|
||||
Mocks should be created by including [`Codeception\Test\Feature\Stub` trait](https://github.com/Codeception/Stub/blob/master/docs/StubTrait.md) into a test case.
|
||||
Execution expectation are set with [`Codeception\Stub\Expected`](https://github.com/Codeception/Stub/blob/master/docs/Expected.md):
|
||||
|
||||
```php
|
||||
<?php
|
||||
// find should be never called
|
||||
$userRepository = $this->make(UserRepository::class, [
|
||||
'find' => Codeception\Stub\Expected::never()
|
||||
]);
|
||||
|
||||
// find should be called once and return a new user
|
||||
$userRepository = $this->make(UserRepository::class, [
|
||||
'find' => Codeception\Stub\Expected::once(new User)
|
||||
]);
|
||||
```
|
||||
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
47
vendor/codeception/stub/RoboFile.php
vendored
Normal file
47
vendor/codeception/stub/RoboFile.php
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Robo\Tasks;
|
||||
|
||||
require_once 'vendor/autoload.php';
|
||||
/**
|
||||
* This is project's console commands configuration for Robo task runner.
|
||||
*
|
||||
* @see https://robo.li/
|
||||
*/
|
||||
class RoboFile extends Tasks
|
||||
{
|
||||
protected $docs = [
|
||||
'docs/Stub.md' => 'Codeception\Stub',
|
||||
'docs/Expected.md' => 'Codeception\Stub\Expected',
|
||||
'docs/StubTrait.md' => 'Codeception\Test\Feature\Stub',
|
||||
];
|
||||
|
||||
public function docs()
|
||||
{
|
||||
foreach ($this->docs as $file => $class) {
|
||||
if (!class_exists($class, true) && !trait_exists($class, true)) {
|
||||
throw new Exception('ups');
|
||||
}
|
||||
$this->say("Here goes, $class");
|
||||
$this->taskGenDoc($file)
|
||||
->docClass($class)
|
||||
->filterMethods(function(ReflectionMethod $method) {
|
||||
if ($method->isConstructor() or $method->isDestructor()) return false;
|
||||
if (!$method->isPublic()) return false;
|
||||
if (strpos($method->name, '_') === 0) return false;
|
||||
if (strpos($method->name, 'stub') === 0) return false;
|
||||
return true;
|
||||
})
|
||||
->processMethodDocBlock(
|
||||
function (ReflectionMethod $m, $doc) {
|
||||
$doc = str_replace(array('@since'), array(' * available since version'), $doc);
|
||||
$doc = str_replace(array(' @', "\n@"), array(" * ", "\n * "), $doc);
|
||||
return $doc;
|
||||
})
|
||||
->processProperty(false)
|
||||
->run();
|
||||
}
|
||||
}
|
||||
}
|
||||
22
vendor/codeception/stub/composer.json
vendored
Normal file
22
vendor/codeception/stub/composer.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "codeception/stub",
|
||||
"description":"Flexible Stub wrapper for PHPUnit's Mock Builder",
|
||||
"type": "library",
|
||||
"license":"MIT",
|
||||
"minimum-stability": "dev",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Codeception\\": "src/"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1",
|
||||
"phpunit/phpunit": "^8.4 | ^9.0 | ^10.0 | ^11 | ^12"
|
||||
},
|
||||
"require-dev": {
|
||||
"consolidation/robo": "^3.0"
|
||||
},
|
||||
"conflict": {
|
||||
"codeception/codeception": "<5.0.6"
|
||||
}
|
||||
}
|
||||
120
vendor/codeception/stub/docs/Expected.md
vendored
Normal file
120
vendor/codeception/stub/docs/Expected.md
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
|
||||
## Codeception\Stub\Expected
|
||||
|
||||
|
||||
|
||||
#### *public static* never($params = null)
|
||||
Checks if a method never has been invoked
|
||||
|
||||
If method invoked, it will immediately throw an
|
||||
exception.
|
||||
|
||||
```php
|
||||
<?php
|
||||
use \Codeception\Stub\Expected;
|
||||
|
||||
$user = $this->make('User', [
|
||||
'getName' => Expected::never(),
|
||||
'someMethod' => function() {}
|
||||
]);
|
||||
$user->someMethod();
|
||||
```
|
||||
|
||||
* `param mixed` $params
|
||||
|
||||
#### *public static* once($params = null)
|
||||
Checks if a method has been invoked exactly one
|
||||
time.
|
||||
|
||||
If the number is less or greater it will later be checked in verify() and also throw an
|
||||
exception.
|
||||
|
||||
```php
|
||||
<?php
|
||||
use \Codeception\Stub\Expected;
|
||||
|
||||
$user = $this->make(
|
||||
'User',
|
||||
array(
|
||||
'getName' => Expected::once('Davert'),
|
||||
'someMethod' => function() {}
|
||||
)
|
||||
);
|
||||
$userName = $user->getName();
|
||||
$this->assertEquals('Davert', $userName);
|
||||
```
|
||||
Alternatively, a function can be passed as parameter:
|
||||
|
||||
```php
|
||||
<?php
|
||||
Expected::once(function() { return Faker::name(); });
|
||||
```
|
||||
|
||||
* `param mixed` $params
|
||||
|
||||
#### *public static* atLeastOnce($params = null)
|
||||
Checks if a method has been invoked at least one
|
||||
time.
|
||||
|
||||
If the number of invocations is 0 it will throw an exception in verify.
|
||||
|
||||
```php
|
||||
<?php
|
||||
use \Codeception\Stub\Expected;
|
||||
|
||||
$user = $this->make(
|
||||
'User',
|
||||
array(
|
||||
'getName' => Expected::atLeastOnce('Davert')),
|
||||
'someMethod' => function() {}
|
||||
)
|
||||
);
|
||||
$user->getName();
|
||||
$userName = $user->getName();
|
||||
$this->assertEquals('Davert', $userName);
|
||||
```
|
||||
|
||||
Alternatively, a function can be passed as parameter:
|
||||
|
||||
```php
|
||||
<?php
|
||||
Expected::atLeastOnce(function() { return Faker::name(); });
|
||||
```
|
||||
|
||||
* `param mixed` $params
|
||||
|
||||
#### *public static* exactly($count, $params = null)
|
||||
Checks if a method has been invoked a certain amount
|
||||
of times.
|
||||
If the number of invocations exceeds the value it will immediately throw an
|
||||
exception,
|
||||
If the number is less it will later be checked in verify() and also throw an
|
||||
exception.
|
||||
|
||||
``` php
|
||||
<?php
|
||||
use \Codeception\Stub;
|
||||
use \Codeception\Stub\Expected;
|
||||
|
||||
$user = $this->make(
|
||||
'User',
|
||||
array(
|
||||
'getName' => Expected::exactly(3, 'Davert'),
|
||||
'someMethod' => function() {}
|
||||
)
|
||||
);
|
||||
$user->getName();
|
||||
$user->getName();
|
||||
$userName = $user->getName();
|
||||
$this->assertEquals('Davert', $userName);
|
||||
```
|
||||
Alternatively, a function can be passed as parameter:
|
||||
|
||||
```php
|
||||
<?php
|
||||
Expected::exactly(function() { return Faker::name() });
|
||||
```
|
||||
|
||||
* `param mixed` $params
|
||||
|
||||
|
||||
308
vendor/codeception/stub/docs/Stub.md
vendored
Normal file
308
vendor/codeception/stub/docs/Stub.md
vendored
Normal file
@ -0,0 +1,308 @@
|
||||
|
||||
## Codeception\Stub
|
||||
|
||||
|
||||
|
||||
#### *public static* make($class, array $params = Array ( ) , $testCase = null)
|
||||
Instantiates a class without executing a constructor.
|
||||
Properties and methods can be set as a second parameter.
|
||||
Even protected and private properties can be set.
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::make('User');
|
||||
Stub::make('User', ['name' => 'davert']);
|
||||
```
|
||||
|
||||
Accepts either name of class or object of that class
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::make(new User, ['name' => 'davert']);
|
||||
```
|
||||
|
||||
To replace method provide it's name as a key in second parameter
|
||||
and it's return value or callback function as parameter
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::make('User', ['save' => function () { return true; }]);
|
||||
Stub::make('User', ['save' => true]);
|
||||
```
|
||||
|
||||
**To create a mock, pass current testcase name as last argument:**
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::make('User', [
|
||||
'save' => \Codeception\Stub\Expected::once()
|
||||
], $this);
|
||||
```
|
||||
|
||||
* template RealInstanceType of object
|
||||
* `param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType>` $class - A class to be mocked
|
||||
* `param array` $params - properties and methods to set
|
||||
* `param bool|PHPUnitTestCase` $testCase
|
||||
|
||||
* return PHPUnitMockObject&RealInstanceType - mock
|
||||
* throws RuntimeException when class does not exist
|
||||
* throws Exception
|
||||
|
||||
#### *public static* factory($class, $num = 1, array $params = Array ( ) )
|
||||
Creates $num instances of class through `Stub::make`.
|
||||
|
||||
* `param mixed` $class
|
||||
* throws Exception
|
||||
|
||||
#### *public static* makeEmptyExcept($class, $method, array $params = Array ( ) , $testCase = null)
|
||||
Instantiates class having all methods replaced with dummies except one.
|
||||
Constructor is not triggered.
|
||||
Properties and methods can be replaced.
|
||||
Even protected and private properties can be set.
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::makeEmptyExcept('User', 'save');
|
||||
Stub::makeEmptyExcept('User', 'save', ['name' => 'davert']);
|
||||
```
|
||||
|
||||
Accepts either name of class or object of that class
|
||||
|
||||
```php
|
||||
<?php
|
||||
* Stub::makeEmptyExcept(new User, 'save');
|
||||
```
|
||||
|
||||
To replace method provide it's name as a key in second parameter
|
||||
and it's return value or callback function as parameter
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::makeEmptyExcept('User', 'save', ['isValid' => function () { return true; }]);
|
||||
Stub::makeEmptyExcept('User', 'save', ['isValid' => true]);
|
||||
```
|
||||
|
||||
**To create a mock, pass current testcase name as last argument:**
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::makeEmptyExcept('User', 'validate', [
|
||||
'save' => \Codeception\Stub\Expected::once()
|
||||
], $this);
|
||||
```
|
||||
* template
|
||||
* `param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType>` $class - A class to be mocked
|
||||
* `param string` $method
|
||||
* `param array` $params
|
||||
* `param bool|PHPUnitTestCase` $testCase
|
||||
|
||||
* return PHPUnitMockObject&RealInstanceType
|
||||
* throws Exception
|
||||
|
||||
#### *public static* makeEmpty($class, array $params = Array ( ) , $testCase = null)
|
||||
Instantiates class having all methods replaced with dummies.
|
||||
Constructor is not triggered.
|
||||
Properties and methods can be set as a second parameter.
|
||||
Even protected and private properties can be set.
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::makeEmpty('User');
|
||||
Stub::makeEmpty('User', ['name' => 'davert']);
|
||||
```
|
||||
|
||||
Accepts either name of class or object of that class
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::makeEmpty(new User, ['name' => 'davert']);
|
||||
```
|
||||
|
||||
To replace method provide it's name as a key in second parameter
|
||||
and it's return value or callback function as parameter
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::makeEmpty('User', ['save' => function () { return true; }]);
|
||||
Stub::makeEmpty('User', ['save' => true]);
|
||||
```
|
||||
|
||||
**To create a mock, pass current testcase name as last argument:**
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::makeEmpty('User', [
|
||||
'save' => \Codeception\Stub\Expected::once()
|
||||
], $this);
|
||||
```
|
||||
|
||||
* template RealInstanceType of object
|
||||
* `param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType>` $class - A class to be mocked
|
||||
* `param bool|PHPUnitTestCase` $testCase
|
||||
|
||||
* return PHPUnitMockObject&RealInstanceType
|
||||
* throws Exception
|
||||
|
||||
#### *public static* copy($obj, array $params = Array ( ) )
|
||||
Clones an object and redefines it's properties (even protected and private)
|
||||
|
||||
* `param` $obj
|
||||
* `param array` $params
|
||||
* return mixed
|
||||
* throws Exception
|
||||
|
||||
#### *public static* construct($class, array $constructorParams = Array ( ) , array $params = Array ( ) , $testCase = null)
|
||||
Instantiates a class instance by running constructor.
|
||||
Parameters for constructor passed as second argument
|
||||
Properties and methods can be set in third argument.
|
||||
Even protected and private properties can be set.
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::construct('User', ['autosave' => false]);
|
||||
Stub::construct('User', ['autosave' => false], ['name' => 'davert']);
|
||||
```
|
||||
|
||||
Accepts either name of class or object of that class
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::construct(new User, ['autosave' => false], ['name' => 'davert']);
|
||||
```
|
||||
|
||||
To replace method provide it's name as a key in third parameter
|
||||
and it's return value or callback function as parameter
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::construct('User', [], ['save' => function () { return true; }]);
|
||||
Stub::construct('User', [], ['save' => true]);
|
||||
```
|
||||
|
||||
**To create a mock, pass current testcase name as last argument:**
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::construct('User', [], [
|
||||
'save' => \Codeception\Stub\Expected::once()
|
||||
], $this);
|
||||
```
|
||||
|
||||
* template RealInstanceType of object
|
||||
* `param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType>` $class - A class to be mocked
|
||||
* `param bool|PHPUnitTestCase` $testCase
|
||||
|
||||
* return PHPUnitMockObject&RealInstanceType
|
||||
* throws Exception
|
||||
|
||||
#### *public static* constructEmpty($class, array $constructorParams = Array ( ) , array $params = Array ( ) , $testCase = null)
|
||||
Instantiates a class instance by running constructor with all methods replaced with dummies.
|
||||
Parameters for constructor passed as second argument
|
||||
Properties and methods can be set in third argument.
|
||||
Even protected and private properties can be set.
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::constructEmpty('User', ['autosave' => false]);
|
||||
Stub::constructEmpty('User', ['autosave' => false], ['name' => 'davert']);
|
||||
```
|
||||
|
||||
Accepts either name of class or object of that class
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::constructEmpty(new User, ['autosave' => false], ['name' => 'davert']);
|
||||
```
|
||||
|
||||
To replace method provide it's name as a key in third parameter
|
||||
and it's return value or callback function as parameter
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::constructEmpty('User', [], ['save' => function () { return true; }]);
|
||||
Stub::constructEmpty('User', [], ['save' => true]);
|
||||
```
|
||||
|
||||
**To create a mock, pass current testcase name as last argument:**
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::constructEmpty('User', [], [
|
||||
'save' => \Codeception\Stub\Expected::once()
|
||||
], $this);
|
||||
```
|
||||
|
||||
* template RealInstanceType of object
|
||||
* `param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType>` $class - A class to be mocked
|
||||
* `param array` $constructorParams
|
||||
* `param array` $params
|
||||
* `param bool|PHPUnitTestCase` $testCase
|
||||
|
||||
* return PHPUnitMockObject&RealInstanceType
|
||||
* throws ReflectionException
|
||||
|
||||
#### *public static* constructEmptyExcept($class, $method, array $constructorParams = Array ( ) , array $params = Array ( ) , $testCase = null)
|
||||
Instantiates a class instance by running constructor with all methods replaced with dummies, except one.
|
||||
Parameters for constructor passed as second argument
|
||||
Properties and methods can be set in third argument.
|
||||
Even protected and private properties can be set.
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::constructEmptyExcept('User', 'save');
|
||||
Stub::constructEmptyExcept('User', 'save', ['autosave' => false], ['name' => 'davert']);
|
||||
```
|
||||
|
||||
Accepts either name of class or object of that class
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::constructEmptyExcept(new User, 'save', ['autosave' => false], ['name' => 'davert']);
|
||||
```
|
||||
|
||||
To replace method provide it's name as a key in third parameter
|
||||
and it's return value or callback function as parameter
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::constructEmptyExcept('User', 'save', [], ['save' => function () { return true; }]);
|
||||
Stub::constructEmptyExcept('User', 'save', [], ['save' => true]);
|
||||
```
|
||||
|
||||
**To create a mock, pass current testcase name as last argument:**
|
||||
|
||||
```php
|
||||
<?php
|
||||
Stub::constructEmptyExcept('User', 'save', [], [
|
||||
'save' => \Codeception\Stub\Expected::once()
|
||||
], $this);
|
||||
```
|
||||
|
||||
* template RealInstanceType of object
|
||||
* `param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType>` $class - A class to be mocked
|
||||
* `param bool|PHPUnitTestCase` $testCase
|
||||
|
||||
* return PHPUnitMockObject&RealInstanceType
|
||||
* throws ReflectionException
|
||||
|
||||
#### *public static* update($mock, array $params)
|
||||
Replaces properties of current stub
|
||||
|
||||
* `param PHPUnitMockObject|object` $mock
|
||||
* `param array` $params
|
||||
* return object
|
||||
throws LogicException
|
||||
|
||||
#### *public static* consecutive()
|
||||
Stubbing a method call to return a list of values in the specified order.
|
||||
|
||||
```php
|
||||
<?php
|
||||
$user = Stub::make('User', ['getName' => Stub::consecutive('david', 'emma', 'sam', 'amy')]);
|
||||
$user->getName(); //david
|
||||
$user->getName(); //emma
|
||||
$user->getName(); //sam
|
||||
$user->getName(); //amy
|
||||
```
|
||||
|
||||
|
||||
230
vendor/codeception/stub/docs/StubTrait.md
vendored
Normal file
230
vendor/codeception/stub/docs/StubTrait.md
vendored
Normal file
@ -0,0 +1,230 @@
|
||||
|
||||
## Codeception\Test\Feature\Stub
|
||||
|
||||
|
||||
|
||||
### Usage in Codeception
|
||||
|
||||
Since Codeception 2.3.8 this trait is enabled in `\Codeception\Test\Unit` class.
|
||||
|
||||
### Usage in PHPUnit
|
||||
|
||||
Include this trait into a TestCase to be able to use Stubs and Mocks:
|
||||
|
||||
```php
|
||||
<?php
|
||||
class MyTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
use Codeception\Test\Feature\Stub;
|
||||
}
|
||||
```
|
||||
|
||||
#### *public* make($class, array $params = Array ( ) )
|
||||
Instantiates a class without executing a constructor.
|
||||
Properties and methods can be set as a second parameter.
|
||||
Even protected and private properties can be set.
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->make('User');
|
||||
$this->make('User', ['name' => 'davert']);
|
||||
```
|
||||
|
||||
Accepts either name of class or object of that class
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->make(new User, ['name' => 'davert']);
|
||||
```
|
||||
|
||||
To replace method provide it's name as a key in second parameter
|
||||
and it's return value or callback function as parameter
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->make('User', ['save' => function () { return true; }]);
|
||||
$this->make('User', ['save' => true]);
|
||||
```
|
||||
* template RealInstanceType of object
|
||||
* `param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType>` $class - A class to be mocked
|
||||
* `param array` $params - properties and methods to set
|
||||
|
||||
* return MockObject&RealInstanceType - mock
|
||||
* throws RuntimeException when class does not exist
|
||||
* throws Exception
|
||||
|
||||
#### *public* makeEmpty($class, array $params = Array ( ) )
|
||||
Instantiates class having all methods replaced with dummies.
|
||||
Constructor is not triggered.
|
||||
Properties and methods can be set as a second parameter.
|
||||
Even protected and private properties can be set.
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->makeEmpty('User');
|
||||
$this->makeEmpty('User', ['name' => 'davert']);
|
||||
```
|
||||
|
||||
Accepts either name of class or object of that class
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->makeEmpty(new User, ['name' => 'davert']);
|
||||
```
|
||||
|
||||
To replace method provide it's name as a key in second parameter
|
||||
and it's return value or callback function as parameter
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->makeEmpty('User', ['save' => function () { return true; }]);
|
||||
$this->makeEmpty('User', ['save' => true]);
|
||||
```
|
||||
|
||||
* template RealInstanceType of object
|
||||
* `param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType>` $class - A class to be mocked
|
||||
* `param array` $params
|
||||
* return MockObject&RealInstanceType
|
||||
* throws Exception
|
||||
|
||||
#### *public* makeEmptyExcept($class, $method, array $params = Array ( ) )
|
||||
Instantiates class having all methods replaced with dummies except one.
|
||||
Constructor is not triggered.
|
||||
Properties and methods can be replaced.
|
||||
Even protected and private properties can be set.
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->makeEmptyExcept('User', 'save');
|
||||
$this->makeEmptyExcept('User', 'save', ['name' => 'davert']);
|
||||
```
|
||||
|
||||
Accepts either name of class or object of that class
|
||||
|
||||
``` php
|
||||
<?php
|
||||
* $this->makeEmptyExcept(new User, 'save');
|
||||
```
|
||||
|
||||
To replace method provide it's name as a key in second parameter
|
||||
and it's return value or callback function as parameter
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->makeEmptyExcept('User', 'save', ['isValid' => function () { return true; }]);
|
||||
$this->makeEmptyExcept('User', 'save', ['isValid' => true]);
|
||||
```
|
||||
|
||||
* template RealInstanceType of object
|
||||
* `param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType>` $class - A class to be mocked
|
||||
|
||||
* return \PHPUnit\Framework\MockObject\MockObject&RealInstanceType
|
||||
* throws Exception
|
||||
|
||||
#### *public* construct($class, array $constructorParams = Array ( ) , array $params = Array ( ) )
|
||||
Instantiates a class instance by running constructor.
|
||||
Parameters for constructor passed as second argument
|
||||
Properties and methods can be set in third argument.
|
||||
Even protected and private properties can be set.
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->construct('User', ['autosave' => false]);
|
||||
$this->construct('User', ['autosave' => false], ['name' => 'davert']);
|
||||
```
|
||||
|
||||
Accepts either name of class or object of that class
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->construct(new User, ['autosave' => false), ['name' => 'davert']);
|
||||
```
|
||||
|
||||
To replace method provide it's name as a key in third parameter
|
||||
and it's return value or callback function as parameter
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->construct('User', [], ['save' => function () { return true; }]);
|
||||
$this->construct('User', [], ['save' => true]);
|
||||
```
|
||||
|
||||
* template RealInstanceType of object
|
||||
* `param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType>` $class - A class to be mocked
|
||||
* return MockObject&RealInstanceType
|
||||
* throws Exception
|
||||
|
||||
#### *public* constructEmpty($class, array $constructorParams = Array ( ) , array $params = Array ( ) )
|
||||
Instantiates a class instance by running constructor with all methods replaced with dummies.
|
||||
Parameters for constructor passed as second argument
|
||||
Properties and methods can be set in third argument.
|
||||
Even protected and private properties can be set.
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->constructEmpty('User', ['autosave' => false]);
|
||||
$this->constructEmpty('User', ['autosave' => false), ['name' => 'davert']);
|
||||
```
|
||||
|
||||
Accepts either name of class or object of that class
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->constructEmpty(new User, ['autosave' => false], ['name' => 'davert']);
|
||||
```
|
||||
|
||||
To replace method provide it's name as a key in third parameter
|
||||
and it's return value or callback function as parameter
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->constructEmpty('User', array(), array('save' => function () { return true; }));
|
||||
$this->constructEmpty('User', array(), array('save' => true));
|
||||
```
|
||||
|
||||
**To create a mock, pass current testcase name as last argument:**
|
||||
|
||||
```php
|
||||
<?php
|
||||
$this->constructEmpty('User', [], [
|
||||
'save' => \Codeception\Stub\Expected::once()
|
||||
]);
|
||||
```
|
||||
|
||||
* template RealInstanceType of object
|
||||
* `param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType>` $class - A class to be mocked
|
||||
* return MockObject&RealInstanceType
|
||||
|
||||
#### *public* constructEmptyExcept($class, $method, array $constructorParams = Array ( ) , array $params = Array ( ) )
|
||||
Instantiates a class instance by running constructor with all methods replaced with dummies, except one.
|
||||
Parameters for constructor passed as second argument
|
||||
Properties and methods can be set in third argument.
|
||||
Even protected and private properties can be set.
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->constructEmptyExcept('User', 'save');
|
||||
$this->constructEmptyExcept('User', 'save', ['autosave' => false], ['name' => 'davert']);
|
||||
```
|
||||
|
||||
Accepts either name of class or object of that class
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->constructEmptyExcept(new User, 'save', ['autosave' => false], ['name' => 'davert']);
|
||||
```
|
||||
|
||||
To replace method provide it's name as a key in third parameter
|
||||
and it's return value or callback function as parameter
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$this->constructEmptyExcept('User', 'save', [], ['save' => function () { return true; }]);
|
||||
$this->constructEmptyExcept('User', 'save', [], ['save' => true]);
|
||||
```
|
||||
|
||||
* template RealInstanceType of object
|
||||
* `param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType>` $class - A class to be mocked
|
||||
* return MockObject&RealInstanceType
|
||||
|
||||
|
||||
656
vendor/codeception/stub/src/Stub.php
vendored
Normal file
656
vendor/codeception/stub/src/Stub.php
vendored
Normal file
@ -0,0 +1,656 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Codeception;
|
||||
|
||||
use Closure;
|
||||
use Codeception\Stub\ConsecutiveMap;
|
||||
use Codeception\Stub\StubMarshaler;
|
||||
use Exception;
|
||||
use LogicException;
|
||||
use PHPUnit\Framework\MockObject\Generator as LegacyGenerator;
|
||||
use PHPUnit\Framework\MockObject\Generator\Generator;
|
||||
use PHPUnit\Framework\MockObject\MockObject as PHPUnitMockObject;
|
||||
use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount;
|
||||
use PHPUnit\Framework\MockObject\Stub\ConsecutiveCalls;
|
||||
use PHPUnit\Framework\MockObject\Stub\ReturnCallback;
|
||||
use PHPUnit\Framework\MockObject\Stub\ReturnStub;
|
||||
use PHPUnit\Framework\TestCase as PHPUnitTestCase;
|
||||
use PHPUnit\Runner\Version as PHPUnitVersion;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use RuntimeException;
|
||||
|
||||
class Stub
|
||||
{
|
||||
public static array $magicMethods = ['__isset', '__get', '__set'];
|
||||
|
||||
/**
|
||||
* Instantiates a class without executing a constructor.
|
||||
* Properties and methods can be set as a second parameter.
|
||||
* Even protected and private properties can be set.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::make('User');
|
||||
* Stub::make('User', ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* Accepts either name of class or object of that class
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::make(new User, ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* To replace method provide it's name as a key in second parameter
|
||||
* and it's return value or callback function as parameter
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::make('User', ['save' => function () { return true; }]);
|
||||
* Stub::make('User', ['save' => true]);
|
||||
* ```
|
||||
*
|
||||
* **To create a mock, pass current testcase name as last argument:**
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::make('User', [
|
||||
* 'save' => \Codeception\Stub\Expected::once()
|
||||
* ], $this);
|
||||
* ```
|
||||
*
|
||||
* @template RealInstanceType of object
|
||||
* @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
|
||||
* @param array $params - properties and methods to set
|
||||
* @param bool|PHPUnitTestCase $testCase
|
||||
*
|
||||
* @return PHPUnitMockObject&RealInstanceType - mock
|
||||
* @throws RuntimeException when class does not exist
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function make($class, array $params = [], $testCase = false)
|
||||
{
|
||||
$class = self::getClassname($class);
|
||||
if (!class_exists($class)) {
|
||||
if (interface_exists($class)) {
|
||||
throw new RuntimeException("Stub::make can't mock interfaces, please use Stub::makeEmpty instead.");
|
||||
}
|
||||
throw new RuntimeException("Stubbed class $class doesn't exist.");
|
||||
}
|
||||
|
||||
$reflection = new ReflectionClass($class);
|
||||
$callables = self::getMethodsToReplace($reflection, $params);
|
||||
if ($reflection->isAbstract()) {
|
||||
$arguments = empty($callables) ? [] : array_keys($callables);
|
||||
$mock = self::generateMockForAbstractClass($class, $arguments, '', false, $testCase);
|
||||
} else {
|
||||
$arguments = empty($callables) ? null : array_keys($callables);
|
||||
$mock = self::generateMock($class, $arguments, [], '', false, $testCase);
|
||||
}
|
||||
|
||||
self::bindParameters($mock, $params);
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates $num instances of class through `Stub::make`.
|
||||
*
|
||||
* @param mixed $class
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function factory($class, int $num = 1, array $params = []): array
|
||||
{
|
||||
$objects = [];
|
||||
for ($i = 0; $i < $num; $i++) {
|
||||
$objects[] = self::make($class, $params);
|
||||
}
|
||||
|
||||
return $objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates class having all methods replaced with dummies except one.
|
||||
* Constructor is not triggered.
|
||||
* Properties and methods can be replaced.
|
||||
* Even protected and private properties can be set.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::makeEmptyExcept('User', 'save');
|
||||
* Stub::makeEmptyExcept('User', 'save', ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* Accepts either name of class or object of that class
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* * Stub::makeEmptyExcept(new User, 'save');
|
||||
* ```
|
||||
*
|
||||
* To replace method provide it's name as a key in second parameter
|
||||
* and it's return value or callback function as parameter
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::makeEmptyExcept('User', 'save', ['isValid' => function () { return true; }]);
|
||||
* Stub::makeEmptyExcept('User', 'save', ['isValid' => true]);
|
||||
* ```
|
||||
*
|
||||
* **To create a mock, pass current testcase name as last argument:**
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::makeEmptyExcept('User', 'validate', [
|
||||
* 'save' => \Codeception\Stub\Expected::once()
|
||||
* ], $this);
|
||||
* ```
|
||||
* @template RealInstanceType of object
|
||||
* @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
|
||||
* @param string $method
|
||||
* @param array $params
|
||||
* @param bool|PHPUnitTestCase $testCase
|
||||
*
|
||||
* @return PHPUnitMockObject&RealInstanceType
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function makeEmptyExcept($class, string $method, array $params = [], $testCase = false)
|
||||
{
|
||||
[$class, $methods] = self::createEmpty($class, $method);
|
||||
$mock = self::generateMock($class, $methods, [], '', false, $testCase);
|
||||
self::bindParameters($mock, $params);
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates class having all methods replaced with dummies.
|
||||
* Constructor is not triggered.
|
||||
* Properties and methods can be set as a second parameter.
|
||||
* Even protected and private properties can be set.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::makeEmpty('User');
|
||||
* Stub::makeEmpty('User', ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* Accepts either name of class or object of that class
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::makeEmpty(new User, ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* To replace method provide it's name as a key in second parameter
|
||||
* and it's return value or callback function as parameter
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::makeEmpty('User', ['save' => function () { return true; }]);
|
||||
* Stub::makeEmpty('User', ['save' => true]);
|
||||
* ```
|
||||
*
|
||||
* **To create a mock, pass current testcase name as last argument:**
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::makeEmpty('User', [
|
||||
* 'save' => \Codeception\Stub\Expected::once()
|
||||
* ], $this);
|
||||
* ```
|
||||
*
|
||||
* @template RealInstanceType of object
|
||||
* @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
|
||||
* @param bool|PHPUnitTestCase $testCase
|
||||
*
|
||||
* @return PHPUnitMockObject&RealInstanceType
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function makeEmpty($class, array $params = [], $testCase = false)
|
||||
{
|
||||
$class = self::getClassname($class);
|
||||
$methods = array_filter(
|
||||
get_class_methods($class),
|
||||
fn($i) => !in_array($i, Stub::$magicMethods)
|
||||
);
|
||||
$mock = self::generateMock($class, $methods, [], '', false, $testCase);
|
||||
self::bindParameters($mock, $params);
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones an object and redefines it's properties (even protected and private)
|
||||
*
|
||||
* @param $obj
|
||||
* @param array $params
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function copy($obj, array $params = [])
|
||||
{
|
||||
$copy = clone($obj);
|
||||
self::bindParameters($copy, $params);
|
||||
|
||||
return $copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a class instance by running constructor.
|
||||
* Parameters for constructor passed as second argument
|
||||
* Properties and methods can be set in third argument.
|
||||
* Even protected and private properties can be set.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::construct('User', ['autosave' => false]);
|
||||
* Stub::construct('User', ['autosave' => false], ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* Accepts either name of class or object of that class
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::construct(new User, ['autosave' => false], ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* To replace method provide it's name as a key in third parameter
|
||||
* and it's return value or callback function as parameter
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::construct('User', [], ['save' => function () { return true; }]);
|
||||
* Stub::construct('User', [], ['save' => true]);
|
||||
* ```
|
||||
*
|
||||
* **To create a mock, pass current testcase name as last argument:**
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::construct('User', [], [
|
||||
* 'save' => \Codeception\Stub\Expected::once()
|
||||
* ], $this);
|
||||
* ```
|
||||
*
|
||||
* @template RealInstanceType of object
|
||||
* @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
|
||||
* @param bool|PHPUnitTestCase $testCase
|
||||
*
|
||||
* @return PHPUnitMockObject&RealInstanceType
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function construct($class, array $constructorParams = [], array $params = [], $testCase = false)
|
||||
{
|
||||
$class = self::getClassname($class);
|
||||
$reflection = new ReflectionClass($class);
|
||||
|
||||
$callables = self::getMethodsToReplace($reflection, $params);
|
||||
|
||||
$arguments = empty($callables) ? null : array_keys($callables);
|
||||
$mock = self::generateMock($class, $arguments, $constructorParams, $testCase);
|
||||
self::bindParameters($mock, $params);
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a class instance by running constructor with all methods replaced with dummies.
|
||||
* Parameters for constructor passed as second argument
|
||||
* Properties and methods can be set in third argument.
|
||||
* Even protected and private properties can be set.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::constructEmpty('User', ['autosave' => false]);
|
||||
* Stub::constructEmpty('User', ['autosave' => false], ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* Accepts either name of class or object of that class
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::constructEmpty(new User, ['autosave' => false], ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* To replace method provide it's name as a key in third parameter
|
||||
* and it's return value or callback function as parameter
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::constructEmpty('User', [], ['save' => function () { return true; }]);
|
||||
* Stub::constructEmpty('User', [], ['save' => true]);
|
||||
* ```
|
||||
*
|
||||
* **To create a mock, pass current testcase name as last argument:**
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::constructEmpty('User', [], [
|
||||
* 'save' => \Codeception\Stub\Expected::once()
|
||||
* ], $this);
|
||||
* ```
|
||||
*
|
||||
* @template RealInstanceType of object
|
||||
* @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
|
||||
* @param array $constructorParams
|
||||
* @param array $params
|
||||
* @param bool|PHPUnitTestCase $testCase
|
||||
*
|
||||
* @return PHPUnitMockObject&RealInstanceType
|
||||
*/
|
||||
public static function constructEmpty($class, array $constructorParams = [], array $params = [], $testCase = false)
|
||||
{
|
||||
$class = self::getClassname($class);
|
||||
$methods = array_filter(
|
||||
get_class_methods($class),
|
||||
fn($i) => !in_array($i, Stub::$magicMethods)
|
||||
);
|
||||
$mock = self::generateMock($class, $methods, $constructorParams, $testCase);
|
||||
self::bindParameters($mock, $params);
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a class instance by running constructor with all methods replaced with dummies, except one.
|
||||
* Parameters for constructor passed as second argument
|
||||
* Properties and methods can be set in third argument.
|
||||
* Even protected and private properties can be set.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::constructEmptyExcept('User', 'save');
|
||||
* Stub::constructEmptyExcept('User', 'save', ['autosave' => false], ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* Accepts either name of class or object of that class
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::constructEmptyExcept(new User, 'save', ['autosave' => false], ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* To replace method provide it's name as a key in third parameter
|
||||
* and it's return value or callback function as parameter
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::constructEmptyExcept('User', 'save', [], ['save' => function () { return true; }]);
|
||||
* Stub::constructEmptyExcept('User', 'save', [], ['save' => true]);
|
||||
* ```
|
||||
*
|
||||
* **To create a mock, pass current testcase name as last argument:**
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Stub::constructEmptyExcept('User', 'save', [], [
|
||||
* 'save' => \Codeception\Stub\Expected::once()
|
||||
* ], $this);
|
||||
* ```
|
||||
*
|
||||
* @template RealInstanceType of object
|
||||
* @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
|
||||
* @param bool|PHPUnitTestCase $testCase
|
||||
*
|
||||
* @return PHPUnitMockObject&RealInstanceType
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public static function constructEmptyExcept(
|
||||
$class,
|
||||
string $method,
|
||||
array $constructorParams = [],
|
||||
array $params = [],
|
||||
$testCase = false
|
||||
) {
|
||||
[$class, $methods] = self::createEmpty($class, $method);
|
||||
$mock = self::generateMock($class, $methods, $constructorParams, $testCase);
|
||||
self::bindParameters($mock, $params);
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
private static function generateMock()
|
||||
{
|
||||
$args = func_get_args();
|
||||
// PHPUnit 11 added the optional parameter $markAsMockObject:
|
||||
// https://github.com/sebastianbergmann/phpunit/commit/db9ae302fe1ad89451ecfacc850e88ab7c6df5a3
|
||||
// The parameter was removed in PHPUnit 12:
|
||||
// https://github.com/sebastianbergmann/phpunit/commit/a98e3939c74f6103cbeb7a785b73eb4a10784474
|
||||
if (version_compare(PHPUnitVersion::series(), '11', '>=') && version_compare(PHPUnitVersion::series(), '12', '<')) {
|
||||
if (!is_bool($args[1]) || !is_bool($args[2])) {
|
||||
$additionalParameters = [];
|
||||
if (!is_bool($args[1])) {
|
||||
$additionalParameters[] = true;
|
||||
}
|
||||
if (!is_bool($args[2])) {
|
||||
$additionalParameters[] = true;
|
||||
}
|
||||
|
||||
array_splice($args, 1, 0, $additionalParameters);
|
||||
}
|
||||
} elseif (version_compare(PHPUnitVersion::series(), '10.4', '>=') && !is_bool($args[1])) {
|
||||
array_splice($args, 1, 0, [true]);
|
||||
}
|
||||
|
||||
return self::doGenerateMock($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mock object for the specified abstract class with all abstract
|
||||
* methods of the class mocked. Concrete methods to mock can be specified with
|
||||
* the last parameter
|
||||
*
|
||||
* @since Method available since Release 1.0.0
|
||||
*/
|
||||
private static function generateMockForAbstractClass(): object
|
||||
{
|
||||
return self::doGenerateMock(func_get_args(), true);
|
||||
}
|
||||
|
||||
private static function doGenerateMock($args, $isAbstract = false)
|
||||
{
|
||||
$testCase = self::extractTestCaseFromArgs($args);
|
||||
|
||||
// PHPUnit 10.4 changed method names
|
||||
if (version_compare(PHPUnitVersion::series(), '10.4', '>=')) {
|
||||
$methodName = $isAbstract ? 'mockObjectForAbstractClass' : 'testDouble';
|
||||
} else {
|
||||
$methodName = $isAbstract ? 'getMockForAbstractClass' : 'getMock';
|
||||
}
|
||||
|
||||
if ($isAbstract && version_compare(PHPUnitVersion::series(), '12', '>=')) {
|
||||
throw new RuntimeException('PHPUnit 12 or greater does not allow to mock abstract classes anymore');
|
||||
}
|
||||
|
||||
// PHPUnit 10.3 changed the namespace
|
||||
if (version_compare(PHPUnitVersion::series(), '10.3', '>=')) {
|
||||
$generatorClass = new Generator();
|
||||
} else {
|
||||
$generatorClass = new LegacyGenerator();
|
||||
}
|
||||
|
||||
$mock = call_user_func_array([$generatorClass, $methodName], $args);
|
||||
|
||||
if ($testCase instanceof PHPUnitTestCase) {
|
||||
if (version_compare(PHPUnitVersion::series(), '12.5', '>=')) {
|
||||
$testCase->registerMockObject($mock::class, $mock);
|
||||
} else {
|
||||
$testCase->registerMockObject($mock);
|
||||
}
|
||||
}
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
private static function extractTestCaseFromArgs(&$args)
|
||||
{
|
||||
$argsLength = count($args) - 1;
|
||||
$testCase = $args[$argsLength];
|
||||
|
||||
unset($args[$argsLength]);
|
||||
|
||||
return $testCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces properties of current stub
|
||||
*
|
||||
* @param PHPUnitMockObject|object $mock
|
||||
* @param array $params
|
||||
* @return object
|
||||
*@throws LogicException
|
||||
*/
|
||||
public static function update(object $mock, array $params): object
|
||||
{
|
||||
self::bindParameters($mock, $params);
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PHPUnitMockObject|object $mock
|
||||
* @param array $params
|
||||
* @throws LogicException
|
||||
*/
|
||||
protected static function bindParameters($mock, array $params)
|
||||
{
|
||||
$reflectionClass = new ReflectionClass($mock);
|
||||
if ($mock instanceof PHPUnitMockObject) {
|
||||
$parentClass = $reflectionClass->getParentClass();
|
||||
if ($parentClass !== false) {
|
||||
$reflectionClass = $reflectionClass->getParentClass();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($params as $param => $value) {
|
||||
// redefine method
|
||||
if ($reflectionClass->hasMethod($param)) {
|
||||
if ($value instanceof StubMarshaler) {
|
||||
$marshaler = $value;
|
||||
$mock
|
||||
->expects($marshaler->getMatcher())
|
||||
->method($param)
|
||||
->will(new ReturnCallback($marshaler->getValue()));
|
||||
} elseif ($value instanceof Closure) {
|
||||
$mock
|
||||
->expects(new AnyInvokedCount)
|
||||
->method($param)
|
||||
->will(new ReturnCallback($value));
|
||||
} elseif ($value instanceof ConsecutiveMap) {
|
||||
$consecutiveMap = $value;
|
||||
$mock
|
||||
->expects(new AnyInvokedCount)
|
||||
->method($param)
|
||||
->will(new ConsecutiveCalls($consecutiveMap->getMap()));
|
||||
} else {
|
||||
$mock
|
||||
->expects(new AnyInvokedCount)
|
||||
->method($param)
|
||||
->will(new ReturnStub($value));
|
||||
}
|
||||
} elseif ($reflectionClass->hasProperty($param)) {
|
||||
$reflectionProperty = $reflectionClass->getProperty($param);
|
||||
$reflectionProperty->setValue($mock, $value);
|
||||
} else {
|
||||
if ($reflectionClass->hasMethod('__set')) {
|
||||
try {
|
||||
$mock->{$param} = $value;
|
||||
} catch (Exception $exception) {
|
||||
throw new LogicException(
|
||||
sprintf(
|
||||
'Could not add property %1$s, class %2$s implements __set method, '
|
||||
. 'and no %1$s property exists',
|
||||
$param,
|
||||
$reflectionClass->getName()
|
||||
),
|
||||
$exception->getCode(),
|
||||
$exception
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$mock->{$param} = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @TO-DO Should be simplified
|
||||
*/
|
||||
protected static function getClassname($object)
|
||||
{
|
||||
if (is_object($object)) {
|
||||
return get_class($object);
|
||||
}
|
||||
|
||||
if (is_callable($object)) {
|
||||
return call_user_func($object);
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
protected static function getMethodsToReplace(ReflectionClass $reflection, array $params): array
|
||||
{
|
||||
$callables = [];
|
||||
foreach ($params as $method => $value) {
|
||||
if ($reflection->hasMethod($method)) {
|
||||
$callables[$method] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $callables;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stubbing a method call to return a list of values in the specified order.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $user = Stub::make('User', ['getName' => Stub::consecutive('david', 'emma', 'sam', 'amy')]);
|
||||
* $user->getName(); //david
|
||||
* $user->getName(); //emma
|
||||
* $user->getName(); //sam
|
||||
* $user->getName(); //amy
|
||||
* ```
|
||||
*/
|
||||
public static function consecutive(): ConsecutiveMap
|
||||
{
|
||||
return new ConsecutiveMap(func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $class
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
private static function createEmpty($class, string $method): array
|
||||
{
|
||||
$class = self::getClassname($class);
|
||||
$reflectionClass = new ReflectionClass($class);
|
||||
|
||||
$methods = $reflectionClass->getMethods();
|
||||
|
||||
$methods = array_filter(
|
||||
$methods,
|
||||
fn($m) => !in_array($m->name, Stub::$magicMethods)
|
||||
);
|
||||
|
||||
$methods = array_filter(
|
||||
$methods,
|
||||
fn($m) => $method != $m->name
|
||||
);
|
||||
|
||||
$methods = array_map(
|
||||
fn($m) => $m->name,
|
||||
$methods
|
||||
);
|
||||
|
||||
$methods = count($methods) ? $methods : null;
|
||||
return [$class, $methods];
|
||||
}
|
||||
}
|
||||
23
vendor/codeception/stub/src/Stub/ConsecutiveMap.php
vendored
Normal file
23
vendor/codeception/stub/src/Stub/ConsecutiveMap.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Codeception\Stub;
|
||||
|
||||
/**
|
||||
* Holds matcher and value of mocked method
|
||||
*/
|
||||
class ConsecutiveMap
|
||||
{
|
||||
private array $consecutiveMap = [];
|
||||
|
||||
public function __construct(array $consecutiveMap)
|
||||
{
|
||||
$this->consecutiveMap = $consecutiveMap;
|
||||
}
|
||||
|
||||
public function getMap(): array
|
||||
{
|
||||
return $this->consecutiveMap;
|
||||
}
|
||||
}
|
||||
167
vendor/codeception/stub/src/Stub/Expected.php
vendored
Normal file
167
vendor/codeception/stub/src/Stub/Expected.php
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Codeception\Stub;
|
||||
|
||||
use Closure;
|
||||
use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastOnce;
|
||||
use PHPUnit\Framework\MockObject\Rule\InvokedCount;
|
||||
|
||||
class Expected
|
||||
{
|
||||
/**
|
||||
* Checks if a method never has been invoked
|
||||
*
|
||||
* If method invoked, it will immediately throw an
|
||||
* exception.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* use \Codeception\Stub\Expected;
|
||||
*
|
||||
* $user = $this->make('User', [
|
||||
* 'getName' => Expected::never(),
|
||||
* 'someMethod' => function() {}
|
||||
* ]);
|
||||
* $user->someMethod();
|
||||
* ```
|
||||
*
|
||||
* @param mixed $params
|
||||
*/
|
||||
public static function never($params = null): StubMarshaler
|
||||
{
|
||||
return new StubMarshaler(
|
||||
new InvokedCount(0),
|
||||
self::closureIfNull($params)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a method has been invoked exactly one
|
||||
* time.
|
||||
*
|
||||
* If the number is less or greater it will later be checked in verify() and also throw an
|
||||
* exception.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* use \Codeception\Stub\Expected;
|
||||
*
|
||||
* $user = $this->make(
|
||||
* 'User',
|
||||
* array(
|
||||
* 'getName' => Expected::once('Davert'),
|
||||
* 'someMethod' => function() {}
|
||||
* )
|
||||
* );
|
||||
* $userName = $user->getName();
|
||||
* $this->assertEquals('Davert', $userName);
|
||||
* ```
|
||||
* Alternatively, a function can be passed as parameter:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Expected::once(function() { return Faker::name(); });
|
||||
* ```
|
||||
*
|
||||
* @param mixed $params
|
||||
*/
|
||||
public static function once($params = null): StubMarshaler
|
||||
{
|
||||
return new StubMarshaler(
|
||||
new InvokedCount(1),
|
||||
self::closureIfNull($params)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a method has been invoked at least one
|
||||
* time.
|
||||
*
|
||||
* If the number of invocations is 0 it will throw an exception in verify.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* use \Codeception\Stub\Expected;
|
||||
*
|
||||
* $user = $this->make(
|
||||
* 'User',
|
||||
* array(
|
||||
* 'getName' => Expected::atLeastOnce('Davert')),
|
||||
* 'someMethod' => function() {}
|
||||
* )
|
||||
* );
|
||||
* $user->getName();
|
||||
* $userName = $user->getName();
|
||||
* $this->assertEquals('Davert', $userName);
|
||||
* ```
|
||||
*
|
||||
* Alternatively, a function can be passed as parameter:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Expected::atLeastOnce(function() { return Faker::name(); });
|
||||
* ```
|
||||
*
|
||||
* @param mixed $params
|
||||
*/
|
||||
public static function atLeastOnce($params = null): StubMarshaler
|
||||
{
|
||||
return new StubMarshaler(
|
||||
new InvokedAtLeastOnce(),
|
||||
self::closureIfNull($params)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a method has been invoked a certain amount
|
||||
* of times.
|
||||
* If the number of invocations exceeds the value it will immediately throw an
|
||||
* exception,
|
||||
* If the number is less it will later be checked in verify() and also throw an
|
||||
* exception.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* use \Codeception\Stub;
|
||||
* use \Codeception\Stub\Expected;
|
||||
*
|
||||
* $user = $this->make(
|
||||
* 'User',
|
||||
* array(
|
||||
* 'getName' => Expected::exactly(3, 'Davert'),
|
||||
* 'someMethod' => function() {}
|
||||
* )
|
||||
* );
|
||||
* $user->getName();
|
||||
* $user->getName();
|
||||
* $userName = $user->getName();
|
||||
* $this->assertEquals('Davert', $userName);
|
||||
* ```
|
||||
* Alternatively, a function can be passed as parameter:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* Expected::exactly(function() { return Faker::name() });
|
||||
* ```
|
||||
*
|
||||
* @param mixed $params
|
||||
*/
|
||||
public static function exactly(int $count, $params = null): StubMarshaler
|
||||
{
|
||||
return new StubMarshaler(
|
||||
new InvokedCount($count),
|
||||
self::closureIfNull($params)
|
||||
);
|
||||
}
|
||||
|
||||
private static function closureIfNull($params): Closure
|
||||
{
|
||||
if ($params instanceof Closure) {
|
||||
return $params;
|
||||
}
|
||||
|
||||
return fn() => $params;
|
||||
}
|
||||
}
|
||||
33
vendor/codeception/stub/src/Stub/StubMarshaler.php
vendored
Normal file
33
vendor/codeception/stub/src/Stub/StubMarshaler.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Codeception\Stub;
|
||||
|
||||
use PHPUnit\Framework\MockObject\Rule\InvocationOrder;
|
||||
|
||||
/**
|
||||
* Holds matcher and value of mocked method
|
||||
*/
|
||||
class StubMarshaler
|
||||
{
|
||||
private InvocationOrder $methodMatcher;
|
||||
|
||||
private $methodValue;
|
||||
|
||||
public function __construct(InvocationOrder $matcher, $value)
|
||||
{
|
||||
$this->methodMatcher = $matcher;
|
||||
$this->methodValue = $value;
|
||||
}
|
||||
|
||||
public function getMatcher(): InvocationOrder
|
||||
{
|
||||
return $this->methodMatcher;
|
||||
}
|
||||
|
||||
public function getValue()
|
||||
{
|
||||
return $this->methodValue;
|
||||
}
|
||||
}
|
||||
299
vendor/codeception/stub/src/Test/Feature/Stub.php
vendored
Normal file
299
vendor/codeception/stub/src/Test/Feature/Stub.php
vendored
Normal file
@ -0,0 +1,299 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Codeception\Test\Feature;
|
||||
|
||||
use Exception;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* ### Usage in Codeception
|
||||
*
|
||||
* Since Codeception 2.3.8 this trait is enabled in `\Codeception\Test\Unit` class.
|
||||
*
|
||||
* ### Usage in PHPUnit
|
||||
*
|
||||
* Include this trait into a TestCase to be able to use Stubs and Mocks:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* class MyTest extends \PHPUnit\Framework\TestCase
|
||||
* {
|
||||
* use Codeception\Test\Feature\Stub;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
trait Stub
|
||||
{
|
||||
private ?array $mocks = null;
|
||||
|
||||
protected function stubStart()
|
||||
{
|
||||
if ($this instanceof TestCase) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->mocks = [];
|
||||
}
|
||||
|
||||
protected function stubEnd($status, $time)
|
||||
{
|
||||
if ($this instanceof TestCase) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($status !== 'ok') { // Codeception status
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->mocks as $mockObject) {
|
||||
if ($mockObject->__phpunit_hasMatchers()) {
|
||||
$this->assertTrue(true); // incrementing assertions
|
||||
}
|
||||
|
||||
$mockObject->__phpunit_verify(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a class without executing a constructor.
|
||||
* Properties and methods can be set as a second parameter.
|
||||
* Even protected and private properties can be set.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->make('User');
|
||||
* $this->make('User', ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* Accepts either name of class or object of that class
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->make(new User, ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* To replace method provide it's name as a key in second parameter
|
||||
* and it's return value or callback function as parameter
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->make('User', ['save' => function () { return true; }]);
|
||||
* $this->make('User', ['save' => true]);
|
||||
* ```
|
||||
* @template RealInstanceType of object
|
||||
* @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
|
||||
* @param array $params - properties and methods to set
|
||||
*
|
||||
* @return MockObject&RealInstanceType - mock
|
||||
* @throws RuntimeException when class does not exist
|
||||
* @throws Exception
|
||||
*/
|
||||
public function make($class, array $params = [])
|
||||
{
|
||||
return $this->mocks[] = \Codeception\Stub::make($class, $params, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates class having all methods replaced with dummies.
|
||||
* Constructor is not triggered.
|
||||
* Properties and methods can be set as a second parameter.
|
||||
* Even protected and private properties can be set.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->makeEmpty('User');
|
||||
* $this->makeEmpty('User', ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* Accepts either name of class or object of that class
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->makeEmpty(new User, ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* To replace method provide it's name as a key in second parameter
|
||||
* and it's return value or callback function as parameter
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->makeEmpty('User', ['save' => function () { return true; }]);
|
||||
* $this->makeEmpty('User', ['save' => true]);
|
||||
* ```
|
||||
*
|
||||
* @template RealInstanceType of object
|
||||
* @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
|
||||
* @param array $params
|
||||
* @return MockObject&RealInstanceType
|
||||
* @throws Exception
|
||||
*/
|
||||
public function makeEmpty($class, array $params = [])
|
||||
{
|
||||
return $this->mocks[] = \Codeception\Stub::makeEmpty($class, $params, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates class having all methods replaced with dummies except one.
|
||||
* Constructor is not triggered.
|
||||
* Properties and methods can be replaced.
|
||||
* Even protected and private properties can be set.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->makeEmptyExcept('User', 'save');
|
||||
* $this->makeEmptyExcept('User', 'save', ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* Accepts either name of class or object of that class
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* * $this->makeEmptyExcept(new User, 'save');
|
||||
* ```
|
||||
*
|
||||
* To replace method provide it's name as a key in second parameter
|
||||
* and it's return value or callback function as parameter
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->makeEmptyExcept('User', 'save', ['isValid' => function () { return true; }]);
|
||||
* $this->makeEmptyExcept('User', 'save', ['isValid' => true]);
|
||||
* ```
|
||||
*
|
||||
* @template RealInstanceType of object
|
||||
* @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
|
||||
*
|
||||
* @return \PHPUnit\Framework\MockObject\MockObject&RealInstanceType
|
||||
* @throws Exception
|
||||
*/
|
||||
public function makeEmptyExcept($class, string $method, array $params = [])
|
||||
{
|
||||
return $this->mocks[] = \Codeception\Stub::makeEmptyExcept($class, $method, $params, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a class instance by running constructor.
|
||||
* Parameters for constructor passed as second argument
|
||||
* Properties and methods can be set in third argument.
|
||||
* Even protected and private properties can be set.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->construct('User', ['autosave' => false]);
|
||||
* $this->construct('User', ['autosave' => false], ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* Accepts either name of class or object of that class
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->construct(new User, ['autosave' => false), ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* To replace method provide it's name as a key in third parameter
|
||||
* and it's return value or callback function as parameter
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->construct('User', [], ['save' => function () { return true; }]);
|
||||
* $this->construct('User', [], ['save' => true]);
|
||||
* ```
|
||||
*
|
||||
* @template RealInstanceType of object
|
||||
* @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
|
||||
* @return MockObject&RealInstanceType
|
||||
* @throws Exception
|
||||
*/
|
||||
public function construct($class, array $constructorParams = [], array $params = [])
|
||||
{
|
||||
return $this->mocks[] = \Codeception\Stub::construct($class, $constructorParams, $params, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a class instance by running constructor with all methods replaced with dummies.
|
||||
* Parameters for constructor passed as second argument
|
||||
* Properties and methods can be set in third argument.
|
||||
* Even protected and private properties can be set.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->constructEmpty('User', ['autosave' => false]);
|
||||
* $this->constructEmpty('User', ['autosave' => false), ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* Accepts either name of class or object of that class
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->constructEmpty(new User, ['autosave' => false], ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* To replace method provide it's name as a key in third parameter
|
||||
* and it's return value or callback function as parameter
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->constructEmpty('User', array(), array('save' => function () { return true; }));
|
||||
* $this->constructEmpty('User', array(), array('save' => true));
|
||||
* ```
|
||||
*
|
||||
* **To create a mock, pass current testcase name as last argument:**
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $this->constructEmpty('User', [], [
|
||||
* 'save' => \Codeception\Stub\Expected::once()
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* @template RealInstanceType of object
|
||||
* @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
|
||||
* @return MockObject&RealInstanceType
|
||||
*/
|
||||
public function constructEmpty($class, array $constructorParams = [], array $params = [])
|
||||
{
|
||||
return $this->mocks[] = \Codeception\Stub::constructEmpty($class, $constructorParams, $params, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a class instance by running constructor with all methods replaced with dummies, except one.
|
||||
* Parameters for constructor passed as second argument
|
||||
* Properties and methods can be set in third argument.
|
||||
* Even protected and private properties can be set.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->constructEmptyExcept('User', 'save');
|
||||
* $this->constructEmptyExcept('User', 'save', ['autosave' => false], ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* Accepts either name of class or object of that class
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->constructEmptyExcept(new User, 'save', ['autosave' => false], ['name' => 'davert']);
|
||||
* ```
|
||||
*
|
||||
* To replace method provide it's name as a key in third parameter
|
||||
* and it's return value or callback function as parameter
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->constructEmptyExcept('User', 'save', [], ['save' => function () { return true; }]);
|
||||
* $this->constructEmptyExcept('User', 'save', [], ['save' => true]);
|
||||
* ```
|
||||
*
|
||||
* @template RealInstanceType of object
|
||||
* @param class-string<RealInstanceType>|RealInstanceType|callable(): class-string<RealInstanceType> $class - A class to be mocked
|
||||
* @return MockObject&RealInstanceType
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function constructEmptyExcept($class, string $method, array $constructorParams = [], array $params = [])
|
||||
{
|
||||
return $this->mocks[] = \Codeception\Stub::constructEmptyExcept($class, $method, $constructorParams, $params, $this);
|
||||
}
|
||||
}
|
||||
16
vendor/codeception/stub/tests/ResetMocks.php
vendored
Normal file
16
vendor/codeception/stub/tests/ResetMocks.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
trait ResetMocks
|
||||
{
|
||||
protected function resetMockObjects()
|
||||
{
|
||||
$refl = new ReflectionObject($this);
|
||||
while (!$refl->hasProperty('mockObjects')) {
|
||||
$refl = $refl->getParentClass();
|
||||
}
|
||||
$prop = $refl->getProperty('mockObjects');
|
||||
$prop->setValue($this, array());
|
||||
}
|
||||
}
|
||||
449
vendor/codeception/stub/tests/StubTest.php
vendored
Normal file
449
vendor/codeception/stub/tests/StubTest.php
vendored
Normal file
@ -0,0 +1,449 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ .'/ResetMocks.php';
|
||||
|
||||
use Codeception\Stub;
|
||||
use Codeception\Stub\StubMarshaler;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\MockObject\NoMoreReturnValuesConfiguredException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Runner\Version as PHPUnitVersion;
|
||||
|
||||
final class StubTest extends TestCase
|
||||
{
|
||||
use ResetMocks;
|
||||
protected DummyClass $dummy;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
require_once $file = __DIR__. '/_data/DummyAbstractClass.php';
|
||||
require_once $file = __DIR__. '/_data/DummyOverloadableClass.php';
|
||||
require_once $file = __DIR__. '/_data/DummyClass.php';
|
||||
$this->dummy = new DummyClass(true);
|
||||
}
|
||||
|
||||
public function testMakeEmpty()
|
||||
{
|
||||
$dummy = Stub::makeEmpty('DummyClass');
|
||||
$this->assertInstanceOf('DummyClass', $dummy);
|
||||
$this->assertTrue(method_exists($dummy, 'helloWorld'));
|
||||
$this->assertNull($dummy->helloWorld());
|
||||
}
|
||||
|
||||
public function testMakeEmptyMethodReplaced()
|
||||
{
|
||||
$dummy = Stub::makeEmpty('DummyClass', ['helloWorld' => fn(): string => 'good bye world']);
|
||||
$this->assertMethodReplaced($dummy);
|
||||
}
|
||||
|
||||
public function testMakeEmptyMethodSimplyReplaced()
|
||||
{
|
||||
$dummy = Stub::makeEmpty('DummyClass', ['helloWorld' => 'good bye world']);
|
||||
$this->assertMethodReplaced($dummy);
|
||||
}
|
||||
|
||||
public function testMakeEmptyExcept()
|
||||
{
|
||||
$dummy = Stub::makeEmptyExcept('DummyClass', 'helloWorld');
|
||||
$this->assertEquals($this->dummy->helloWorld(), $dummy->helloWorld());
|
||||
$this->assertNull($dummy->goodByeWorld());
|
||||
}
|
||||
|
||||
public function testMakeEmptyExceptPropertyReplaced()
|
||||
{
|
||||
$dummy = Stub::makeEmptyExcept('DummyClass', 'getCheckMe', ['checkMe' => 'checked!']);
|
||||
$this->assertEquals('checked!', $dummy->getCheckMe());
|
||||
}
|
||||
|
||||
public function testMakeEmptyExceptMagicalPropertyReplaced()
|
||||
{
|
||||
$dummy = Stub::makeEmptyExcept('DummyClass', 'getCheckMeToo', ['checkMeToo' => 'checked!']);
|
||||
$this->assertEquals('checked!', $dummy->getCheckMeToo());
|
||||
}
|
||||
|
||||
public function testFactory()
|
||||
{
|
||||
$dummies = Stub::factory('DummyClass', 2);
|
||||
$this->assertCount(2, $dummies);
|
||||
$this->assertInstanceOf('DummyClass', $dummies[0]);
|
||||
}
|
||||
|
||||
public function testMake()
|
||||
{
|
||||
$dummy = Stub::make('DummyClass', ['goodByeWorld' => fn(): string => 'hello world']);
|
||||
$this->assertEquals($this->dummy->helloWorld(), $dummy->helloWorld());
|
||||
$this->assertEquals("hello world", $dummy->goodByeWorld());
|
||||
}
|
||||
|
||||
public function testMakeMethodReplaced()
|
||||
{
|
||||
$dummy = Stub::make('DummyClass', ['helloWorld' => fn(): string => 'good bye world']);
|
||||
$this->assertMethodReplaced($dummy);
|
||||
}
|
||||
|
||||
public function testMakeWithMagicalPropertiesReplaced()
|
||||
{
|
||||
$dummy = Stub::make('DummyClass', ['checkMeToo' => 'checked!']);
|
||||
$this->assertEquals('checked!', $dummy->checkMeToo);
|
||||
}
|
||||
|
||||
public function testMakeMethodSimplyReplaced()
|
||||
{
|
||||
$dummy = Stub::make('DummyClass', ['helloWorld' => 'good bye world']);
|
||||
$this->assertMethodReplaced($dummy);
|
||||
}
|
||||
|
||||
public function testCopy()
|
||||
{
|
||||
$dummy = Stub::copy($this->dummy, ['checkMe' => 'checked!']);
|
||||
$this->assertEquals('checked!', $dummy->getCheckMe());
|
||||
$dummy = Stub::copy($this->dummy, ['checkMeToo' => 'checked!']);
|
||||
$this->assertEquals('checked!', $dummy->getCheckMeToo());
|
||||
}
|
||||
|
||||
public function testConstruct()
|
||||
{
|
||||
$dummy = Stub::construct('DummyClass', ['checkMe' => 'checked!']);
|
||||
$this->assertEquals('constructed: checked!', $dummy->getCheckMe());
|
||||
|
||||
$dummy = Stub::construct(
|
||||
'DummyClass',
|
||||
['checkMe' => 'checked!'],
|
||||
['targetMethod' => fn(): bool => false]
|
||||
);
|
||||
$this->assertEquals('constructed: checked!', $dummy->getCheckMe());
|
||||
$this->assertEquals(false, $dummy->targetMethod());
|
||||
}
|
||||
|
||||
public function testConstructMethodReplaced()
|
||||
{
|
||||
$dummy = Stub::construct(
|
||||
'DummyClass',
|
||||
[],
|
||||
['helloWorld' => fn(): string => 'good bye world']
|
||||
);
|
||||
$this->assertMethodReplaced($dummy);
|
||||
}
|
||||
|
||||
public function testConstructMethodSimplyReplaced()
|
||||
{
|
||||
$dummy = Stub::make('DummyClass', ['helloWorld' => 'good bye world']);
|
||||
$this->assertMethodReplaced($dummy);
|
||||
}
|
||||
|
||||
public function testConstructEmpty()
|
||||
{
|
||||
$dummy = Stub::constructEmpty('DummyClass', ['checkMe' => 'checked!']);
|
||||
$this->assertNull($dummy->getCheckMe());
|
||||
}
|
||||
|
||||
public function testConstructEmptyExcept()
|
||||
{
|
||||
$dummy = Stub::constructEmptyExcept('DummyClass', 'getCheckMe', ['checkMe' => 'checked!']);
|
||||
$this->assertNull($dummy->targetMethod());
|
||||
$this->assertEquals('constructed: checked!', $dummy->getCheckMe());
|
||||
}
|
||||
|
||||
public function testUpdate()
|
||||
{
|
||||
$dummy = Stub::construct('DummyClass');
|
||||
Stub::update($dummy, ['checkMe' => 'done']);
|
||||
$this->assertEquals('done', $dummy->getCheckMe());
|
||||
Stub::update($dummy, ['checkMeToo' => 'done']);
|
||||
$this->assertEquals('done', $dummy->getCheckMeToo());
|
||||
}
|
||||
|
||||
public function testStubsFromObject()
|
||||
{
|
||||
$dummy = Stub::make(new DummyClass());
|
||||
$this->assertInstanceOf(
|
||||
MockObject::class,
|
||||
$dummy
|
||||
);
|
||||
$dummy = Stub::make(new DummyOverloadableClass());
|
||||
$this->assertSame(DummyOverloadableClass::class, get_parent_class($dummy));
|
||||
$dummy = Stub::makeEmpty(new DummyClass());
|
||||
$this->assertInstanceOf(
|
||||
MockObject::class,
|
||||
$dummy
|
||||
);
|
||||
$dummy = Stub::makeEmpty(new DummyOverloadableClass());
|
||||
$this->assertSame(DummyOverloadableClass::class, get_parent_class($dummy));
|
||||
$dummy = Stub::makeEmptyExcept(new DummyClass(), 'helloWorld');
|
||||
$this->assertInstanceOf(
|
||||
MockObject::class,
|
||||
$dummy
|
||||
);
|
||||
$dummy = Stub::makeEmptyExcept(new DummyOverloadableClass(), 'helloWorld');
|
||||
$this->assertSame(DummyOverloadableClass::class, get_parent_class($dummy));
|
||||
$dummy = Stub::construct(new DummyClass());
|
||||
$this->assertInstanceOf(
|
||||
MockObject::class,
|
||||
$dummy
|
||||
);
|
||||
$dummy = Stub::construct(new DummyOverloadableClass());
|
||||
$this->assertSame(DummyOverloadableClass::class, get_parent_class($dummy));
|
||||
$dummy = Stub::constructEmpty(new DummyClass());
|
||||
$this->assertInstanceOf(
|
||||
MockObject::class,
|
||||
$dummy
|
||||
);
|
||||
$dummy = Stub::constructEmpty(new DummyOverloadableClass());
|
||||
$this->assertSame(DummyOverloadableClass::class, get_parent_class($dummy));
|
||||
$dummy = Stub::constructEmptyExcept(new DummyClass(), 'helloWorld');
|
||||
$this->assertInstanceOf(
|
||||
MockObject::class,
|
||||
$dummy
|
||||
);
|
||||
$dummy = Stub::constructEmptyExcept(new DummyOverloadableClass(), 'helloWorld');
|
||||
$this->assertSame(DummyOverloadableClass::class, get_parent_class($dummy));
|
||||
}
|
||||
|
||||
protected function assertMethodReplaced($dummy)
|
||||
{
|
||||
$this->assertTrue(method_exists($dummy, 'helloWorld'));
|
||||
$this->assertNotEquals($this->dummy->helloWorld(), $dummy->helloWorld());
|
||||
$this->assertEquals($dummy->helloWorld(), 'good bye world');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array<string|StubMarshaler>>
|
||||
*/
|
||||
public static function matcherAndFailMessageProvider(): array
|
||||
{
|
||||
return [
|
||||
[Stub\Expected::atLeastOnce(),
|
||||
'Expected invocation at least once but it never'
|
||||
],
|
||||
[Stub\Expected::once(),
|
||||
'Method was expected to be called 1 times, actually called 0 times.'
|
||||
],
|
||||
[Stub\Expected::exactly(1),
|
||||
'Method was expected to be called 1 times, actually called 0 times.'
|
||||
],
|
||||
[Stub\Expected::exactly(3),
|
||||
'Method was expected to be called 3 times, actually called 0 times.'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider matcherAndFailMessageProvider
|
||||
*/
|
||||
#[DataProvider('matcherAndFailMessageProvider')]
|
||||
public function testExpectedMethodIsCalledFail(StubMarshaler $stubMarshaler, string $failMessage)
|
||||
{
|
||||
$mock = Stub::makeEmptyExcept('DummyClass', 'call', ['targetMethod' => $stubMarshaler], $this);
|
||||
$mock->goodByeWorld();
|
||||
|
||||
try {
|
||||
$mock->__phpunit_verify();
|
||||
$this->fail('Expected exception');
|
||||
} catch (Exception $exception) {
|
||||
$this->assertTrue(strpos($failMessage, $exception->getMessage()) >= 0, 'String contains');
|
||||
|
||||
}
|
||||
|
||||
$this->resetMockObjects();
|
||||
}
|
||||
|
||||
public function testNeverExpectedMethodIsCalledFail()
|
||||
{
|
||||
$mock = Stub::makeEmptyExcept('DummyClass', 'call', ['targetMethod' => Stub\Expected::never()], $this);
|
||||
$mock->goodByeWorld();
|
||||
|
||||
try {
|
||||
$mock->call();
|
||||
} catch (Exception $e) {
|
||||
$this->assertTrue(strpos('was not expected to be called', $e->getMessage()) >= 0, 'String contains');
|
||||
}
|
||||
|
||||
$this->resetMockObjects();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array<int|bool|StubMarshaler|string|null>>
|
||||
*/
|
||||
public static function matcherProvider(): array
|
||||
{
|
||||
return [
|
||||
[0, Stub\Expected::never()],
|
||||
[1, Stub\Expected::once()],
|
||||
[2, Stub\Expected::atLeastOnce()],
|
||||
[3, Stub\Expected::exactly(3)],
|
||||
[1, Stub\Expected::once(fn(): bool => true)],
|
||||
[2, Stub\Expected::atLeastOnce(fn(): array => [])],
|
||||
[1, Stub\Expected::exactly(1, fn() => null)],
|
||||
[1, Stub\Expected::exactly(1, fn(): string => 'hello world!')],
|
||||
[1, Stub\Expected::exactly(1, 'hello world!')],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider matcherProvider
|
||||
*/
|
||||
#[DataProvider('matcherProvider')]
|
||||
public function testMethodMatcherWithMake(int $count, StubMarshaler $matcher, $expected = false)
|
||||
{
|
||||
$dummy = Stub::make('DummyClass', ['goodByeWorld' => $matcher], $this);
|
||||
|
||||
$this->repeatCall($count, [$dummy, 'goodByeWorld'], $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider matcherProvider
|
||||
*/
|
||||
#[DataProvider('matcherProvider')]
|
||||
public function testMethodMatcherWithMakeEmpty(int $count, StubMarshaler $matcher)
|
||||
{
|
||||
$dummy = Stub::makeEmpty('DummyClass', ['goodByeWorld' => $matcher], $this);
|
||||
|
||||
$this->repeatCall($count, [$dummy, 'goodByeWorld']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider matcherProvider
|
||||
*/
|
||||
#[DataProvider('matcherProvider')]
|
||||
public function testMethodMatcherWithMakeEmptyExcept(int $count, StubMarshaler $matcher)
|
||||
{
|
||||
$dummy = Stub::makeEmptyExcept('DummyClass', 'getCheckMe', ['goodByeWorld' => $matcher], $this);
|
||||
|
||||
$this->repeatCall($count, [$dummy, 'goodByeWorld']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider matcherProvider
|
||||
*/
|
||||
#[DataProvider('matcherProvider')]
|
||||
public function testMethodMatcherWithConstruct(int $count, StubMarshaler $matcher)
|
||||
{
|
||||
$dummy = Stub::construct('DummyClass', [], ['goodByeWorld' => $matcher], $this);
|
||||
|
||||
$this->repeatCall($count, [$dummy, 'goodByeWorld']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider matcherProvider
|
||||
*/
|
||||
#[DataProvider('matcherProvider')]
|
||||
public function testMethodMatcherWithConstructEmpty(int $count, StubMarshaler $matcher)
|
||||
{
|
||||
$dummy = Stub::constructEmpty('DummyClass', [], ['goodByeWorld' => $matcher], $this);
|
||||
|
||||
$this->repeatCall($count, [$dummy, 'goodByeWorld']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider matcherProvider
|
||||
*/
|
||||
#[DataProvider('matcherProvider')]
|
||||
public function testMethodMatcherWithConstructEmptyExcept(int $count, StubMarshaler $matcher)
|
||||
{
|
||||
$dummy = Stub::constructEmptyExcept(
|
||||
'DummyClass',
|
||||
'getCheckMe',
|
||||
[],
|
||||
['goodByeWorld' => $matcher],
|
||||
$this
|
||||
);
|
||||
|
||||
$this->repeatCall($count, [$dummy, 'goodByeWorld']);
|
||||
}
|
||||
|
||||
private function repeatCall($count, $callable, $expected = false)
|
||||
{
|
||||
for ($i = 0; $i < $count; ++$i) {
|
||||
$actual = call_user_func($callable);
|
||||
if ($expected) {
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testConsecutive()
|
||||
{
|
||||
$dummy = Stub::make('DummyClass', ['helloWorld' => Stub::consecutive('david', 'emma', 'sam', 'amy')]);
|
||||
|
||||
$this->assertEquals('david', $dummy->helloWorld());
|
||||
$this->assertEquals('emma', $dummy->helloWorld());
|
||||
$this->assertEquals('sam', $dummy->helloWorld());
|
||||
$this->assertEquals('amy', $dummy->helloWorld());
|
||||
|
||||
// Expected null value when no more values
|
||||
// For PHP 10.5.30 or higher an exception is thrown
|
||||
// https://github.com/sebastianbergmann/phpunit/commit/490879817a1417fd5fa1149a47b6f2f1b70ada6a
|
||||
if (version_compare(PHPUnitVersion::id(), '10.5.30', '>=')) {
|
||||
$this->expectException(NoMoreReturnValuesConfiguredException::class);
|
||||
$dummy->helloWorld();
|
||||
} else {
|
||||
$this->assertNull($dummy->helloWorld());
|
||||
}
|
||||
}
|
||||
|
||||
public function testStubPrivateProperties()
|
||||
{
|
||||
$tester = Stub::construct(
|
||||
'MyClassWithPrivateProperties',
|
||||
['name' => 'gamma'],
|
||||
[
|
||||
'randomName' => 'chicken',
|
||||
't' => 'ticky2',
|
||||
'getRandomName' => fn(): string => "randomstuff"
|
||||
]
|
||||
);
|
||||
$this->assertEquals('gamma', $tester->getName());
|
||||
$this->assertEquals('randomstuff', $tester->getRandomName());
|
||||
$this->assertEquals('ticky2', $tester->getT());
|
||||
}
|
||||
|
||||
public function testStubMakeEmptyInterface()
|
||||
{
|
||||
$stub = Stub::makeEmpty(Countable::class, ['count' => 5]);
|
||||
$this->assertEquals(5, $stub->count());
|
||||
}
|
||||
|
||||
public function testStubMakeEmptyAbstractClass()
|
||||
{
|
||||
if (version_compare(PHPUnitVersion::id(), '12', '>=')) {
|
||||
$this->expectException(RuntimeException::class);
|
||||
$this->expectExceptionMessage('PHPUnit 12 or greater does not allow to mock abstract classes anymore');
|
||||
}
|
||||
|
||||
$stub = Stub::make('DummyAbstractClass');
|
||||
$this->assertInstanceOf('DummyAbstractClass', $stub);
|
||||
}
|
||||
}
|
||||
|
||||
class MyClassWithPrivateProperties
|
||||
{
|
||||
|
||||
private string $name = '';
|
||||
|
||||
private string $randomName = 'gaia';
|
||||
|
||||
private string $t = 'ticky';
|
||||
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getRandomName(): string
|
||||
{
|
||||
return $this->randomName;
|
||||
}
|
||||
|
||||
public function getT(): string
|
||||
{
|
||||
return $this->t;
|
||||
}
|
||||
}
|
||||
79
vendor/codeception/stub/tests/StubTraitTest.php
vendored
Normal file
79
vendor/codeception/stub/tests/StubTraitTest.php
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Codeception\Stub\Expected;
|
||||
use Codeception\Test\Feature\Stub;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
require_once __DIR__ .'/ResetMocks.php';
|
||||
|
||||
final class StubTraitTest extends TestCase
|
||||
{
|
||||
use ResetMocks;
|
||||
use Stub;
|
||||
|
||||
protected DummyClass $dummy;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
require_once $file = __DIR__. '/_data/DummyOverloadableClass.php';
|
||||
require_once $file = __DIR__. '/_data/DummyClass.php';
|
||||
$this->dummy = new DummyClass(true);
|
||||
}
|
||||
|
||||
public function testMakeStubs()
|
||||
{
|
||||
$this->dummy = $this->make('DummyClass', ['helloWorld' => 'bye']);
|
||||
$this->assertEquals('bye', $this->dummy->helloWorld());
|
||||
$this->assertEquals('good bye', $this->dummy->goodByeWorld());
|
||||
|
||||
$this->dummy = $this->makeEmpty('DummyClass', ['helloWorld' => 'bye']);
|
||||
$this->assertEquals('bye', $this->dummy->helloWorld());
|
||||
$this->assertNull($this->dummy->goodByeWorld());
|
||||
|
||||
$this->dummy = $this->makeEmptyExcept('DummyClass', 'goodByeWorld', ['helloWorld' => 'bye']);
|
||||
$this->assertEquals('bye', $this->dummy->helloWorld());
|
||||
$this->assertEquals('good bye', $this->dummy->goodByeWorld());
|
||||
$this->assertNull($this->dummy->exceptionalMethod());
|
||||
}
|
||||
|
||||
public function testConstructStubs()
|
||||
{
|
||||
$this->dummy = $this->construct('DummyClass', ['!'], ['helloWorld' => 'bye']);
|
||||
$this->assertEquals('constructed: !', $this->dummy->getCheckMe());
|
||||
$this->assertEquals('bye', $this->dummy->helloWorld());
|
||||
$this->assertEquals('good bye', $this->dummy->goodByeWorld());
|
||||
|
||||
$this->dummy = $this->constructEmpty('DummyClass', ['!'], ['helloWorld' => 'bye']);
|
||||
$this->assertNull($this->dummy->getCheckMe());
|
||||
$this->assertEquals('bye', $this->dummy->helloWorld());
|
||||
$this->assertNull($this->dummy->goodByeWorld());
|
||||
|
||||
$this->dummy = $this->constructEmptyExcept('DummyClass', 'getCheckMe', ['!'], ['helloWorld' => 'bye']);
|
||||
$this->assertEquals('constructed: !', $this->dummy->getCheckMe());
|
||||
$this->assertEquals('bye', $this->dummy->helloWorld());
|
||||
$this->assertNull($this->dummy->goodByeWorld());
|
||||
$this->assertNull($this->dummy->exceptionalMethod());
|
||||
}
|
||||
|
||||
public function testMakeMocks()
|
||||
{
|
||||
$this->dummy = $this->make('DummyClass', [
|
||||
'helloWorld' => Expected::once()
|
||||
]);
|
||||
$this->dummy->helloWorld();
|
||||
try {
|
||||
$this->dummy->helloWorld();
|
||||
} catch (Exception $exception) {
|
||||
$this->assertTrue(
|
||||
strpos('was not expected to be called more than once', $exception->getMessage()) >= 0,
|
||||
'String contains'
|
||||
);
|
||||
$this->resetMockObjects();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->fail('No exception thrown');
|
||||
}
|
||||
}
|
||||
7
vendor/codeception/stub/tests/_data/DummyAbstractClass.php
vendored
Normal file
7
vendor/codeception/stub/tests/_data/DummyAbstractClass.php
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
abstract class DummyAbstractClass
|
||||
{
|
||||
}
|
||||
94
vendor/codeception/stub/tests/_data/DummyClass.php
vendored
Executable file
94
vendor/codeception/stub/tests/_data/DummyClass.php
vendored
Executable file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
class DummyClass
|
||||
{
|
||||
/**
|
||||
* @var int|string
|
||||
*/
|
||||
protected $checkMe = 1;
|
||||
|
||||
protected array $properties = ['checkMeToo' => 1];
|
||||
|
||||
function __construct($checkMe = 1)
|
||||
{
|
||||
$this->checkMe = 'constructed: '.$checkMe;
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function helloWorld()
|
||||
{
|
||||
return 'hello';
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function goodByeWorld()
|
||||
{
|
||||
return 'good bye';
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
protected function notYourBusinessWorld()
|
||||
{
|
||||
return 'goAway';
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getCheckMe()
|
||||
{
|
||||
return $this->checkMe;
|
||||
}
|
||||
|
||||
public function getCheckMeToo()
|
||||
{
|
||||
return $this->checkMeToo;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function call()
|
||||
{
|
||||
$this->targetMethod();
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function targetMethod()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function exceptionalMethod()
|
||||
{
|
||||
throw new Exception('Catch it!');
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
if ($this->isMagical($name)) {
|
||||
$this->properties[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
if ($this->__isset($name)) {
|
||||
return $this->properties[$name];
|
||||
}
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
return $this->isMagical($name) && isset($this->properties[$name]);
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
private function isMagical($name)
|
||||
{
|
||||
$reflectionClass = new ReflectionClass($this);
|
||||
return !$reflectionClass->hasProperty($name);
|
||||
}
|
||||
}
|
||||
93
vendor/codeception/stub/tests/_data/DummyOverloadableClass.php
vendored
Normal file
93
vendor/codeception/stub/tests/_data/DummyOverloadableClass.php
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
class DummyOverloadableClass
|
||||
{
|
||||
/**
|
||||
* @var int|string
|
||||
*/
|
||||
protected $checkMe = 1;
|
||||
|
||||
protected array $properties = ['checkMeToo' => 1];
|
||||
|
||||
function __construct($checkMe = 1)
|
||||
{
|
||||
$this->checkMe = 'constructed: '.$checkMe;
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function helloWorld()
|
||||
{
|
||||
return 'hello';
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function goodByeWorld()
|
||||
{
|
||||
return 'good bye';
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
protected function notYourBusinessWorld()
|
||||
{
|
||||
return 'goAway';
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getCheckMe()
|
||||
{
|
||||
return $this->checkMe;
|
||||
}
|
||||
|
||||
public function getCheckMeToo()
|
||||
{
|
||||
return $this->checkMeToo;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function call()
|
||||
{
|
||||
$this->targetMethod();
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function targetMethod()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function exceptionalMethod()
|
||||
{
|
||||
throw new Exception('Catch it!');
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
//seeing as we're not implementing __set here, add check for __mocked
|
||||
$return = null;
|
||||
if ($name === '__mocked') {
|
||||
$return = property_exists($this, '__mocked') && $this->__mocked !== null ? $this->__mocked : null;
|
||||
} elseif ($this->__isset($name)) {
|
||||
$return = $this->properties[$name];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
return $this->isMagical($name) && isset($this->properties[$name]);
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
private function isMagical($name)
|
||||
{
|
||||
$reflectionClass = new ReflectionClass($this);
|
||||
return !$reflectionClass->hasProperty($name);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user