This commit is contained in:
2020-02-01 16:47:12 +07:00
commit 4c619ad6e6
16739 changed files with 3329179 additions and 0 deletions

3
vendor/codeception/specify/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
vendor
.idea
composer.phar

10
vendor/codeception/specify/.travis.yml vendored Normal file
View File

@@ -0,0 +1,10 @@
language: php
php:
- 5.4
- 5.5
- 5.6
- 7
before_script:
- composer install

26
vendor/codeception/specify/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,26 @@
# Changelog
#### 0.4.2
* Testing exception messages by @chrismichaels84 https://github.com/Codeception/Specify#exceptions
#### 0.4.0
* Fixes cloning properties in examples. Issue #6 *2014-10-15*
* Added global and local specify configs, for disabling cloning properties and changing cloning methods *2014-10-15*
#### 0.3.6 03/22/2014
* Cloning unclonnable items
#### 0.3.5 03/22/2014
* Updated to DeepCopy 1.1.0
#### 0.3.4 02/23/2014
* Added DeepCopy library to save/restore objects between specs
* Robo file for releases

20
vendor/codeception/specify/LICENSE vendored Normal file
View File

@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 Codeception PHP Testing Framework
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.

251
vendor/codeception/specify/README.md vendored Normal file
View File

@@ -0,0 +1,251 @@
Specify
=======
BDD style code blocks for PHPUnit / Codeception
Specify allows you to write your tests in more readable BDD style, the same way you might have experienced with [Jasmine](https://jasmine.github.io/).
Inspired by MiniTest of Ruby now you combine BDD and classical TDD style in one test.
[![Build Status](https://travis-ci.org/Codeception/Specify.png?branch=master)](https://travis-ci.org/Codeception/Specify) [![Latest Stable Version](https://poser.pugx.org/codeception/specify/v/stable.png)](https://packagist.org/packages/codeception/specify)
Additionaly, we recommend to combine this with [**Codeception/Verify**](https://github.com/Codeception/Verify) library, to get BDD style assertions.
``` php
<?php
class UserTest extends PHPUnit_Framework_TestCase {
use Codeception\Specify;
public function setUp()
{
$this->user = new User;
}
public function testValidation()
{
$this->assertInstanceOf('Model', $this->user);
$this->specify("username is required", function() {
$this->user->username = null;
verify($this->user->validate(['username'])->false());
});
$this->specify("username is too long", function() {
$this->user->username = 'toolooooongnaaaaaaameeee',
verify($this->user->validate(['username'])->false());
});
// alternative, TDD assertions can be used too.
$this->specify("username is ok", function() {
$this->user->username = 'davert',
$this->assertTrue($this->user->validate(['username']));
});
}
}
?>
```
## Purpose
This tiny library makes your tests a bit readable, by orginizing test in well described code blocks.
Each code block is isolated.
This means call to `$this->specify` does not affect any instance variable of a test class.
``` php
<?php
$this->user->name = 'davert';
$this->specify("i can change my name", function() {
$this->user->name = 'jon';
$this->assertEquals('jon', $this->user->name);
});
$this->assertEquals('davert', $this->user->name);
?>
```
Failure in `specify` block won't get your test stopped.
``` php
<?php
$this->specify("failing but test goes on", function() {
$this->fail('bye');
});
$this->assertTrue(true);
// Assertions: 2, Failures: 1
?>
```
If a test fails you will see specification text in the result.
## Isolation
Isolation is achieved by **cloning object properties** for each specify block.
By default objects are cloned using deep cloning method.
This behavior can be customized in order to speed up test execution by preventing some objects from cloning or switching to shallow cloning using `clone` operator.
Some properties can be ignored from cloning using either global or local config settings.
### Global Configuration
Cloning configuration can be set globally
```php
<?php
// globally disabling cloning of properties
Codeception\Specify\Config::setIgnoredProperties(['user', 'repository']);
?>
```
See complete [reference](https://github.com/Codeception/Specify/blob/master/docs/GlobalConfig.md).
### Local Configuration
Configuring can be done locally per test case
```php
<?php
class UserTest extends \PHPUnit_Framework_TestCase
{
use Codeception\Specify;
function testUser()
{
// do not deep clone user property
$this->specifyConfig()
->shallowClone('user');
}
}
```
Only specific properties can be preserved in specify blocks:
```php
<?php
class UserTest extends \PHPUnit_Framework_TestCase
{
use Codeception\Specify;
protected $user;
protected $post;
function testUser()
{
$this->user = 'davert';
$this->post = 'hello world';
$this->specifyConfig()
->cloneOnly('user');
$this->specify('post is not cloned', function() {
$this->user = 'john';
$this->post = 'bye world';
});
$this->assertEquals('davert', $this->user); // user is restored
$this->assertEquals('bye world', $this->post); // post was not stored
}
}
```
[Reference](https://github.com/Codeception/Specify/blob/master/docs/LocalConfig.md)
## Exceptions
You can wait for exception thrown inside a block.
``` php
<?php
$this->specify('404 if user does not exist', function() {
$this->userController->show(999);
}, ['throws' => 'NotFoundException']);
// alternatively
$this->specify('404 if user does not exist', function() {
$this->userController->show(999);
}, ['throws' => new NotFoundException]);
?>
```
Also you can handle fails inside a block.
``` php
<?php
$this->specify('this assertion is failing', function() {
$this->assertEquals(2, 3+5);
}, ['throws' => 'fail']);
?>
```
In both cases, you can optionally test the exception message
``` php
<?php
$this->specify('some exception with a message', function() {
throw new NotFoundException('my error message');
}, ['throws' => ['NotFoundException', 'my error message']]);
?>
```
## Examples
DataProviders alternative. Quite useful for basic data providers.
``` php
<?php
$this->specify("should calculate square numbers", function($number, $square) {
$this->assertEquals($square, $number*$number);
}, ['examples' => [
[2,4],
[3,9]
]]);
?>
```
You can also use DataProvider functions in `examples` param.
``` php
<?php
$this->specify("should calculate square numbers", function($number, $square) {
$this->assertEquals($square, $number*$number);
}, ['examples' => $this->provider()]);
?>
```
## Before/After
There are also before and after callbacks, which act as setUp/tearDown but only for specify.
``` php
<?php
$this->beforeSpecify(function() {
// prepare something;
});
$this->afterSpecify(function() {
// reset something
});
$this->cleanSpecify(); // removes before/after callbacks
?>
```
## Installation
*Requires PHP >= 5.4.*
Install with Composer:
```json
"require-dev": {
"codeception/specify": "*",
"codeception/verify": "*"
}
```
Include `Codeception\Specify` trait into your test.
License: MIT

51
vendor/codeception/specify/RoboFile.php vendored Normal file
View File

@@ -0,0 +1,51 @@
<?php
require_once __DIR__.'/vendor/autoload.php';
class Robofile extends \Robo\Tasks
{
public function release()
{
$this->test();
$version = file_get_contents('VERSION');
$this->docs();
// create GitHub release
$this->taskGitHubRelease($version)
->uri('Codeception/Specify')
->askDescription()
->run();
}
public function changed($description)
{
$this->taskChangelog()
->version(file_get_contents('VERSION'))
->change($description)
->run();
}
protected $docs = [
'docs/GlobalConfig.md' => '\Codeception\Specify\Config',
'docs/LocalConfig.md' => '\Codeception\Specify\ConfigBuilder',
];
public function docs()
{
foreach ($this->docs as $file => $class) {
class_exists($class, true);
$this->taskGenDoc($file)
->docClass($class)
->processProperty(false)
->run();
}
}
public function test()
{
$res = $this->taskPHPUnit()->run();
if (!$res) exit;
}
}

1
vendor/codeception/specify/VERSION vendored Normal file
View File

@@ -0,0 +1 @@
0.4.2

View File

@@ -0,0 +1,24 @@
{
"name": "codeception/specify",
"description": "BDD code blocks for PHPUnit and Codeception",
"minimum-stability": "stable",
"license": "MIT",
"authors": [
{
"name": "Michael Bodnarchuk",
"email": "davert.php@mailican.com"
}
],
"require": {
"php": ">=5.4.0",
"myclabs/deep-copy": "~1.1"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"autoload": {
"psr-0": {
"Codeception\\": "src/"
}
}
}

805
vendor/codeception/specify/composer.lock generated vendored Normal file
View File

@@ -0,0 +1,805 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "d9f26c1a29043f49648df159c61f0f18",
"packages": [
{
"name": "myclabs/deep-copy",
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "f0cb3bd7eddef40adcc1a1aaeaf569ceb3164532"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/f0cb3bd7eddef40adcc1a1aaeaf569ceb3164532",
"reference": "f0cb3bd7eddef40adcc1a1aaeaf569ceb3164532",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"require-dev": {
"doctrine/collections": "1.*",
"phpunit/phpunit": "~4.1"
},
"type": "library",
"autoload": {
"psr-4": {
"DeepCopy\\": "src/DeepCopy/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Create deep copies (clones) of your objects",
"homepage": "https://github.com/myclabs/DeepCopy",
"keywords": [
"clone",
"copy",
"duplicate",
"object",
"object graph"
],
"time": "2014-08-29 00:01:20"
}
],
"packages-dev": [
{
"name": "doctrine/instantiator",
"version": "1.0.4",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
"reference": "f976e5de371104877ebc89bd8fecb0019ed9c119"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/f976e5de371104877ebc89bd8fecb0019ed9c119",
"reference": "f976e5de371104877ebc89bd8fecb0019ed9c119",
"shasum": ""
},
"require": {
"php": ">=5.3,<8.0-DEV"
},
"require-dev": {
"athletic/athletic": "~0.1.8",
"ext-pdo": "*",
"ext-phar": "*",
"phpunit/phpunit": "~4.0",
"squizlabs/php_codesniffer": "2.0.*@ALPHA"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Instantiator\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com",
"homepage": "http://ocramius.github.com/"
}
],
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
"homepage": "https://github.com/doctrine/instantiator",
"keywords": [
"constructor",
"instantiate"
],
"time": "2014-10-13 12:58:55"
},
{
"name": "phpunit/php-code-coverage",
"version": "2.0.11",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "53603b3c995f5aab6b59c8e08c3a663d2cc810b7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/53603b3c995f5aab6b59c8e08c3a663d2cc810b7",
"reference": "53603b3c995f5aab6b59c8e08c3a663d2cc810b7",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"phpunit/php-file-iterator": "~1.3",
"phpunit/php-text-template": "~1.2",
"phpunit/php-token-stream": "~1.3",
"sebastian/environment": "~1.0",
"sebastian/version": "~1.0"
},
"require-dev": {
"ext-xdebug": ">=2.1.4",
"phpunit/phpunit": "~4.1"
},
"suggest": {
"ext-dom": "*",
"ext-xdebug": ">=2.2.1",
"ext-xmlwriter": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
"homepage": "https://github.com/sebastianbergmann/php-code-coverage",
"keywords": [
"coverage",
"testing",
"xunit"
],
"time": "2014-08-31 06:33:04"
},
{
"name": "phpunit/php-file-iterator",
"version": "1.3.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "acd690379117b042d1c8af1fafd61bde001bf6bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb",
"reference": "acd690379117b042d1c8af1fafd61bde001bf6bb",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"classmap": [
"File/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "FilterIterator implementation that filters files based on a list of suffixes.",
"homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
"keywords": [
"filesystem",
"iterator"
],
"time": "2013-10-10 15:34:57"
},
{
"name": "phpunit/php-text-template",
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-text-template.git",
"reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
"reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"classmap": [
"Text/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Simple template engine.",
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
"keywords": [
"template"
],
"time": "2014-01-30 17:20:04"
},
{
"name": "phpunit/php-timer",
"version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
"reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
"reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"classmap": [
"PHP/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Utility class for timing",
"homepage": "https://github.com/sebastianbergmann/php-timer/",
"keywords": [
"timer"
],
"time": "2013-08-02 07:42:54"
},
{
"name": "phpunit/php-token-stream",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "f8d5d08c56de5cfd592b3340424a81733259a876"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/f8d5d08c56de5cfd592b3340424a81733259a876",
"reference": "f8d5d08c56de5cfd592b3340424a81733259a876",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Wrapper around PHP's tokenizer extension.",
"homepage": "https://github.com/sebastianbergmann/php-token-stream/",
"keywords": [
"tokenizer"
],
"time": "2014-08-31 06:12:13"
},
{
"name": "phpunit/phpunit",
"version": "4.3.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "06005259429c156c02596add91f6a59c7dc3d4af"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/06005259429c156c02596add91f6a59c7dc3d4af",
"reference": "06005259429c156c02596add91f6a59c7dc3d4af",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-json": "*",
"ext-pcre": "*",
"ext-reflection": "*",
"ext-spl": "*",
"php": ">=5.3.3",
"phpunit/php-code-coverage": "~2.0",
"phpunit/php-file-iterator": "~1.3.1",
"phpunit/php-text-template": "~1.2",
"phpunit/php-timer": "~1.0.2",
"phpunit/phpunit-mock-objects": "~2.3",
"sebastian/comparator": "~1.0",
"sebastian/diff": "~1.1",
"sebastian/environment": "~1.0",
"sebastian/exporter": "~1.0",
"sebastian/version": "~1.0",
"symfony/yaml": "~2.0"
},
"suggest": {
"phpunit/php-invoker": "~1.1"
},
"bin": [
"phpunit"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.3.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
"",
"../../symfony/yaml/"
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "The PHP Unit Testing framework.",
"homepage": "http://www.phpunit.de/",
"keywords": [
"phpunit",
"testing",
"xunit"
],
"time": "2014-10-06 06:20:35"
},
{
"name": "phpunit/phpunit-mock-objects",
"version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
"reference": "c63d2367247365f688544f0d500af90a11a44c65"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/c63d2367247365f688544f0d500af90a11a44c65",
"reference": "c63d2367247365f688544f0d500af90a11a44c65",
"shasum": ""
},
"require": {
"doctrine/instantiator": "~1.0,>=1.0.1",
"php": ">=5.3.3",
"phpunit/php-text-template": "~1.2"
},
"require-dev": {
"phpunit/phpunit": "~4.3"
},
"suggest": {
"ext-soap": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Mock Object library for PHPUnit",
"homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
"keywords": [
"mock",
"xunit"
],
"time": "2014-10-03 05:12:11"
},
{
"name": "sebastian/comparator",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "e54a01c0da1b87db3c5a3c4c5277ddf331da4aef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e54a01c0da1b87db3c5a3c4c5277ddf331da4aef",
"reference": "e54a01c0da1b87db3c5a3c4c5277ddf331da4aef",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"sebastian/diff": "~1.1",
"sebastian/exporter": "~1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Volker Dusch",
"email": "github@wallbash.com"
},
{
"name": "Bernhard Schussek",
"email": "bschussek@2bepublished.at"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Provides the functionality to compare PHP values for equality",
"homepage": "http://www.github.com/sebastianbergmann/comparator",
"keywords": [
"comparator",
"compare",
"equality"
],
"time": "2014-05-11 23:00:21"
},
{
"name": "sebastian/diff",
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "5843509fed39dee4b356a306401e9dd1a931fec7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/5843509fed39dee4b356a306401e9dd1a931fec7",
"reference": "5843509fed39dee4b356a306401e9dd1a931fec7",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Kore Nordmann",
"email": "mail@kore-nordmann.de"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Diff implementation",
"homepage": "http://www.github.com/sebastianbergmann/diff",
"keywords": [
"diff"
],
"time": "2014-08-15 10:29:00"
},
{
"name": "sebastian/environment",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "6288ebbf6fa3ed2b2ff2d69c356fbaaf4f0971a7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6288ebbf6fa3ed2b2ff2d69c356fbaaf4f0971a7",
"reference": "6288ebbf6fa3ed2b2ff2d69c356fbaaf4f0971a7",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Provides functionality to handle HHVM/PHP environments",
"homepage": "http://www.github.com/sebastianbergmann/environment",
"keywords": [
"Xdebug",
"environment",
"hhvm"
],
"time": "2014-10-07 09:23:16"
},
{
"name": "sebastian/exporter",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "c7d59948d6e82818e1bdff7cadb6c34710eb7dc0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c7d59948d6e82818e1bdff7cadb6c34710eb7dc0",
"reference": "c7d59948d6e82818e1bdff7cadb6c34710eb7dc0",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Volker Dusch",
"email": "github@wallbash.com"
},
{
"name": "Bernhard Schussek",
"email": "bschussek@2bepublished.at"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
},
{
"name": "Adam Harvey",
"email": "aharvey@php.net"
}
],
"description": "Provides the functionality to export PHP variables for visualization",
"homepage": "http://www.github.com/sebastianbergmann/exporter",
"keywords": [
"export",
"exporter"
],
"time": "2014-09-10 00:51:36"
},
{
"name": "sebastian/version",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/version.git",
"reference": "b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43",
"reference": "b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43",
"shasum": ""
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
"time": "2014-03-07 15:35:33"
},
{
"name": "symfony/yaml",
"version": "v2.5.5",
"target-dir": "Symfony/Component/Yaml",
"source": {
"type": "git",
"url": "https://github.com/symfony/Yaml.git",
"reference": "b1dbc53593b98c2d694ebf383660ac9134d30b96"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/b1dbc53593b98c2d694ebf383660ac9134d30b96",
"reference": "b1dbc53593b98c2d694ebf383660ac9134d30b96",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.5-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\Yaml\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Symfony Yaml Component",
"homepage": "http://symfony.com",
"time": "2014-09-22 09:14:18"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"platform": {
"php": ">=5.4.0"
},
"platform-dev": []
}

View File

@@ -0,0 +1,50 @@
## Codeception\Specify\Config
Global Specify configuration. Should be set in bootstrap.
```php
<?php
// disable deep cloning of properties inside specify block
\Codeception\Specify\Config::setDeepClone(false);
?>
```
#### *public* propertyIgnored($property)
#### *public* classIgnored($value)
#### *public* propertyIsShallowCloned($property)
#### *public* propertyIsDeeplyCloned($property)
#### *public static* setDeepClone($deepClone)
Enable or disable using of deep cloning for objects by default.
Deep cloning is the default.
* `param boolean` $deepClone
#### *public static* setIgnoredClasses($ignoredClasses)
#### *public static* setIgnoredProperties($ignoredProperties)
Globally set class properties are going to be ignored for cloning in specify blocks.
```php
<?php
\Codeception\Specify\Config::setIgnoredProperties(['users', 'repository']);
```
* `param array` $ignoredProperties
#### *public static* addIgnoredClasses($ignoredClasses)
Add specific classes to cloning ignore list. Instances of those classes won't be cloned for specify blocks.
```php
<?php
\Codeception\Specify\Config::addIgnoredClasses(['\Acme\Domain\UserRepo', '\Acme\Domain\PostRepo']);
?>
```
* `param` $ignoredClasses
#### *public static* create()
@return Config

View File

@@ -0,0 +1,110 @@
## Codeception\Specify\ConfigBuilder
Configure Specify usage.
Specify copies properties of object and restores them for each specify block.
Objects can be cloned deeply or using standard `clone` operator.
Specify can be configured to prevent specific properties in specify blocks, to choose default cloning method,
or cloning method for specific properties.
```php
<?php
$this->specifyConfig()
->ignore('user') // do not clone
?>
```
#### *public* __construct($config = null)
#### *public* ignore($properties = null)
Ignore cloning specific object properties in specify blocks.
```php
<?php
$this->user = new User;
$this->specifyConfig()->ignore('user');
$this->specify('change user name', function() {
$this->user->name = 'davert';
});
$this->user->name == 'davert'; // name changed
?>
```
* `param array` $properties
* `return` $this
#### *public* ignoreClasses($classes = null)
Adds specific class to ignore list, if property is an instance of class it will not be cloned for specify block.
* `param array` $classes
* `return` $this
#### *public* deepClone($properties = null)
Turn on/off deep cloning mode.
Deep cloning mode can also be specified for specific properties.
```php
<?php
$this->user = new User;
$this->post = new Post;
$this->tag = new Tag;
// turn on deep cloning by default
$this->specifyConfig()->deepClone();
// turn off deep cloning by default
$this->specifyConfig()->deepClone(false);
// deep clone only user and tag property
$this->specifyConfig()->deepClone('user', 'tag');
// alternatively
$this->specifyConfig()->deepClone(['user', 'tag']);
?>
```
* `param bool` $properties
* `return` $this
#### *public* shallowClone($properties = null)
Disable deep cloning mode, use shallow cloning by default, which is faster.
Deep cloning mode can also be disabled for specific properties.
```php
<?php
$this->user = new User;
$this->post = new Post;
$this->tag = new Tag;
// turn off deep cloning by default
$this->specifyConfig()->shallowClone();
// turn on deep cloning by default
$this->specifyConfig()->shallowClone(false);
// shallow clone only user and tag property
$this->specifyConfig()->shallowClone('user', 'tag');
// alternatively
$this->specifyConfig()->shallowClone(['user', 'tag']);
?>
```
* `param bool` $properties
* `return` $this
#### *public* cloneOnly($properties)
Clone only specific properties
```php
<?php
$this->specifyConfig()->cloneOnly('user', 'post');
?>
```
* `param` $properties
* `return` $this

View File

@@ -0,0 +1,8 @@
<phpunit colors="true"
bootstrap="tests/_bootstrap.php">
<testsuites>
<testsuite name="Specify">
<directory>tests</directory>
</testsuite>
</testsuites>
</phpunit>

View File

@@ -0,0 +1,288 @@
<?php
namespace Codeception;
use Codeception\Specify\Config;
use Codeception\Specify\ConfigBuilder;
use Codeception\Specify\ObjectProperty;
trait Specify
{
private $beforeSpecify = array();
private $afterSpecify = array();
/**
* @var Specify\Config
*/
private $specifyConfig;
/**
* @var \DeepCopy\DeepCopy()
*/
private $copier;
private function specifyInit()
{
if ($this->copier) return;
$this->copier = new \DeepCopy\DeepCopy();
$this->copier->skipUncloneable();
if (!$this->specifyConfig) $this->specifyConfig = Config::create();
}
function specify($specification, \Closure $callable = null, $params = [])
{
if (!$callable) return;
$this->specifyInit();
$test = $callable->bindTo($this);
$oldName = $this->getName();
$newName = $oldName . ' | ' . $specification;
$this->setName($newName);
$properties = $this->getSpecifyObjectProperties();
// prepare for execution
$throws = $this->getSpecifyExpectedException($params);
$examples = $this->getSpecifyExamples($params);
$showExamplesIndex = $examples !== [[]];
foreach ($examples as $idx => $example) {
if ($showExamplesIndex) {
$this->setName($newName . ' | examples index ' . $idx);
}
// copy current object properties
$this->specifyCloneProperties($properties);
if (!empty($this->beforeSpecify) && is_array($this->beforeSpecify)) {
foreach ($this->beforeSpecify as $closure) {
if ($closure instanceof \Closure) $closure->__invoke();
}
}
$this->specifyExecute($test, $throws, $example);
// restore object properties
$this->specifyRestoreProperties($properties);
if (!empty($this->afterSpecify) && is_array($this->afterSpecify)) {
foreach ($this->afterSpecify as $closure) {
if ($closure instanceof \Closure) $closure->__invoke();
}
}
}
// restore test name
$this->setName($oldName);
}
/**
* @param $params
* @return array
* @throws \RuntimeException
*/
private function getSpecifyExamples($params)
{
if (isset($params['examples'])) {
if (!is_array($params['examples'])) throw new \RuntimeException("Examples should be an array");
return $params['examples'];
}
return [[]];
}
private function getSpecifyExpectedException($params)
{
if (isset($params['throws'])) {
$throws = (is_array($params['throws'])) ? $params['throws'][0] : $params['throws'];
if (is_object($throws)) {
$throws = get_class($throws);
}
if ($throws === 'fail') {
$throws = 'PHPUnit_Framework_AssertionFailedError';
}
$message = (is_array($params['throws']) && isset($params['throws'][1])) ? $params['throws'][1] : false;
return [$throws, $message];
}
return false;
}
private function specifyExecute($test, $throws = false, $examples = array())
{
$message = false;
if (is_array($throws)) {
$message = ($throws[1]) ? strtolower($throws[1]) : false;
$throws = $throws[0];
}
$result = $this->getTestResultObject();
try {
call_user_func_array($test, $examples);
$this->specifyCheckMockObjects();
} catch (\PHPUnit_Framework_AssertionFailedError $e) {
if ($throws !== get_class($e)){
$result->addFailure(clone($this), $e, $result->time());
}
if ($message !==false && $message !== strtolower($e->getMessage())) {
$f = new \PHPUnit_Framework_AssertionFailedError("exception message '$message' was expected, but '" . $e->getMessage() . "' was received");
$result->addFailure(clone($this), $f, $result->time());
}
} catch (\Exception $e) {
if ($throws) {
if ($throws !== get_class($e)) {
$f = new \PHPUnit_Framework_AssertionFailedError("exception '$throws' was expected, but " . get_class($e) . ' was thrown');
$result->addFailure(clone($this), $f, $result->time());
}
if ($message !==false && $message !== strtolower($e->getMessage())) {
$f = new \PHPUnit_Framework_AssertionFailedError("exception message '$message' was expected, but '" . $e->getMessage() . "' was received");
$result->addFailure(clone($this), $f, $result->time());
}
} else {
throw $e;
}
}
if ($throws) {
if (isset($e)) {
$this->assertTrue(true, 'exception handled');
} else {
$f = new \PHPUnit_Framework_AssertionFailedError("exception '$throws' was not thrown as expected");
$result->addFailure(clone($this), $f, $result->time());
}
}
}
public function specifyConfig()
{
if (!$this->specifyConfig) $this->specifyConfig = Config::create();
return new ConfigBuilder($this->specifyConfig);
}
function beforeSpecify(\Closure $callable = null)
{
$this->beforeSpecify[] = $callable->bindTo($this);
}
function afterSpecify(\Closure $callable = null)
{
$this->afterSpecify[] = $callable->bindTo($this);
}
function cleanSpecify()
{
$this->beforeSpecify = $this->afterSpecify = array();
}
/**
* @param ObjectProperty[] $properties
*/
private function specifyCloneProperties($properties)
{
foreach ($properties as $property) {
$propertyName = $property->getName();
$propertyValue = $property->getValue();
if ($this->specifyConfig->classIgnored($propertyValue)) {
continue;
}
if ($this->specifyConfig->propertyIsShallowCloned($propertyName)) {
if (is_object($propertyValue)) {
$property->setValue(clone $propertyValue);
} else {
$property->setValue($propertyValue);
}
}
if ($this->specifyConfig->propertyIsDeeplyCloned($propertyName)) {
$property->setValue($this->copier->copy($propertyValue));
}
}
}
/**
* @param ObjectProperty[] $properties
*/
private function specifyRestoreProperties($properties)
{
foreach ($properties as $property) {
$property->restoreValue();
}
}
/**
* @return ObjectProperty[]
*/
private function getSpecifyObjectProperties()
{
$objectReflection = new \ReflectionObject($this);
$propertiesToClone = $objectReflection->getProperties();
if (($classProperties = $this->specifyGetClassPrivateProperties()) !== []) {
$propertiesToClone = array_merge($propertiesToClone, $classProperties);
}
$properties = [];
foreach ($propertiesToClone as $property) {
if ($this->specifyConfig->propertyIgnored($property->getName())) {
continue;
}
$properties[] = new ObjectProperty($this, $property);
}
// isolate mockObjects property from PHPUnit_Framework_TestCase
if (($phpUnitReflection = $this->specifyGetPhpUnitReflection()) !== null) {
$properties[] = $mockObjects = new ObjectProperty(
$this, $phpUnitReflection->getProperty('mockObjects')
);
// remove all mock objects inherited from parent scope(s)
$mockObjects->setValue([]);
}
return $properties;
}
private function specifyCheckMockObjects()
{
if (($phpUnitReflection = $this->specifyGetPhpUnitReflection()) !== null) {
$verifyMockObjects = $phpUnitReflection->getMethod('verifyMockObjects');
$verifyMockObjects->setAccessible(true);
$verifyMockObjects->invoke($this);
}
}
private function specifyGetClassPrivateProperties()
{
static $properties = [];
if (!isset($properties[__CLASS__])) {
$reflection = new \ReflectionClass(__CLASS__);
$properties[__CLASS__] = (get_class($this) !== __CLASS__)
? $reflection->getProperties(\ReflectionProperty::IS_PRIVATE) : [];
}
return $properties[__CLASS__];
}
/**
* @return \ReflectionClass|null
*/
private function specifyGetPhpUnitReflection()
{
if ($this instanceof \PHPUnit_Framework_TestCase) {
return new \ReflectionClass('\PHPUnit_Framework_TestCase');
}
}
}

View File

@@ -0,0 +1,156 @@
<?php
namespace Codeception\Specify;
/**
* Global Specify configuration. Should be set in bootstrap.
*
* ```php
* <?php
* // disable deep cloning of properties inside specify block
* \Codeception\Specify\Config::setDeepClone(false);
* ?>
* ```
*/
class Config
{
protected static $ignoredClasses = [
'Codeception\Actor',
'Symfony\Component\EventDispatcher\EventDispatcher',
'Codeception\Scenario',
'Codeception\Lib\Parser'
];
protected static $ignoredProperties = [
// PHPUnit
'backupGlobals',
'backupGlobalsBlacklist',
'backupStaticAttributes',
'backupStaticAttributesBlacklist',
'runTestInSeparateProcess',
'preserveGlobalState',
// Codeception
'dependencies',
'dependencyInput',
'tester',
'guy',
'name'
];
protected static $deepClone = true;
public $is_deep = true;
public $ignore = array();
public $ignore_classes = array();
public $shallow = array();
public $deep = array();
public $only = null;
public function propertyIgnored($property)
{
if ($this->only) {
return !in_array($property, $this->only);
}
return in_array($property, $this->ignore);
}
public function classIgnored($value)
{
if (!is_object($value)) return false;
return in_array(get_class($value), $this->ignore_classes);
}
public function propertyIsShallowCloned($property)
{
if ($this->only and !$this->is_deep) {
return in_array($property, $this->only);
}
if (!$this->is_deep and !in_array($property, $this->deep)) {
return true;
}
return in_array($property, $this->shallow);
}
public function propertyIsDeeplyCloned($property)
{
if ($this->only and $this->is_deep) {
return in_array($property, $this->only);
}
if ($this->is_deep and !in_array($property, $this->shallow)) {
return true;
}
return in_array($property, $this->deep);
}
/**
* Enable or disable using of deep cloning for objects by default.
* Deep cloning is the default.
*
* @param boolean $deepClone
*/
public static function setDeepClone($deepClone)
{
self::$deepClone = $deepClone;
}
/***
* Set classes which are going to be ignored for cloning in specify blocks.
*
* @param array $ignoredClasses
*/
public static function setIgnoredClasses($ignoredClasses)
{
self::$ignoredClasses = $ignoredClasses;
}
/**
* Globally set class properties are going to be ignored for cloning in specify blocks.
*
* ```php
* <?php
* \Codeception\Specify\Config::setIgnoredProperties(['users', 'repository']);
* ```
*
* @param array $ignoredProperties
*/
public static function setIgnoredProperties($ignoredProperties)
{
self::$ignoredProperties = $ignoredProperties;
}
/**
* Add specific classes to cloning ignore list. Instances of those classes won't be cloned for specify blocks.
*
* ```php
* <?php
* \Codeception\Specify\Config::addIgnoredClasses(['\Acme\Domain\UserRepo', '\Acme\Domain\PostRepo']);
* ?>
* ```
*
* @param $ignoredClasses
*/
public static function addIgnoredClasses($ignoredClasses)
{
self::$ignoredClasses = array_merge(self::$ignoredClasses, $ignoredClasses);
}
private function __construct()
{
}
/**
* @return Config
*/
static function create()
{
$config = new Config();
$config->is_deep = self::$deepClone;
$config->ignore = self::$ignoredProperties;
$config->ignore_classes = self::$ignoredClasses;
$config->shallow = array();
$config->deep = array();
$config->only = null;
return $config;
}
}

View File

@@ -0,0 +1,172 @@
<?php
namespace Codeception\Specify;
/**
* Configure Specify usage.
*
* Specify copies properties of object and restores them for each specify block.
* Objects can be cloned deeply or using standard `clone` operator.
* Specify can be configured to prevent specific properties in specify blocks, to choose default cloning method,
* or cloning method for specific properties.
*
* ```php
* <?php
* $this->specifyConfig()
* ->ignore('user') // do not clone
* ?>
* ```
*/
class ConfigBuilder
{
/**
* @var Config
*/
protected $config;
public function __construct(Config $config = null)
{
$this->config = $config;
if (!$config) {
$this->config = Config::create();
}
}
/**
* Ignore cloning specific object properties in specify blocks.
*
* ```php
* <?php
* $this->user = new User;
* $this->specifyConfig()->ignore('user');
* $this->specify('change user name', function() {
* $this->user->name = 'davert';
* });
* $this->user->name == 'davert'; // name changed
* ?>
* ```
*
* @param array $properties
* @return $this
*/
public function ignore($properties = array())
{
if (!is_array($properties)) {
$properties = func_get_args();
}
$this->config->ignore = array_merge($this->config->ignore, $properties);
return $this;
}
/**
* Adds specific class to ignore list, if property is an instance of class it will not be cloned for specify block.
*
* @param array $classes
* @return $this
*/
public function ignoreClasses($classes = array())
{
$this->config->ignore_classes = array_merge($this->config->ignore_classes, $classes);
return $this;
}
/**
* Turn on/off deep cloning mode.
* Deep cloning mode can also be specified for specific properties.
*
* ```php
* <?php
* $this->user = new User;
* $this->post = new Post;
* $this->tag = new Tag;
*
* // turn on deep cloning by default
* $this->specifyConfig()->deepClone();
*
* // turn off deep cloning by default
* $this->specifyConfig()->deepClone(false);
*
* // deep clone only user and tag property
* $this->specifyConfig()->deepClone('user', 'tag');
*
* // alternatively
* $this->specifyConfig()->deepClone(['user', 'tag']);
* ?>
* ```
*
* @param bool $properties
* @return $this
*/
public function deepClone($properties = true)
{
if (is_bool($properties)) {
$this->config->is_deep = $properties;
return $this;
}
if (!is_array($properties)) {
$properties = func_get_args();
}
$this->config->deep = $properties;
return $this;
}
/**
* Disable deep cloning mode, use shallow cloning by default, which is faster.
* Deep cloning mode can also be disabled for specific properties.
*
* ```php
* <?php
* $this->user = new User;
* $this->post = new Post;
* $this->tag = new Tag;
*
* // turn off deep cloning by default
* $this->specifyConfig()->shallowClone();
*
* // turn on deep cloning by default
* $this->specifyConfig()->shallowClone(false);
*
* // shallow clone only user and tag property
* $this->specifyConfig()->shallowClone('user', 'tag');
*
* // alternatively
* $this->specifyConfig()->shallowClone(['user', 'tag']);
* ?>
* ```
*
* @param bool $properties
* @return $this
*/
public function shallowClone($properties = true)
{
if (is_bool($properties)) {
$this->config->is_deep = !$properties;
return $this;
}
if (!is_array($properties)) {
$properties = func_get_args();
}
$this->config->shallow = array_merge($this->config->shallow, $properties);
return $this;
}
/**
* Clone only specific properties
*
* ```php
* <?php
* $this->specifyConfig()->cloneOnly('user', 'post');
* ?>
* ```
*
* @param $properties
* @return $this
*/
public function cloneOnly($properties)
{
if (!is_array($properties)) {
$properties = func_get_args();
}
$this->config->only = $properties;
return $this;
}
}

View File

@@ -0,0 +1,78 @@
<?php
namespace Codeception\Specify;
/**
* Helper for manipulating by an object property.
*
* @author Roman Ishchenko <roman@ishchenko.ck.ua>
*/
class ObjectProperty
{
/**
* @var mixed
*/
private $_owner;
/**
* @var \ReflectionProperty|string
*/
private $_property;
/**
* @var mixed
*/
private $_initValue;
/**
* ObjectProperty constructor.
*
* @param $owner
* @param $property
* @param $value
*/
public function __construct($owner, $property, $value = null)
{
$this->_owner = $owner;
$this->_property = $property;
if (!($this->_property instanceof \ReflectionProperty)) {
$this->_property = new \ReflectionProperty($owner, $this->_property);
}
$this->_property->setAccessible(true);
$this->_initValue = ($value === null ? $this->getValue() : $value);
}
/**
* @return string
*/
public function getName()
{
return $this->_property->getName();
}
/**
* Restores initial value
*/
public function restoreValue()
{
$this->setValue($this->_initValue);
}
/**
* @return mixed
*/
public function getValue()
{
return $this->_property->getValue($this->_owner);
}
/**
* @param mixed $value
*/
public function setValue($value)
{
$this->_property->setValue($this->_owner, $value);
}
}

View File

@@ -0,0 +1,41 @@
<?php
class ConfigTest extends \SpecifyUnitTest
{
/**
* @var \Codeception\Specify\Config
*/
protected $config;
protected function setUp()
{
$this->config = \Codeception\Specify\Config::create();
}
public function testDefaults()
{
$this->assertTrue($this->config->propertyIgnored('backupGlobals'));
$this->assertTrue($this->config->propertyIgnored('dependencies'));
$this->assertTrue($this->config->propertyIsDeeplyCloned('user'));
$this->assertFalse($this->config->propertyIsShallowCloned('user'));
}
public function testCloneModes()
{
$this->config->is_deep = false;
$this->config->deep[] = 'user';
$this->assertTrue($this->config->propertyIsShallowCloned('profile'));
$this->assertFalse($this->config->propertyIsShallowCloned('user'));
$this->assertTrue($this->config->propertyIsDeeplyCloned('user'));
}
public function testConfigOnly()
{
$this->config->deep = ['user', 'post', 'tag'];
$this->config->only = ['user'];
// $this->assertFalse($this->config->propertyIgnored('user'));
// $this->assertTrue($this->config->propertyIgnored('post'));
}
}

View File

@@ -0,0 +1,65 @@
<?php
class ObjectPropertyTest extends \SpecifyUnitTest
{
private $private = 'private';
public function testConstruction()
{
$this->prop = 'test';
$prop = new \Codeception\Specify\ObjectProperty($this, 'prop');
$this->assertEquals('prop', $prop->getName());
$this->assertEquals('test', $prop->getValue());
$prop = new \Codeception\Specify\ObjectProperty($this, 'private');
$this->assertEquals('private', $prop->getName());
$this->assertEquals('private', $prop->getValue());
$prop = new \Codeception\Specify\ObjectProperty(
$this, new ReflectionProperty($this, 'private')
);
$this->assertEquals('private', $prop->getName());
$this->assertEquals('private', $prop->getValue());
}
public function testRestore()
{
$this->prop = 'test';
$prop = new \Codeception\Specify\ObjectProperty($this, 'prop');
$prop->setValue('another value');
$this->assertEquals('another value', $this->prop);
$prop->restoreValue();
$this->assertEquals('test', $this->prop);
$prop = new \Codeception\Specify\ObjectProperty($this, 'private');
$prop->setValue('another private value');
$this->assertEquals('another private value', $this->private);
$prop->restoreValue();
$this->assertEquals('private', $this->private);
$prop = new \Codeception\Specify\ObjectProperty($this, 'prop', 'testing');
$this->assertEquals('test', $prop->getValue());
$prop->setValue('Hello, World!');
$this->assertEquals($prop->getValue(), $this->prop);
$this->assertEquals('Hello, World!', $prop->getValue());
$prop->restoreValue();
$this->assertEquals($prop->getValue(), $this->prop);
$this->assertEquals('testing', $prop->getValue());
}
}

View File

@@ -0,0 +1,328 @@
<?php
class SpecifyTest extends \SpecifyUnitTest
{
protected $user;
protected $a;
private $private = false;
public function testSpecification()
{
$this->user = new stdClass();
$this->user->name = 'davert';
$this->specify("i can change my name", function() {
$this->user->name = 'jon';
$this->assertEquals('jon', $this->user->name);
});
$this->assertEquals('davert', $this->user->name);
$this->specify('i can fail here but test goes on', function() {
$this->markTestIncomplete();
});
$this->assertTrue(true);
}
function testBeforeCallback()
{
$this->beforeSpecify(function() {
$this->user = "davert";
});
$this->specify("user should be davert", function() {
$this->assertEquals('davert', $this->user);
});
}
function testMultiBeforeCallback()
{
$this->beforeSpecify(function() {
$this->user = "davert";
});
$this->beforeSpecify(function() {
$this->user .= "jon";
});
$this->specify("user should be davertjon", function() {
$this->assertEquals('davertjon', $this->user);
});
}
function testAfterCallback()
{
$this->afterSpecify(function() {
$this->user = "davert";
});
$this->specify("user should be davert", function() {
$this->user = "jon";
});
$this->assertEquals('davert', $this->user);
}
function testMultiAfterCallback()
{
$this->afterSpecify(function() {
$this->user = "davert";
});
$this->afterSpecify(function() {
$this->user .= "jon";
});
$this->specify("user should be davertjon", function() {
$this->user = "jon";
});
$this->assertEquals('davertjon', $this->user);
}
function testCleanSpecifyCallbacks()
{
$this->afterSpecify(function() {
$this->user = "davert";
});
$this->cleanSpecify();
$this->specify("user should be davert", function() {
$this->user = "jon";
});
$this->assertNull($this->user);
}
public function testExceptions()
{
$this->specify('user is invalid', function() {
throw new Exception;
}, ['throws' => 'Exception']);
$this->specify('user is invalid', function() {
throw new RuntimeException;
}, ['throws' => 'RuntimeException']);
$this->specify('user is invalid', function() {
throw new RuntimeException;
}, ['throws' => new RuntimeException()]);
$this->specify('i can handle fails', function() {
$this->fail("Ok, I'm failing");
}, ['throws' => 'fail']);
}
public function testExceptionsWithMessages()
{
$this->specify('user is invalid', function() {
throw new Exception("test message");
}, ['throws' => ['Exception', 'test message']]);
$this->specify('user is invalid', function() {
throw new RuntimeException("test message");
}, ['throws' => ['RuntimeException', 'test message']]);
$this->specify('user is invalid', function() {
throw new RuntimeException("test message");
}, ['throws' => [new RuntimeException(), "test message"]]);
$this->specify('i can handle fails', function() {
$this->fail("test message");
}, ['throws' => ['fail', 'test message']]);
$this->specify('ignores an empty message', function() {
$this->fail("test message");
}, ['throws' => ['fail']]);
$this->specify('mixed case exception messages', function() {
throw new RuntimeException("teSt mESSage");
}, ['throws' => ['RuntimeException', 'Test MessaGE']]);
}
/**
* @expectedException RuntimeException
*/
public function testFailWhenUnexpectedExceptionHappens()
{
$this->specify('i bubble exception up if no throws is defined', function() {
throw new RuntimeException;
});
}
public function testExamples()
{
$this->specify('specify may contain examples', function($a, $b) {
$this->assertEquals($b, $a*$a);
}, ['examples' => [
['2', '4'],
['3', '9']
]]);
}
function testOnlySpecifications()
{
$this->specify('should be valid');
}
public function testDeepCopy()
{
$this->a = new TestOne();
$this->a->prop = new TestOne();
$this->a->prop->prop = 1;
$this->specify('nested object can be changed', function() {
$this->assertEquals(1, $this->a->prop->prop);
$this->a->prop->prop = 2;
$this->assertEquals(2, $this->a->prop->prop);
});
$this->assertEquals(1, $this->a->prop->prop);
}
public function testConfiguration()
{
$this->specifyConfig()
->ignore('user');
$this->specify("user should be jon", function() {
$this->user = "jon";
});
$this->specifyConfig()
->ignore(['user']);
$this->specify("user should be davert", function() {
$this->user = "davert";
});
$this->a = new TestOne();
$this->a->prop = new TestOne();
$this->a->prop->prop = 1;
$this->specifyConfig()
->shallowClone('a');
$this->specify("user should be davert", function() {
$this->a->prop->prop = "davert";
});
$this->assertEquals("davert", $this->a->prop->prop);
}
public function testCloneOnly()
{
$this->specifyConfig()
->cloneOnly('user');
$this->user = "bob";
$this->a = "rob";
$this->specify("user should be jon", function() {
$this->user = "jon";
$this->a = 'alice';
});
$this->assertEquals('bob', $this->user);
$this->assertEquals('alice', $this->a);
}
/**
* @Issue https://github.com/Codeception/Specify/issues/6
*/
function testPropertyRestore()
{
$this->testOne = new testOne();
$this->testOne->prop = ['hello', 'world'];
$this->specify('array contains hello+world', function ($testData) {
$this->testOne->prop = ['bye', 'world'];
$this->assertContains($testData, $this->testOne->prop);
}, ['examples' => [
['bye'],
['world'],
]]);
$this->assertEquals(['hello', 'world'], $this->testOne->prop);
$this->assertFalse($this->private);
$this->assertTrue($this->getPrivateProperty());
$this->specify('property $private should be restored properly', function() {
$this->private = 'i\'m protected';
$this->setPrivateProperty('i\'m private');
$this->assertEquals('i\'m private', $this->getPrivateProperty());
});
$this->assertFalse($this->private);
$this->assertTrue($this->getPrivateProperty());
}
public function testExamplesIndexInName()
{
$name = $this->getName();
$this->specify('it appends index of an example to a test case name', function ($idx, $example) use ($name) {
$name .= ' | it appends index of an example to a test case name';
$this->assertEquals($name . ' | examples index ' . $idx, $this->getName());
$this->specify('nested specification without examples', function () use ($idx, $name) {
$name .= ' | examples index ' . $idx;
$name .= ' | nested specification without examples';
$this->assertEquals($name, $this->getName());
});
$this->specify('nested specification with examples', function () use ($idx, $name) {
$name .= ' | examples index ' . $idx;
$name .= ' | nested specification with examples';
$name .= ' | examples index 0';
$this->assertEquals($name, $this->getName());
}, ['examples' => [
[$example]
]]);
}, ['examples' => [
[0, ''],
[1, '0'],
[2, null],
[3, 'bye'],
[4, 'world'],
]]);
$this->specify('it does not append index to a test case name if there are no examples', function () use ($name) {
$name .= ' | it does not append index to a test case name if there are no examples';
$this->assertEquals($name, $this->getName());
$this->specify('nested specification without examples', function () use ($name) {
$this->assertEquals($name . ' | nested specification without examples', $this->getName());
});
$this->specify('nested specification with examples', function () use ($name) {
$this->assertEquals($name . ' | nested specification with examples | examples index 0', $this->getName());
}, ['examples' => [
[null]
]]);
});
}
public function testMockObjectsIsolation()
{
$mock = $this->getMock(get_class($this), ['testMockObjectsIsolation']);
$mock->expects($this->once())->method('testMockObjectsIsolation');
$this->specify('this should fail', function () {
$mock = $this->getMock(get_class($this), ['testMockObjectsIsolation']);
$mock->expects($this->exactly(100500))->method('testMockObjectsIsolation');
}, ['throws' => 'PHPUnit_Framework_ExpectationFailedException']);
$this->specify('this should not fail', function () {
$mock = $this->getMock(get_class($this), ['testMockObjectsIsolation']);
$mock->expects($this->never())->method('testMockObjectsIsolation');
});
$mock->testMockObjectsIsolation();
}
// public function testFail()
// {
// $this->specify('this will fail', function(){
// $this->assertTrue(false);
// });
//
// $this->specify('this will fail too', function(){
// echo "executed";
// $this->assertTrue(true);
// }, ['throws' => 'Exception']);
// }
}
class TestOne
{
public $prop;
}

View File

@@ -0,0 +1,3 @@
<?php
require_once __DIR__.'/../vendor/autoload.php';
require_once __DIR__ . '/_support/SpecifyUnitTest.php';

View File

@@ -0,0 +1,23 @@
<?php
class SpecifyUnitTest extends \PHPUnit_Framework_TestCase
{
use Codeception\Specify;
private $private = true;
/**
* @param mixed $private
*/
protected function setPrivateProperty($private)
{
$this->private = $private;
}
/**
* @return mixed
*/
protected function getPrivateProperty()
{
return $this->private;
}
}