PK ~?VYdL L LICENSEnu W+A 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.
PK ~?V6b; VERSIONnu W+A 1.0.0PK ~?Vŝ .travis.ymlnu W+A language: php
php:
- 5.5
- 5.6
- 7.0
before_script:
- stty cols 160
- composer install -n --prefer-source
script: "php vendor/bin/codecept run"
PK ~?Vou7! ! codeception.ymlnu W+A paths:
tests: tests
log: tests/_log
data: tests/_data
helpers: tests/_helpers
settings:
bootstrap: _bootstrap.php
suite_class: \PHPUnit_Framework_TestSuite
colors: true
memory_limit: 1024M
log: true
coverage:
enabled: true
include:
- src/*PK ~?Vi*
RoboFile.phpnu W+A 'AspectMock\Test',
'docs/ClassProxy.md' => 'AspectMock\Proxy\ClassProxy',
'docs/InstanceProxy.md' => 'AspectMock\Proxy\InstanceProxy',
'docs/FuncProxy.md' => 'AspectMock\Proxy\FuncProxy'
];
protected function version()
{
return file_get_contents(__DIR__.'/VERSION');
}
public function release()
{
$this->say("Releasing AspectMock");
$this->test();
$this->docs();
$this->taskGitStack()
->add('CHANGELOG.md')
->commit('updated')
->push()
->run();
$this->taskGitHubRelease($this->version())
->uri('Codeception/AspectMock')
->askDescription()
->run();
$this->bump();
}
public function docs()
{
foreach ($this->docs as $file => $class) {
class_exists($class, true);
$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;
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();
}
}
public function changed($addition)
{
$this->taskChangelog()
->version($this->version())
->change($addition)
->run();
}
public function bump($version = null)
{
if (!$version) {
$versionParts = explode('.', $this->version());
$versionParts[count($versionParts)-1]++;
$version = implode('.', $versionParts);
}
file_put_contents('VERSION', $version);
}
public function test()
{
$res = $this->taskCodecept()->run();
if (!$res) {
$this->say('Tests did not pass, release declined');
exit;
}
}
}
PK ~?V8w w
composer.jsonnu W+A {
"name": "codeception/aspect-mock",
"description": "Experimental Mocking Framework powered by Aspects",
"authors": [
{
"name": "Michael Bodnarchuk",
"email": "davert.php@mailican.com"
}
],
"autoload": {
"psr-0": {
"AspectMock": "src/"
}
},
"require": {
"php": ">=5.4.0",
"goaop/framework": "~1.0",
"symfony/finder": "~2.4|~3.0"
},
"require-dev": {
"codeception/base": "~2.1",
"codeception/verify": "~0.2",
"codeception/specify": "~0.3"
},
"license": "MIT"
}
PK ~?Vթk* * CHANGELOG.mdnu W+A # Changelog
#### 1.0.0
* **Updated to Go AOP Framework 1.0**
* Added verifying inherited method calls by @torreytsui. See #90
* Replaces `return` with `yield` for non-root namespaces. By @faridanthony See #93
* Fix bug that class does not bind in static double by @torreytsui. See #89
#### 0.5.5
* compatible with Symfony3 and PHP7
#### 0.5.4
* Improved namespace handling
* Added ability to display actually passed parameter in the error message
* Fixed counting of dynamic class methods (#24)
* Fixes for functions that have a brace as default on parametersi
* Replace return with yield when docComments returns Generator
#### 0.5.3
* Updated to goaop/framework 0.6.x and codeception 2.1
#### 0.5.1
* Fixed strict errors for func verifier
#### 0.5.0
* `test::ns` method removed
* Mocking functions implemented with `test::func` method
* Fixed mocking functions with arguments passed by reference (#34)
* Fixed passing arguments by reference in InstanceProxy
* Debug mode can be disabled in options with `debug => false`
* Updated to Go\Aop 0.5.0
#### 0.5.0-beta 05/14/2014
* Moved to Go\Aop 0.5.x-dev
#### 0.4.2 05/09/2014
* Depdendency on AspectMock ~0.4.0
#### 0.4.1
* RoboFile
* Verify invocation arguments with closures
* Verify invocation arguments with closures
* Vetter support for traits
PK ~?Vv tests/unit.suite.ymlnu W+A # Codeception Test Suite Configuration
# suite for unit (internal) tests.
# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.
class_name: CodeGuy
modules:
enabled: [CodeHelper]
PK ~?VU " tests/_data/demo/TraitedClass2.phpnu W+A
* Move forward to next element
* @link http://php.net/manual/en/iterator.next.php
* @return void Any returned value is ignored.
*/
public function next()
{
// TODO: Implement next() method.
}
/**
* (PHP 5 >= 5.0.0)
* Return the key of the current element
* @link http://php.net/manual/en/iterator.key.php
* @return mixed scalar on success, or null on failure.
*/
public function key()
{
// TODO: Implement key() method.
}
/**
* (PHP 5 >= 5.0.0)
* Checks if current position is valid
* @link http://php.net/manual/en/iterator.valid.php
* @return boolean The return value will be casted to boolean and then evaluated.
* Returns true on success or false on failure.
*/
public function valid()
{
// TODO: Implement valid() method.
}
/**
* (PHP 5 >= 5.0.0)
* Rewind the Iterator to the first element
* @link http://php.net/manual/en/iterator.rewind.php
* @return void Any returned value is ignored.
*/
public function rewind()
{
// TODO: Implement rewind() method.
}
}PK ~?VgtT tests/_data/demo/UserModel.phpnu W+A $value)
{
$this->$key = $value;
}
}
/**
* @param mixed $name
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* @return mixed
*/
public function getName()
{
return $this->name;
}
/**
* @param array $info
*/
public function setInfo($info)
{
$this->info = $info;
return $this;
}
/**
* @return array
*/
public function getInfo($info)
{
return $this->info;
}
function save()
{
throw new \PHPUnit_Framework_AssertionFailedError("I should not be called");
}
public function __call($name, $args = array())
{
if ($name == 'renameUser') return 'David Blane';
}
public static function __callStatic($name, $args)
{
if ($name == 'defaultRole') return "member";
}
public function dump()
{
return file_put_contents(\Codeception\Configuration::logDir().'user.txt',$this->name);
}
}PK ~?Vَ # tests/_data/demo/AdminUserModel.phpnu W+A name = "Admin_111";
parent::save();
}
}PK ~?V J J " tests/_data/demo/TraitedClass1.phpnu W+A save();
}
public function updateName(UserModel $user)
{
$user->setName("Current User");
$user->save();
}
public function renameUser(UserModel $user, $name)
{
$user->renameUser($name);
$user->save();
}
public static function renameStatic(UserModel $user, $name)
{
$user->renameUser($name);
$user->save();
}
public function __call($name, $args)
{
if ($name == 'rename') {
return 'David Blane';
}
}
}
PK ~?Vy y ! tests/_data/demo/WorkingTrait.phpnu W+A add('AspectMock', __DIR__ . '/../../src');
$loader->add('demo', __DIR__ );
$loader->register();
$kernel = \AspectMock\Kernel::getInstance();
$kernel->init([
'debug' => true,
'cacheDir' => __DIR__.'/cache',
]);
$user = new demo\UserModel;
$user->save();PK ~?VYf( ( tests/_data/autoload.phpnu W+A add('demo',__DIR__);
//$loader->register();
require_once __DIR__.'/demo/UserModel.php';
require_once __DIR__.'/demo/UserService.php';
require_once __DIR__.'/demo/AdminUserModel.php';
require_once __DIR__.'/demo/WorkingTrait.php';PK ~?Vw+} } tests/_bootstrap.phpnu W+A add('AspectMock', __DIR__ . '/../src');
$loader->add('demo', __DIR__ . '/_data');
$loader->register();
$kernel = \AspectMock\Kernel::getInstance();
$kernel->init([
'debug' => true,
'cacheDir' => __DIR__.'/_data/cache',
'includePaths' => [__DIR__.'/_data/demo'],
'interceptFunctions' => true
]);PK ~?V:<Թ
tests/unit/MockFailedTest.phpnu W+A setExpectedException('PHPUnit_Framework_ExpectationFailedException');
}
protected function tearDown()
{
double::clean();
}
protected function user()
{
$user = new UserModel();
double::registerObject($user);
$user = new InstanceProxy($user);
return $user;
}
protected function userProxy()
{
$userProxy = new ClassProxy('demo\UserModel');
double::registerClass('demo\UserModel');
return $userProxy;
}
public function testInstanceInvoked()
{
$this->user()->verifyInvoked('setName');
}
public function testInstanceInvokedWothoutParams()
{
$user = $this->user();
$user->setName('davert');
$user->verifyInvoked('setName',[]);
}
public function testInstanceInvokedMultipleTimes()
{
$user = $this->user();
$user->setName('davert');
$user->setName('jon');
$user->verifyInvokedMultipleTimes('setName',3);
}
public function testInstanceInvokedMultipleTimesWithoutParams()
{
$user = $this->user();
$user->setName('davert');
$user->setName('jon');
$user->verifyInvokedMultipleTimes('setName',2,['davert']);
}
public function testClassMethodFails()
{
$userProxy = $this->userProxy();
UserModel::tableName();
UserModel::tableName();
$userProxy->verifyInvokedOnce('tableName');
}
public function testClassMethodNeverInvokedFails()
{
$user = new UserModel();
$userProxy = $this->userProxy();
$user->setName('davert');
$userProxy->verifyNeverInvoked('setName');
}
public function testClassMethodInvokedMultipleTimes()
{
$user = new UserModel();
$userProxy = $this->userProxy();
$user->setName('davert');
$user->setName('bob');
$userProxy->verifyInvokedMultipleTimes('setName',2,['davert']);
}
public function testClassMethodInvoked()
{
$user = new UserModel();
$userProxy = $this->userProxy();
$user->setName(1111);
$userProxy->verifyInvoked('setName',[2222]);
}
public function testAnythingFail()
{
$anyProxy = new AnythingClassProxy('demo\UserModel');
$any = $anyProxy->construct();
$any->hello();
$anyProxy->verifyInvoked('hello');
}
}PK ~?V" tests/unit/MockTest.phpnu W+A setName('davert');
$this->specify('setName() was invoked', function() use ($user) {
$user->verifyInvoked('setName');
$user->verifyInvoked('setName',['davert']);
$user->verifyInvokedMultipleTimes('setName',1);
$user->verifyInvokedMultipleTimes('setName',1,['davert']);
$user->verifyNeverInvoked('setName',['bugoga']);
});
$this->specify('save() was not invoked', function() use ($user) {
$user->verifyNeverInvoked('save');
$user->verifyNeverInvoked('save',['params']);
});
}
public function testVerifyClassMethods()
{
double::registerClass('demo\UserModel',['save' => null]);
$user = new ClassProxy('demo\UserModel');
$service = new UserService();
$service->create(array('name' => 'davert'));
$user->verifyInvoked('save');
$user->verifyInvoked('save',[]);
$user->verifyInvokedMultipleTimes('save',1);
$user->verifyNeverInvoked('getName');
}
public function testVerifyStaticMethods()
{
double::registerClass('demo\UserModel');
$user = new ClassProxy('demo\UserModel');
UserModel::tableName();
$user->verifyInvoked('tableName');
}
public function testVerifyThatWasCalledWithParameters()
{
$user = new UserModel();
double::registerObject($user);
$user = new InstanceProxy($user);
$user->setName('davert');
$user->setName('jon');
$user->verifyInvokedOnce('setName',['davert']);
}
public function testVerifyClassMethodCalled()
{
$user = new UserModel();
$userProxy = new ClassProxy('demo\UserModel');
double::registerClass('demo\UserModel');
$user->setName('davert');
$user->setName('jon');
$userProxy->verifyInvokedMultipleTimes('setName',2);
$userProxy->verifyInvokedOnce('setName',['jon']);
$userProxy->verifyNeverInvoked('save');
$userProxy->verifyNeverInvoked('setName',['bob']);
verify($user->getName())->equals('jon');
}
/**
* Allow verifying extended methods.
*
* Given:
*
*
*
*
*
* Verification:
*
*
* super();
*
* // Will pass
* $parentProxy->verifyInvoked('super');
* $childProxy->verifyInvoked('super');
* ?>
*
*/
public function testVerifyClassInheritedMethodCalled()
{
$adminUser = new AdminUserModel();
double::registerClass(\demo\UserModel::class);
double::registerClass(\demo\AdminUserModel::class);
$userProxy = new ClassProxy(\demo\UserModel::class);
$adminUserProxy = new ClassProxy(\demo\AdminUserModel::class);
$adminUser->getName();
$userProxy->verifyInvokedOnce('getName');
$adminUserProxy->verifyInvokedOnce('getName');
}
}PK ~?VhwpA= = # tests/unit/FunctionInjectorTest.phpnu W+A funcInjector = new FunctionInjector('demo', 'strlen');
test::clean();
}
public function testTemplate()
{
$php = $this->funcInjector->getPHP();
verify($php)->contains("function strlen()");
verify($php)->contains("return call_user_func_array('strlen', func_get_args());");
}
public function testSave()
{
$this->funcInjector->save();
exec('php -l '.$this->getFileName(), $output, $code);
verify($code)->equals(0);
codecept_debug($this->funcInjector->getPHP());
}
public function testLoadFunc()
{
$this->funcInjector->save();
codecept_debug($this->funcInjector->getFileName());
$this->funcInjector->inject();
verify(strlen('hello'))->equals(5);
}
public function testReimplementFunc()
{
test::func('demo', 'strlen', 10);
verify(strlen('hello'))->equals(10);
}
public function testVerifier()
{
$func = test::func('demo', 'strlen', 10);
expect(strlen('hello'))->equals(10);
$func->verifyInvoked();
$func->verifyInvoked(['hello']);
$func->verifyInvokedOnce();
$func->verifyInvokedOnce(['hello']);
$func->verifyInvokedMultipleTimes(1, ['hello']);
$func->verifyNeverInvoked(['hee']);
}
public function testVerifierFullyQualifiedNamespace()
{
$func = test::func('\demo', 'strlen', 10);
expect(strlen('hello'))->equals(10);
$func->verifyInvoked();
$func->verifyInvoked(['hello']);
$func->verifyInvokedOnce();
$func->verifyInvokedOnce(['hello']);
$func->verifyInvokedMultipleTimes(1, ['hello']);
$func->verifyNeverInvoked(['hee']);
}
public function testFailedVerification()
{
$this->setExpectedException('PHPUnit_Framework_ExpectationFailedException');
$func = test::func('demo', 'strlen', function() { return 10; });
expect(strlen('hello'))->equals(10);
$func->verifyNeverInvoked('strlen');
}
}
PK ~?VRw5 $ tests/unit/AccessDemoClassesTest.phpnu W+A 'davert']);
$this->assertEquals('davert', $user->getName());
}
/**
* @expectedException PHPUnit_Framework_AssertionFailedError
*/
public function testUserService()
{
$service = new UserService();
$service->create(['name' => 'davert']);
}
}PK ~?Vmu u tests/unit/_bootstrap.phpnu W+A isDefined())->true();
verify($class->hasMethod('setName'))->true();
verify($class->hasMethod('setNothing'))->false();
verify($class->hasProperty('name'))->true();
verify($class->hasProperty('otherName'))->false();
verify($class->traits())->isEmpty();
verify($class->interfaces())->isEmpty();
verify($class->parent())->null();
}
public function testMegaClassValidations()
{
$class = test::double('demo\MegaClass');
/** @var $class ClassProxy **/
verify($class->isDefined())->true();
verify($class->hasMethod('setName'))->false();
verify($class->traits())->contains('Codeception\Specify');
verify($class->interfaces())->contains('Iterator');
verify($class->parent())->equals('stdClass');
}
public function testUndefinedClass()
{
$this->setExpectedException('Exception');
test::double('MyUndefinedClass');
}
public function testInstanceCreation()
{
$this->class = test::double('demo\UserModel');
$this->specify('instance can be created from a class proxy', function() {
$user = $this->class->construct(['name' => 'davert']);
verify($user->getName())->equals('davert');
$this->assertInstanceOf('demo\UserModel', $user);
});
$this->specify('instance can be created without constructor', function() {
$user = $this->class->make();
$this->assertInstanceOf('demo\UserModel', $user);
});
}
public function testClassWithTraits() {
// if a trait is used by more than one doubled class, when BeforeMockTransformer
// runs on the second class it will see the trait's methods as being a part of
// the class itself, and try to inject its code into the class, rather than the
// trait. in failure mode, this test will result in:
// Parse error: syntax error, unexpected 'if' (T_IF), expecting function (T_FUNCTION)
// in [...]/TraitedModel2.php
$unused = test::double('demo\TraitedClass1'); // this model uses `TraitedModelTrait`
$class = test::double('demo\TraitedClass2'); // so does this one
/** @var $class ClassProxy **/
verify($class->isDefined())->true();
verify($class->hasMethod('method1InTrait'))->true();
verify($class->hasMethod('methodInClass'))->true();
}
}
PK ~?VYGC tests/unit/StubTest.phpnu W+A null]);
$user = new UserModel();
$user->save();
}
public function testSaveAgain()
{
double::registerClass('\demo\UserModel', ['save' => "saved!"]);
$user = new UserModel();
$saved = $user->save();
$this->assertEquals('saved!', $saved);
}
public function testCallback()
{
double::registerClass('\demo\UserModel', ['save' => function () { return $this->name; }]);
$user = new UserModel(['name' => 'davert']);
$name = $user->save();
$this->assertEquals('davert', $name);
}
public function testBindSelfCallback()
{
double::registerClass('\demo\UserModel', ['getTopSecret' => function () {
return UserModel::$topSecret;
}]);
$topSecret = UserModel::getTopSecret();
$this->assertEquals('awesome', $topSecret);
}
public function testObjectInstance()
{
$user = new UserModel(['name' => 'davert']);
double::registerObject($user,['save' => null]);
$user->save();
}
public function testStaticAccess()
{
$this->assertEquals('users', UserModel::tableName());
double::registerClass('\demo\UserModel', ['tableName' => 'my_users']);
$this->assertEquals('my_users', UserModel::tableName());
}
public function testInheritance()
{
double::registerClass('\demo\UserModel', ['save' => false]);
$admin = new AdminUserModel();
$admin->save();
$this->assertEquals('Admin_111', $admin->getName());
}
public function testMagic()
{
double::registerClass('\demo\UserService', ['rename' => 'David Copperfield']);
$admin = new UserService();
$this->assertEquals('David Copperfield', $admin->rename());
}
public function testMagicOfInheritedClass()
{
double::registerClass('\demo\AdminUserModel', ['renameUser' => 'David Copperfield']);
$admin = new AdminUserModel();
$this->assertEquals('David Copperfield', $admin->renameUser());
}
public function testMagicStaticInherited()
{
double::registerClass('\demo\AdminUserModel', ['defaultRole' => 'admin']);
$this->assertEquals('admin', AdminUserModel::defaultRole());
}
public function testMagicStatic()
{
double::registerClass('\demo\UserModel', ['defaultRole' => 'admin']);
$this->assertEquals('admin', UserModel::defaultRole());
}
// public function testStubFunctionCall()
// {
// double::registerFunc('file_put_contents', 'Done');
// $user = new UserModel();
// $user->setName('David Bovie');
// $this->assertEquals('Done', $user->dump());
// }
}PK ~?VT T tests/unit/testDoubleTest.phpnu W+A null]);
(new demo\UserModel())->save();
$user->verifyInvoked('save');
\demo\UserModel::tableName();
\demo\UserModel::tableName();
$user->verifyInvokedMultipleTimes('tableName',2);
$this->specify('disabling all methods', function() use ($user) {
test::methods($user, []);
verify(\demo\UserModel::tableName())->null();
});
}
public function testDoubleFullyQualifiedClass()
{
$user = test::double('\demo\UserModel', ['save' => null]);
(new demo\UserModel())->save();
$user->verifyInvoked('save');
\demo\UserModel::tableName();
\demo\UserModel::tableName();
$user->verifyInvokedMultipleTimes('tableName',2);
$this->specify('disabling all methods', function() use ($user) {
test::methods($user, []);
verify(\demo\UserModel::tableName())->null();
});
}
public function testDoubleObject()
{
$user = new demo\UserModel();
$user = test::double($user, ['save' => null]);
$user->save();
$user->verifyInvoked('save');
$this->specify('only selected methods can be added to instance', function() use ($user) {
$user = test::methods($user, ['setName']);
$user->setName('davert');
verify($user->getName())->notEquals('davert');
verify($user->getName())->null();
verify($user->getObject()->getName())->null();
});
}
public function testSpecUndefinedClass()
{
$class = test::spec('MyVirtualClass');
/** @var $class ClassProxy **/
$this->assertFalse($class->isDefined());
$this->assertFalse($class->hasMethod('__toString'));
$this->assertFalse($class->hasMethod('edit'));
verify($class->interfaces())->isEmpty();
$this->any = $class->make();
$this->any = $class->construct();
$this->specify('should return original class name', function() {
$this->assertContains('Undefined', (string)$this->any);
$this->assertContains('MyVirtualClass', (string)$this->any->__toString());
});
$this->specify('any method can be invoked', function() {
$this->assertInstanceOf('AspectMock\Proxy\Anything', $this->any->doSmth()->withTHis()->andThatsAll()->null());
});
$this->specify('any property can be accessed', function() {
$this->any->that = 'xxx';
$this->assertInstanceOf('AspectMock\Proxy\Anything', $this->any->this->that->another);
});
$this->specify('can be used as array', function() {
$this->any['has keys'];
unset($this->any['this']);
$this->any['this'] = 'that';
$this->assertFalse(isset($this->any['that']));
$this->assertInstanceOf('AspectMock\Proxy\Anything', $this->any['keys']);
});
$this->specify('can be iterated', function() {
foreach ($this->any as $anything) {}
});
$this->specify('proxifies magic method calls', function() {
$any = test::double($this->any);
$any->callMeMaybe();
$any->name = 'hello world';
$this->assertInstanceOf('AspectMock\Proxy\Anything', $any->name);
verify($any->class->className)->equals('AspectMock\Proxy\Anything');
});
}
public function testCleanupSpecificClasses()
{
$service = test::double('demo\UserService',['updateName' => 'hello'])->make();
test::double('demo\UserModel',['tableName' => 'my_table']);
verify(demo\UserModel::tableName())->equals('my_table');
test::clean('demo\UserModel');
verify(demo\UserModel::tableName())->equals('users');
verify($service->updateName(new \demo\UserModel()))->equals('hello');
}
public function testCleanupSpecificObj()
{
$model = test::double('demo\UserModel');
$user1 = test::double($model->make(), ['getName' => 'bad boy']);
$user2 = test::double($model->make(), ['getName' => 'good boy']);
verify($user1->getName())->equals('bad boy');
verify($user2->getName())->equals('good boy');
test::clean($user1);
verify($user1->getName())->null();
verify($user2->getName())->equals('good boy');
}
}
PK ~?V_Bp tests/unit/VerifierTest.phpnu W+A 'foo',
'email' => 'foo@bar.cl',
);
$user = new UserModel();
double::registerObject($user);
$user = new InstanceProxy($user);
$user->setInfo($info);
$user->setInfo([]);
$matcher = function($params) use ($info) {
$args = $params[0][0]; // first call, first arg
$empty = $params[1][0]; // second call, first arg
verify($info)->equals($args);
verify($empty)->isEmpty();
};
$this->specify('closure was called', function() use ($user, $info, $matcher) {
$user->verifyInvokedMultipleTimes('setInfo', 2, $matcher);
$user->verifyInvoked('setInfo', $matcher);
});
}
public function testVerifyMagicMethods()
{
$this->specify('works for class proxy', function() {
// Set up user object.
double::registerClass("demo\UserModel",
['renameUser'=>"Bob Jones", 'save'=>null]);
$userProxy = new ClassProxy("demo\UserModel");
$user = new UserModel(['name'=>"John Smith"]);
// Rename the user via magic method.
UserService::renameStatic($user, "Bob Jones");
// Assert rename was counted.
$userProxy->verifyInvoked('renameUser');
});
$this->specify('works for instance proxy', function() {
// Set up user object.
$user = new UserModel(['name'=>"John Smith"]);
double::registerObject($user);
$user = new InstanceProxy($user);
// Rename the user via magic method.
$user->renameUser("Bob Jones");
// Assert rename was counted.
$user->verifyInvoked('renameUser');
});
}
}
PK ~?V4/)
tests/_log/.gitignorenu W+A *
!.gitignorePK ~?VLw tests/_helpers/CodeHelper.phpnu W+A assertEquals('users', UserModel::tableName());
$userModel = test::double('UserModel', ['tableName' => 'my_users']);
$this->assertEquals('my_users', UserModel::tableName());
$userModel->verifyInvoked('tableName');
}
?>
```
#### Allows replacement of class methods.
Testing code developed with the **ActiveRecord** pattern. Does the use of the ActiveRecord pattern sound like bad practice? No. But the code below is untestable in classic unit testing.
``` php
setName($name);
$user->save();
}
}
?>
```
Without AspectMock you need to introduce `User` as an explicit dependency into class `UserService` to get it tested.
But lets leave the code as it is. It works. Nevertheless, we should still test it to avoid regressions.
We don't want the `$user->save` method to actually get executed, as it will hit the database.
Instead we will replace it with a dummy and verify that it gets called by `createUserByName`:
``` php
null]));
$service = new UserService;
$service->createUserByName('davert');
$this->assertEquals('davert', $user->getName());
$user->verifyInvoked('save');
}
?>
```
#### Intercept even parent class methods and magic methods
``` php
null]));
test::double('User', ['findByNameAndEmail' => new User(['name' => 'jon'])]));
$user = User::findByNameAndEmail('jon','jon@coltrane.com'); // magic method
$this->assertEquals('jon', $user->getName());
$user->save(['name' => 'miles']); // ActiveRecord->save did not hit database
$AR->verifyInvoked('save');
$this->assertEquals('miles', $user->getName());
}
?>
```
#### Override even standard PHP functions
``` php
assertEquals('now', time());
```
#### Beautifully simple
Only 4 methods are necessary for method call verification and one method to define test doubles:
``` php
'davert']);
$this->assertEquals('davert', $user->getName());
$user->verifyInvoked('getName');
$user->verifyInvokedOnce('getName');
$user->verifyNeverInvoked('setName');
$user->verifyInvokedMultipleTimes('setName',1);
}
?>
```
To check that method `setName` was called with `davert` as argument.
``` php
verifyMethodInvoked('setName', ['davert']);
?>
```
## Wow! But how does it work?
No PECL extensions is required. The [Go! AOP](http://go.aopphp.com/) library does the heavy lifting by patching autoloaded PHP classes on the fly. By introducing pointcuts to every method call, Go! allows intercepting practically any call to a method. AspectMock is a very tiny framework consisting of only 8 files using the power of the [Go! AOP Framework](http://go.aopphp.com/). Check out Aspect Oriented Development and the Go! library itself.
## Requirements
PHP >= 5.4 + [Go! AOP Requirements](https://github.com/goaop/framework#requirements)
## Installation
### 1. Add aspect-mock to your composer.json.
```
{
"require-dev": {
"codeception/aspect-mock": "*"
}
}
```
### 2. Install AspectMock with Go! AOP as a dependency.
```
php composer.phar update
```
## Configuration
Include `AspectMock\Kernel` class into your tests bootstrap file.
### With Composer's Autoloader
``` php
init([
'debug' => true,
'includePaths' => [__DIR__.'/../src']
]);
?>
```
If your project uses Composer's autoloader, that's all you need to get started.
### With Custom Autoloader
If you use a custom autoloader (like in Yii/Yii2 frameworks), you should explicitly point AspectMock to modify it:
``` php
init([
'debug' => true,
'includePaths' => [__DIR__.'/../src']
]);
$kernel->loadFile('YourAutoloader.php'); // path to your autoloader
?>
```
Load all autoloaders of your project this way, if you do not rely on Composer entirely.
### Without Autoloader
If it still doesn't work for you...
Explicitly load all required files before testing:
``` php
init([
'debug' => true,
'includePaths' => [__DIR__.'/../src']
]);
require 'YourAutoloader.php';
$kernel->loadPhpFiles('/../common');
?>
```
### Customization
There are a few options you can customize setting up AspectMock. All them are defined in Go! Framework.
They might help If you still didn't get AspectMock running on your project.
* `appDir` defines the root of web application which is being tested. All classes outside the root will be replaced with the proxies generated by AspectMock. By default it is a directory in which `vendor` dir of composer if located. **If you don't use Composer** or you have custom path to composer's vendor's folder, you should specify appDir
* `cacheDir` a dir where updated source PHP files can be stored. If this directory is not set, proxie classes will be built on each run. Otherwise all PHP files used in tests will be updated with aspect injections and stored into `cacheDir` path.
* `includePaths` directories with files that should be enhanced by Go Aop. Should point to your applications source files as well as framework files and any libraries you use..
* `excludePaths` a paths in which PHP files should not be affected by aspects. **You should exclude your tests files from interception**.
Example:
``` php
init([
'appDir' => __DIR__ . '/../../',
'cacheDir' => '/tmp/myapp',
'includePaths' => [__DIR__.'/../src']
'excludePaths' => [__DIR__] // tests dir should be excluded
]);
?>
```
[More configs for different frameworks](https://github.com/Codeception/AspectMock/wiki/Example-configs).
**It's pretty important to configure AspectMock properly. Otherwise it may not work as expected or you get side effects. Please make sure you included all files that you need to mock, but your test files as well as testing frameworks are excluded.**
## Usage in PHPUnit
Use newly created `bootstrap` in your `phpunit.xml` configuration. Also disable `backupGlobals`:
``` xml
```
Clear the test doubles registry between tests.
``` php
null]);
\demo\UserModel::tableName();
\demo\UserModel::tableName();
$user->verifyInvokedMultipleTimes('tableName',2);
}
?>
```
## Usage in Codeception.
Include `AspectMock\Kernel` into `tests/_bootstrap.php`.
We recommend including a call to `test::clean()` from your `CodeHelper` class:
``` php
```
## Improvements?
There is guaranteed to be room for improvements. This framework was not designed to do everything you might ever need (see notes below). But if you feel like you require a feature, please submit a Pull Request. It's pretty easy since there's not much code, and the Go! library is very well documented.
## Credits
Follow [**@codeception**](http://twitter.com/codeception) for updates.
Daveloped by **Michael Bodnarchuk**.
License: **MIT**.
Powered by [Go! Aspect-Oriented Framework](http://go.aopphp.com/)
PK ~?V@=% % src/AspectMock/Test.phpnu W+A
* ```
*/
class Test {
/**
* `test::double` registers class or object to track its calls.
* In second argument you may pass values that mocked mathods should return.
*
* Returns either of [**ClassProxy**](https://github.com/Codeception/AspectMock/blob/master/docs/ClassProxy.md) (when a string was passed)
* or [**InstanceProxy**](https://github.com/Codeception/AspectMock/blob/master/docs/InstanceProxy.md) (when an object was passed).
* Proxies are used to verify method invocations, and some other useful things (check out the links above for more).
*
* Examples:
*
* ``` php
* 'davert']);
* $user->getName() // => davert
* $user->verifyInvoked('getName'); // => success
* $user->getObject() // => returns instance of User, i.e. real, not proxified object
*
* # with closure
* $user = test::double(new User, ['getName' => function() { return $this->login; }]);
* $user->login = 'davert';
* $user->getName(); // => davert
*
* # on a class
* $ar = test::double('ActiveRecord', ['save' => null]);
* $user = new User;
* $user->name = 'davert';
* $user->save(); // passes to ActiveRecord->save() and does not insert any SQL.
* $ar->verifyInvoked('save'); // true
*
* # on static method call
* User::tableName(); // 'users'
* $user = test::double('User', ['tableName' => 'fake_users']);
* User::tableName(); // 'fake_users'
* $user->verifyInvoked('tableName'); // success
*
* # append declaration
* $user = new User;
* test::double($user, ['getName' => 'davert']);
* test::double($user, ['getEmail' => 'davert@mail.ua']);
* $user->getName(); // => 'davert'
* $user->getEmail(); => 'davert@mail.ua'
*
* # create an instance of mocked class
* test::double('User')->construct(['name' => 'davert']); // via constructir
* test::double('User')->make(); // without calling constructor
*
* # stub for magic method
* test::double('User', ['findByUsernameAndPasswordAndEmail' => false]);
* User::findByUsernameAndPasswordAndEmail(); // null
*
* # stub for method of parent class
* # if User extends ActiveRecord
* test::double('ActiveRecord', ['save' => false]);
* $user = new User(['name' => 'davert']);
* $user->save(); // false
*
* ?>
* ```
*
* @api
* @param string|object $classOrObject
* @param array $params [ 'methodName' => 'returnValue' ]
* @throws \Exception
* @return Verifier Usually Proxy\ClassProxy|Proxy\InstanceProxy
*/
public static function double($classOrObject, array $params = array())
{
$classOrObject = Registry::getRealClassOrObject($classOrObject);
if (is_string($classOrObject)) {
if (!class_exists($classOrObject)) {
throw new \Exception("Class $classOrObject not loaded.\nIf you want to test undefined class use 'test::spec' method");
}
Core\Registry::registerClass($classOrObject, $params);
return new Proxy\ClassProxy($classOrObject);
}
if (is_object($classOrObject)) {
Core\Registry::registerObject($classOrObject, $params);
return new Proxy\InstanceProxy($classOrObject);
}
return null;
}
/**
* If you follow TDD/BDD practices a test should be written before the class is defined.
* If you would call undefined class in a test, a fatal error will be triggered.
* Instead you can use `test::spec` method that will create a proxy for an undefined class.
*
* ``` php
* defined(); // false
* ?>
* ```
*
* You can create instances of undefined classes and play with them:
*
* ``` php
* construct();
* $user->setName('davert');
* $user->setNumPosts(count($user->getPosts()));
* $this->assertEquals('davert', $user->getName()); // fail
* ?>
* ```
*
* The test will be executed normally and will fail at the first assertion.
*
* `test::spec()->construct` creates an instance of `AspectMock\Proxy\Anything`
* which tries not to cause errors whatever you try to do with it.
*
* ``` php
* construct();
* $user->can()->be->called()->anything();
* $user->can['be used as array'];
* foreach ($user->names as $name) {
* $name->canBeIterated();
* }
* ?>
* ```
*
* None of those calls will trigger an error in your test.
* Thus, you can write a valid test before the class is declared.
*
* If class is already defined, `test::spec` will act as `test::double`.
*
* @api
* @param string|object $classOrObject
* @param array $params
* @return Verifier Usually Proxy\ClassProxy|Proxy\InstanceProxy
*/
public static function spec($classOrObject, array $params = array())
{
if (is_object($classOrObject)) return self::double($classOrObject, $params);
if (class_exists($classOrObject)) return self::double($classOrObject, $params);
return new AnythingClassProxy($classOrObject);
}
/**
* Replaces all methods in a class with dummies, except those specified in the `$only` param.
*
* ``` php
* 'jon']);
* test::methods($user, ['getName']);
* $user->setName('davert'); // not invoked
* $user->getName(); // jon
* ?>
* ```
*
* You can create a dummy without a constructor with all methods disabled:
*
* ``` php
* make();
* test::methods($user, []);
* ?>
* ```
*
* @api
* @param string|object $classOrObject
* @param string[] $only
* @return Verifier Usually Proxy\ClassProxy|Proxy\InstanceProxy
* @throws \Exception
*/
public static function methods($classOrObject, array $only = array())
{
$classOrObject = Registry::getRealClassOrObject($classOrObject);
if (is_object($classOrObject)) {
$reflected = new \ReflectionClass(get_class($classOrObject));
} else {
if (!class_exists($classOrObject)) throw new \Exception("Class $classOrObject not defined.");
$reflected = new \ReflectionClass($classOrObject);
}
$methods = $reflected->getMethods(\ReflectionMethod::IS_PUBLIC);
$params = array();
foreach ($methods as $m) {
if ($m->isConstructor()) continue;
if ($m->isDestructor()) continue;
if (in_array($m->name, $only)) continue;
$params[$m->name] = null;
}
return self::double($classOrObject, $params);
}
/**
* Replaces function in provided namespace with user-defined function or value that function returns.
* Function is restored to original on cleanup.
*
* ```php
* verifyInvoked();
* $func->verifyInvokedOnce(['Y']);
* ```
*
* @param string $namespace
* @param string $functionName
* @param mixed $body whatever a function might return or Callable substitute
* @return Proxy\FuncProxy
*/
public static function func($namespace, $functionName, $body)
{
Core\Registry::registerFunc($namespace, $functionName, $body);
return new Proxy\FuncProxy($namespace, $functionName);
}
/**
* Clears test doubles registry.
* Should be called between tests.
*
* ``` php
*
* ```
*
* Also you can clean registry only for the specific class or object.
*
* ``` php
*
* ```
*
* @api
* @param string|object $classOrObject
* @return void
*/
public static function clean($classOrInstance = null)
{
Core\Registry::clean($classOrInstance);
}
/**
* Clears mock verifications but not stub definitions.
*
* @api
* @return void
*/
public static function cleanInvocations()
{
Core\Registry::cleanInvocations();
}
}
PK ~?VAX src/AspectMock/Core/Mocker.phpnu W+A getMethod();
// $obj = $invocation->getThis();
$result = __AM_CONTINUE__;
if (in_array($method, $this->methodMap)) {
$invocation = new \AspectMock\Intercept\MethodInvocation();
$invocation->setThis($class);
$invocation->setMethod($method);
$invocation->setArguments($params);
$invocation->isStatic($static);
$invocation->setDeclaredClass($declaredClass);
$result = $this->invokeFakedMethods($invocation);
}
// Record actual method called, not faked method.
if (in_array($method, $this->dynamicMethods)) {
$method = array_shift($params);
$params = array_shift($params);
}
if (!$static) {
if (isset($this->objectMap[spl_object_hash($class)])) Registry::registerInstanceCall($class, $method, $params);
$class = get_class($class);
}
if (isset($this->classMap[$class])) Registry::registerClassCall($class, $method, $params);
if ($class != $declaredClass && isset($this->classMap[$declaredClass])) Registry::registerClassCall($declaredClass, $method, $params);
return $result;
}
public function fakeFunctionAndRegisterCalls($namespace, $function, $args)
{
$result = __AM_CONTINUE__;
$fullFuncName = "$namespace\\$function";
Registry::registerFunctionCall($fullFuncName, $args);
if (isset($this->funcMap[$fullFuncName])) {
$func = $this->funcMap[$fullFuncName];
if (is_callable($func)) {
$result = call_user_func_array($func, $args);
} else {
$result = $func;
}
}
return $result;
}
protected function invokeFakedMethods(MethodInvocation $invocation)
{
$method = $invocation->getMethod();
if (!in_array($method, $this->methodMap)) return __AM_CONTINUE__;
$obj = $invocation->getThis();
if (is_object($obj)) {
// instance method
$params = $this->getObjectMethodStubParams($obj, $method);
if ($params !== false) return $this->stub($invocation, $params);
// class method
$params = $this->getClassMethodStubParams(get_class($obj), $method);
if ($params !== false) return $this->stub($invocation, $params);
// inheritance
$params = $this->getClassMethodStubParams($invocation->getDeclaredClass(), $method);
if ($params !== false) return $this->stub($invocation, $params);
// magic methods
if ($method == '__call') {
$args = $invocation->getArguments();
$method = array_shift($args);
$params = $this->getObjectMethodStubParams($obj, $method);
if ($params !== false) return $this->stubMagicMethod($invocation, $params);
// magic class method
$params = $this->getClassMethodStubParams(get_class($obj), $method);
if ($params !== false) return $this->stubMagicMethod($invocation, $params);
// inheritance
$calledClass = $invocation->getDeclaredClass();
$params = $this->getClassMethodStubParams($calledClass, $method);
if ($params !== false) return $this->stubMagicMethod($invocation, $params);
}
} else {
// static method
$params = $this->getClassMethodStubParams($obj, $method);
if ($params !== false) return $this->stub($invocation, $params);
// magic static method (facade)
if ($method == '__callStatic') {
$args = $invocation->getArguments();
$method = array_shift($args);
$params = $this->getClassMethodStubParams($obj, $method);
if ($params !== false) return $this->stubMagicMethod($invocation, $params);
// inheritance
$calledClass = $invocation->getDeclaredClass();
$params = $this->getClassMethodStubParams($calledClass, $method);
if ($params !== false) return $this->stubMagicMethod($invocation, $params);
}
}
return __AM_CONTINUE__;
}
protected function getObjectMethodStubParams($obj, $method_name)
{
$oid = spl_object_hash($obj);
if (!isset($this->objectMap[$oid])) return false;
$params = $this->objectMap[$oid];
if (!array_key_exists($method_name,$params)) return false;
return $params;
}
protected function getClassMethodStubParams($class_name, $method_name)
{
if (!isset($this->classMap[$class_name])) return false;
$params = $this->classMap[$class_name];
if (!array_key_exists($method_name,$params)) return false;
return $params;
}
protected function stub(MethodInvocation $invocation, $params)
{
$name = $invocation->getMethod();
$replacedMethod = $params[$name];
$replacedMethod = $this->turnToClosure($replacedMethod);
if ($invocation->isStatic()) {
$replacedMethod = \Closure::bind($replacedMethod, null, $invocation->getThis());
} else {
$replacedMethod = $replacedMethod->bindTo($invocation->getThis(), get_class($invocation->getThis()));
}
return call_user_func_array($replacedMethod, $invocation->getArguments());
}
protected function stubMagicMethod(MethodInvocation $invocation, $params)
{
$args = $invocation->getArguments();
$name = array_shift($args);
$replacedMethod = $params[$name];
$replacedMethod = $this->turnToClosure($replacedMethod);
if ($invocation->isStatic()) {
\Closure::bind($replacedMethod, null, $invocation->getThis());
} else {
$replacedMethod = $replacedMethod->bindTo($invocation->getThis(), get_class($invocation->getThis()));
}
return call_user_func_array($replacedMethod, $args);
}
protected function turnToClosure($returnValue)
{
if ($returnValue instanceof \Closure) return $returnValue;
return function() use ($returnValue) {
return $returnValue;
};
}
public function registerClass($class, $params = array())
{
$class = ltrim($class,'\\');
if (isset($this->classMap[$class])) {
$params = array_merge($this->classMap[$class], $params);
}
$this->methodMap = array_merge($this->methodMap, array_keys($params));
$this->classMap[$class] = $params;
}
public function registerObject($object, $params = array())
{
$hash = spl_object_hash($object);
if (isset($this->objectMap[$hash])) {
$params = array_merge($this->objectMap[$hash], $params);
}
$this->objectMap[$hash] = $params;
$this->methodMap = array_merge($this->methodMap, array_keys($params));
}
public function registerFunc($namespace, $func, $body)
{
$namespace = ltrim($namespace,'\\');
if (!function_exists("$namespace\\$func")) {
$injector = new FunctionInjector($namespace, $func);
$injector->save();
$injector->inject();
}
$this->funcMap["$namespace\\$func"] = $body;
}
public function clean($objectOrClass = null)
{
if (!$objectOrClass) {
$this->classMap = [];
$this->objectMap = [];
$this->methodMap = ['__call','__callStatic'];
$this->funcMap = [];
} elseif (is_object($objectOrClass)) {
unset($this->objectMap[spl_object_hash($objectOrClass)]);
} else {
unset($this->classMap[$objectOrClass]);
}
}
}
PK ~?V@1
src/AspectMock/Core/Registry.phpnu W+A registerClass($name, $params);
}
static function registerObject($object, $params = array())
{
self::$mocker->registerObject($object, $params);
}
static function registerFunc($namespace, $function, $resultOrClosure)
{
self::$mocker->registerFunc($namespace, $function, $resultOrClosure);
}
static function getClassCallsFor($class)
{
$class = ltrim($class,'\\');
return isset(self::$classCalls[$class])
? self::$classCalls[$class]
: [];
}
static function getInstanceCallsFor($instance)
{
$oid = spl_object_hash($instance);
return isset(self::$instanceCalls[$oid])
? self::$instanceCalls[$oid]
: [];
}
static function getFuncCallsFor($func)
{
$func = ltrim($func,'\\');
return isset(self::$funcCalls[$func]) ? self::$funcCalls[$func] : [];
}
static function clean($classOrInstance = null)
{
$classOrInstance = self::getRealClassOrObject($classOrInstance);
self::$mocker->clean($classOrInstance);
if (is_object($classOrInstance)) {
$oid = spl_object_hash($classOrInstance);
unset(self::$instanceCalls[$oid]);
} elseif (is_string($classOrInstance)) {
unset(self::$classCalls[$classOrInstance]);
} else {
self::cleanInvocations();
}
}
static function cleanInvocations()
{
self::$instanceCalls = [];
self::$classCalls = [];
self::$funcCalls = [];
}
static function registerInstanceCall($instance, $method, $args = array())
{
$oid = spl_object_hash($instance);
if (!isset(self::$instanceCalls[$oid])) self::$instanceCalls[$oid] = [];
isset(self::$instanceCalls[$oid][$method])
? self::$instanceCalls[$oid][$method][] = $args
: self::$instanceCalls[$oid][$method] = array($args);
}
static function registerClassCall($class, $method, $args = array())
{
if (!isset(self::$classCalls[$class])) self::$classCalls[$class] = [];
isset(self::$classCalls[$class][$method])
? self::$classCalls[$class][$method][] = $args
: self::$classCalls[$class][$method] = array($args);
}
static function registerFunctionCall($functionName, $args)
{
if (!isset(self::$funcCalls[$functionName])) self::$funcCalls[$functionName] = [];
isset(self::$funcCalls[$functionName])
? self::$funcCalls[$functionName][] = $args
: self::$funcCalls[$functionName] = array($args);
}
public static function getRealClassOrObject($classOrObject)
{
if ($classOrObject instanceof ClassProxy) return $classOrObject->className;
if ($classOrObject instanceof InstanceProxy) return $classOrObject->getObject();
return $classOrObject;
}
/**
* @param mixed $mocker
*/
public static function setMocker(Mocker $mocker)
{
self::$mocker = $mocker;
}
}
PK ~?VOme? * src/AspectMock/Util/ArgumentsFormatter.phpnu W+A namespace = $namespace;
$this->function = $function;
$this->place('ns', $this->namespace);
$this->place('func', $this->function);
}
public function save()
{
$this->fileName = tempnam(sys_get_temp_dir(), $this->function);
file_put_contents($this->fileName, $this->template);
}
public function inject()
{
require_once $this->fileName;
}
public function getFileName()
{
return $this->fileName;
}
public function getPHP()
{
return $this->template;
}
protected function place($var, $value)
{
$this->template = str_replace("{{{$var}}}", $value, $this->template);
}
} PK ~?V]) ( src/AspectMock/Intercept/before_mock.phpnu W+A fakeMethodsAndRegisterCalls($class, $declaredClass, $method, $params, $static);
}
function __amock_before_func($namespace, $func, $params) {
$res = \AspectMock\Core\Registry::$mocker->fakeFunctionAndRegisterCalls($namespace, $func, $params);
return $res;
}
const __AM_CONTINUE__ = '__am_continue__';
PK ~?VZpz z - src/AspectMock/Intercept/MethodInvocation.phpnu W+A declaredClass = $declaredClass;
}
/**
* @return mixed
*/
public function getDeclaredClass()
{
return $this->declaredClass;
}
/**
* @param mixed $isStatic
*/
public function isStatic($isStatic = null)
{
if ($isStatic === null) return $this->isStatic;
$this->isStatic = $isStatic;
}
protected $class;
/**
* @param mixed $class
*/
public function setThis($class)
{
$this->class = $class;
}
/**
* @return mixed
*/
public function getThis()
{
return $this->class;
}
/**
* @param mixed $closure
*/
public function setClosure($closure)
{
$this->closure = $closure;
}
/**
* @return mixed
*/
public function getClosure()
{
return $this->closure;
}
/**
* @param mixed $method
*/
public function setMethod($method)
{
$this->method = $method;
}
/**
* @return mixed
*/
public function getMethod()
{
return $this->method;
}
/**
* @param mixed $params
*/
public function setArguments($params)
{
$this->arguments = $params;
}
/**
* @return mixed
*/
public function getArguments()
{
return $this->arguments;
}
}PK ~?V1S== = 2 src/AspectMock/Intercept/BeforeMockTransformer.phpnu W+A uri;
try {
CleanableMemory::enterProcessing();
$parsedSource = $this->broker->processString($metadata->source, $fileName, true);
} catch (FileProcessingException $e) {
CleanableMemory::leaveProcessing();
return false;
}
/** @var $namespaces ParsedFileNamespace[] */
$namespaces = $parsedSource->getNamespaces();
$dataArray = explode("\n", $metadata->source);
foreach ($namespaces as $namespace) {
/** @var $classes ParsedClass[] */
$classes = $namespace->getClasses();
foreach ($classes as $class) {
// Skip interfaces
if ($class->isInterface()) {
continue;
}
// Look for aspects
if (in_array('Go\Aop\Aspect', $class->getInterfaceNames())) {
continue;
}
$methods = $class->getMethods();
foreach ($methods as $method) {
/** @var $method ReflectionMethod` * */
if ($method->getDeclaringClassName() != $class->getName()) {
continue;
}
// methods from traits have the same declaring class name, so check that the filenames match, too
if ($method->getFileName() != $class->getFileName()) {
continue;
}
if ($method->isAbstract()) {
continue;
}
$beforeDefinition = $method->isStatic()
? $this->beforeStatic
: $this->before;
// replace return with yield when doccomment shows it returns a Generator
if (preg_match('/(\@return\s+[\\\]?Generator)/', $method->getDocComment())) {
$beforeDefinition = str_replace('return', 'yield', $beforeDefinition);
}
$reflectedParams = $method->getParameters();
$params = [];
foreach ($reflectedParams as $reflectedParam) {
/** @var $reflectedParam ReflectionParameter * */
$params[] = ($reflectedParam->isPassedByReference() ? '&$' : '$') . $reflectedParam->getName();
}
$params = implode(", ", $params);
$beforeDefinition = sprintf($beforeDefinition, $params);
for ($i = $method->getStartLine() - 1; $i < $method->getEndLine(); $i++) {
$pos = strpos($dataArray[$i], '{');
if ($pos === false) {
continue;
} else {
// Bug FIX for functions that have the curly bracket as default on their own parameters:
// Launch a "continue" command if the bracket found have a quote (') or a double quote (")
// exactly just before or after
if (in_array(substr($dataArray[$i], $pos - 1, 1), ['"', "'"]) ||
in_array(substr($dataArray[$i], $pos + 1, 1), ['"', "'"])
) {
continue;
}
}
$dataArray[$i] = substr($dataArray[$i], 0, $pos + 1) . $beforeDefinition . substr($dataArray[$i], $pos + 1);
break;
}
}
}
}
$metadata->source = implode("\n", $dataArray);
}
}PK ~?VU] src/AspectMock/Kernel.phpnu W+A files()->name('*.php')->in($dir);
foreach ($files as $file) {
$this->loadFile($file->getRealpath());
}
}
/**
* Includes file and injects aspect pointcuts into int
*
* @param $file
*/
public function loadFile($file)
{
include FilterInjectorTransformer::rewrite($file);
}
protected function registerTransformers()
{
$cachePathManager = $this->getContainer()->get('aspect.cache.path.manager');;
$sourceTransformers = array(
new FilterInjectorTransformer($this, SourceTransformingLoader::getId(), $cachePathManager),
new MagicConstantTransformer($this),
new BeforeMockTransformer(
$this,
new TokenReflection\Broker(
new CleanableMemory()
),
$this->getContainer()->get('aspect.advice_matcher'),
$cachePathManager,
$this->getContainer()->get('aspect.cached.loader')
)
);
return array(
new CachingTransformer($this, $sourceTransformers, $cachePathManager)
);
}
}
require __DIR__ . '/Intercept/before_mock.php';PK ~?V$% + src/AspectMock/Proxy/AnythingClassProxy.phpnu W+A className = $class_name;
$this->reflected = new \ReflectionClass('AspectMock\Proxy\Anything');
}
public function isDefined()
{
return false;
}
public function construct()
{
return new Anything($this->className);
}
public function make()
{
return new Anything($this->className);
}
public function interfaces()
{
return array();
}
public function hasMethod($method)
{
return false;
}
}
PK ~?V?a ! src/AspectMock/Proxy/Verifier.phpnu W+A className,$method)
? '::'
: '->';
}
protected function onlyExpectedArguments($expectedParams, $passedArgs)
{
return empty($expectedParams) ?
$passedArgs :
array_slice($passedArgs, 0, count($expectedParams));
}
/**
* Verifies a method was invoked at least once.
* In second argument you can specify with which params method expected to be invoked;
*
* ``` php
* verifyInvoked('save');
* $user->verifyInvoked('setName',['davert']);
*
* ?>
* ```
*
* @param $name
* @param null $params
* @throws \PHPUnit_Framework_ExpectationFailedException
* @param array $params
* @throws fail
*/
public function verifyInvoked($name, $params = null)
{
$calls = $this->getCallsForMethod($name);
$separator = $this->callSyntax($name);
if (empty($calls)) throw new fail(sprintf($this->invokedFail, $this->className.$separator.$name, ''));
if (is_array($params)) {
foreach ($calls as $args) {
if ($this->onlyExpectedArguments($params, $args) === $params) return;
}
$params = ArgumentsFormatter::toString($params);
$gotParams = ArgumentsFormatter::toString($calls[0]);
throw new fail(sprintf($this->invokedFail, $this->className.$separator.$name."($params)", $this->className.$separator.$name."($gotParams)"));
} else if(is_callable($params)) {
$params($calls);
}
}
/**
* Verifies that method was invoked only once.
*
* @param $name
* @param array $params
*/
public function verifyInvokedOnce($name, $params = null)
{
$this->verifyInvokedMultipleTimes($name, 1, $params);
}
/**
* Verifies that method was called exactly $times times.
*
* ``` php
* verifyInvokedMultipleTimes('save',2);
* $user->verifyInvokedMultipleTimes('dispatchEvent',3,['before_validate']);
* $user->verifyInvokedMultipleTimes('dispatchEvent',4,['after_save']);
* ?>
* ```
*
* @param $name
* @param $times
* @param array $params
* @throws \PHPUnit_Framework_ExpectationFailedException
*/
public function verifyInvokedMultipleTimes($name, $times, $params = null)
{
if ($times == 0) return $this->verifyNeverInvoked($name, $params);
$calls = $this->getCallsForMethod($name);
$separator = $this->callSyntax($name);
if (empty($calls)) throw new fail(sprintf($this->notInvokedMultipleTimesFail, $this->className.$separator.$name, $times));
if (is_array($params)) {
$equals = 0;
foreach ($calls as $args) {
if ($this->onlyExpectedArguments($params, $args) == $params) $equals++;
}
if ($equals == $times) return;
$params = ArgumentsFormatter::toString($params);
throw new fail(sprintf($this->invokedMultipleTimesFail, $this->className.$separator.$name."($params)", $times, $equals));
} else if(is_callable($params)) {
$params($calls);
}
$num_calls = count($calls);
if ($num_calls != $times) throw new fail(sprintf($this->invokedMultipleTimesFail, $this->className.$separator.$name, $times, $num_calls));
}
/**
* Verifies that method was not called.
* In second argument with which arguments is not expected to be called.
*
* ``` php
* setName('davert');
* $user->verifyNeverInvoked('setName'); // fail
* $user->verifyNeverInvoked('setName',['davert']); // fail
* $user->verifyNeverInvoked('setName',['bob']); // success
* $user->verifyNeverInvoked('setName',[]); // success
* ?>
* ```
*
* @param $name
* @param null $params
* @throws \PHPUnit_Framework_ExpectationFailedException
*/
public function verifyNeverInvoked($name, $params = null)
{
$calls = $this->getCallsForMethod($name);
$separator = $this->callSyntax($name);
if (is_array($params)) {
if (empty($calls)) return;
$params = ArgumentsFormatter::toString($params);
foreach ($calls as $args) {
if ($this->onlyExpectedArguments($params, $args) == $params) throw new fail(sprintf($this->neverInvoked, $this->className));
}
return;
}
if (count($calls)) throw new fail(sprintf($this->neverInvoked, $this->className.$separator.$name));
}
}
PK ~?Vi &