Skip to content
This repository has been archived by the owner on Nov 23, 2022. It is now read-only.

Commit

Permalink
Merge branch '1.0' fix #155
Browse files Browse the repository at this point in the history
* 1.0:
  Make test conditional on Phar actually existing
  Fix up the nesting on the version check
  Adding php 5.6 to travis
  Fixing up the construction of internal classes such as Phar
  • Loading branch information
mlively committed Jan 26, 2015
2 parents f849f9f + 004b5bc commit e6c899d
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 10 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ php:
- 5.3
- 5.4
- 5.5
- 5.6
- hhvm

matrix:
Expand Down
103 changes: 93 additions & 10 deletions src/Phake/ClassGenerator/MockClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,6 @@ public function generate($newClassName, $mockedClassName, Phake_Mock_InfoRegistr

if (!$mockedClass->isInterface()) {
$extends = "extends {$mockedClassName}";
if ('PDO' == $mockedClassName
|| 'PDOStatement' == $mockedClassName
|| $mockedClass->isSubclassOf('PDO')
|| $mockedClass->isSubclassOf('PDOStatement')
) {
$constructor = "public function __construct() {}";
}
} elseif ($mockedClassName != 'Phake_IMock') {
$implements = ", $mockedClassName";

Expand All @@ -183,14 +176,18 @@ class {$newClassName} {$extends}
public static \$__PHAKE_staticInfo;
const __PHAKE_name = '{$mockedClassName}';
public \$__PHAKE_constructorArgs;
{$constructor}
/**
* @return void
*/
public function __destruct() {}
{$this->generateSafeConstructorOverride($mockedClass)}
{$this->generateMockedMethods($mockedClass, $interfaces)}
}
";
Expand Down Expand Up @@ -218,6 +215,29 @@ public function instantiate(
Phake_Stubber_IAnswer $defaultAnswer,
array $constructorArgs = null
) {
$reflClass = new ReflectionClass($newClassName);
$constructor = $reflClass->getConstructor();

if ($constructor == null || ($constructor->class == $newClassName && $constructor->getNumberOfParameters() == 0))
{
$mockObject = new $newClassName;
}
elseif (version_compare(PHP_VERSION, '5.4.0', '>=')) {
try {
$mockObject = $reflClass->newInstanceWithoutConstructor();
} catch (ReflectionException $ignore) {
}
}

if (empty($mockObject))
{
$mockObject = @unserialize(sprintf('O:%d:"%s":0:{}', strlen($newClassName), $newClassName));
if ($mockObject == null)
{
$mockObject = unserialize(sprintf('C:%d:"%s":0:{}', strlen($newClassName), $newClassName));
}
}

try {
$mockObject = @unserialize(sprintf('O:%d:"%s":0:{}', strlen($newClassName), $newClassName));
if ($mockObject === false) {
Expand All @@ -231,6 +251,7 @@ public function instantiate(
}

$mockObject->__PHAKE_info = $this->createMockInfo($newClassName::__PHAKE_name, $recorder, $mapper, $defaultAnswer);
$mockObject->__PHAKE_constructorArgs = $constructorArgs;

$mockReflClass = new ReflectionClass($mockObject);
if (null !== $constructorArgs && $mockReflClass->hasMethod('__construct')) {
Expand Down Expand Up @@ -270,6 +291,67 @@ protected function generateMockedMethods(ReflectionClass $mockedClass, array $mo
return $methodDefs;
}


private function isConstructorDefinedInInterface(ReflectionClass $mockedClass)
{
$constructor = $mockedClass->getConstructor();

if (empty($constructor) && $mockedClass->hasMethod('__construct'))
{
$constructor = $mockedClass->getMethod('__construct');
}

if (empty($constructor))
{
return false;
}

$reflectionClass = $constructor->getDeclaringClass();

if ($reflectionClass->isInterface())
{
return true;
}

/* @var ReflectionClass $interface */
foreach ($reflectionClass->getInterfaces() as $interface)
{
if ($interface->getConstructor() !== null)
{
return true;
}
}

$parent = $reflectionClass->getParentClass();
if (!empty($parent))
{
return $this->isConstructorDefinedInInterface($parent);
}
else
{
return false;
}
}

private function generateSafeConstructorOverride(ReflectionClass $mockedClass)
{
if (!$this->isConstructorDefinedInInterface($mockedClass))
{
$constructorDef = "
public function __construct()
{
{$this->getConstructorChaining($mockedClass)}
}
";
return $constructorDef;
}
else
{
return '';
}
}


/**
* Creates the constructor implementation
*
Expand All @@ -280,9 +362,10 @@ protected function getConstructorChaining(ReflectionClass $originalClass)
{
return $originalClass->hasMethod('__construct') ? "
if (is_array(\$constructorArgs))
if (is_array(\$this->__PHAKE_constructorArgs))
{
call_user_func_array(array(\$this, 'parent::__construct'), \$constructorArgs);
call_user_func_array(array(\$this, 'parent::__construct'), \$this->__PHAKE_constructorArgs);
\$this->__PHAKE_constructorArgs = null;
}
" : "";
}
Expand Down
10 changes: 10 additions & 0 deletions tests/PhakeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,16 @@ public function testResettingStaticCallRecorder()
Phake::verifyStatic($mock)->staticMethod();
}

public function testMockingPhar()
{
if (!class_exists('Phar'))
{
$this->markTestSkipped('Phar class does not exist');
}
$phar = Phake::mock('Phar');

$this->assertInstanceOf('Phar', $phar);
}

/**
* Tests that resetting a mock clears the stubber
Expand Down

0 comments on commit e6c899d

Please sign in to comment.