diff --git a/src/TUnit/framework/mock/MockObject.php b/src/TUnit/framework/mock/MockObject.php index d328c37..21c7dd5 100644 --- a/src/TUnit/framework/mock/MockObject.php +++ b/src/TUnit/framework/mock/MockObject.php @@ -7,6 +7,8 @@ protected $referenceObject; protected $methods; + protected static $registry = array(); + public function __construct($class) { if (!class_exists($class) || !interface_exists($class)) { throw new InvalidArgumentException('The class "' . $class . '" does not exist'); @@ -19,12 +21,33 @@ } $this->referenceObject = $refClass; - $this->methods = array( - 'default' => array(), + $this->methods = array( + 'default' => array( + $this->referenceObject->getConstructor()->getName() => array( + 'body' => '', + 'call_parent' => true + ) + ), 'generic' => array() ); } + public static function registerInvocation($name, MockInvocation $invocation) { + if (!isset(self::$registry[$name])) { + throw new LogicException('Unable to register invocation because the object does not exist in the registry'); + } + + self::$registry[$name]->registerInvocation($invocation); + } + + public static function getTracker($name) { + if (!isset(self::$registry[$name])) { + throw new LogicException('Unable to retrieve invocation tracker because the object does not exist in the registry'); + } + + return self::$registry[$name]; + } + public function addMethod($methodName, $callParent = false, $body = '') { $methodType = 'generic'; @@ -55,10 +78,6 @@ return !$method->isFinal() && !$method->isPrivate() && !$method->isStatic(); } - protected function getDefaultMethodBody() { - - } - public function generate(array $constructorArgs = array(), $name = '') { if (empty($name)) { $className = $this->referenceObject->getName(); @@ -70,15 +89,29 @@ if (class_exists($name) || interface_exists($name)) { throw new RuntimeException('Cannot use the name "' . $name . '" for mock object because the class or interface already exists'); } + + $code = $this->generateClassDefinition($name); + eval($code); + + $obj = new ReflectionClass($name); + $obj = $obj->newInstanceArgs($constructorArgs); + self::$registry[$name] = new InvocationTracker(); + return $obj; } - private function generateClassDefinition(ReflectionClass $class, array $methods, array $args, $name) { - $code = 'class ' . $name . ' ' . ($class->isInterface() ? 'implements' : 'extends') . $class->getName() . ' {' . "\n"; + protected function generateClassDefinition($name) { + $code = 'class ' . $name . ' '; + if ($this->referenceObject->isInterface()) { + $code .= 'implements ' . $this->referenceObject->getName() . ', MockObject'; + } else { + $code .= 'extends ' . $this->getReferenceObject->getName() . ' implements MockObject'; + } - $genericMethods = array(); - foreach ($methods as $method) { - if ($class->hasMethod($method)) { - $code .= self::generateMethodDefinition($class->getMethod($method)); + $code .= " {\n"; + + foreach ($this->methods as $type => $methods) { + foreach ($methods as $method => $methodData) { + $code .= $this->generateMethodDefinition($type, $method, $methodData); } } @@ -86,20 +119,28 @@ return $code; } - private function generateMethodDefinition(ReflectionMethod $method) { + protected function generateMethodDefinition($type, $name, array $methodData) { + $modifier = 'public'; + $params = ''; + $paramList = ''; + if ($type === 'default') { + $method = $this->referenceObject->getMethod($name); + $modifier = ($method->isPublic()) ? 'public' : 'protected'; + $params = Util::buildParameterList($method); + $paramList = Util::getParameterNameList($method); + } - } - - private function generateGenericMethodDefinition(array $methods) { - $code = 'public function __call($method, array $args) {' . "\n"; - $code .= ' $allowedMethods = ' . var_export($methods, true) . ';' . "\n"; - $code .= ' if (in_array($method, $allowedMethods)) {' . "\n"; - $code .= ' ' . "\n"; - $code .= ' } else {' . "\n"; - $code .= ' throw new BadMethodCallException(\'The method "\' . $method . \'" does not exist on the mocked class "\' . get_class($this) . \'"\');' . "\n"; - $code .= ' }' . "\n"; - $code .= '}'; + $code = " $modifier function $name($params) {\n"; + $code .= " MockObject::registerInvocation(get_class($this), __FUNCTION__, func_get_args());\n"; + if ($methodData['call_parent']) { + $code .= " parent::$name($paramList);\n"; + } + if (!empty($methodData['body'])) { + $code .= "\t\t" . str_replace("\n", "\n\t\t", $methodData['body']) . "\n"; + } + + $code .= ' }'; return $code; } diff --git a/src/TUnit/util/Util.php b/src/TUnit/util/Util.php index a9d46d5..b7a63b4 100644 --- a/src/TUnit/util/Util.php +++ b/src/TUnit/util/Util.php @@ -22,10 +22,57 @@ case 'resource': return 'resource of type ' . get_resource_type($var); case 'array': - return 'array(' . count($var) . ')'; + return 'array[' . count($var) . ']'; } } + public static function buildParameterDefinition(ReflectionMethod $method) { + $paramList = ''; + foreach ($method->getParameters() as $i => $param) { + if ($param->getClass()) { + $paramList .= $param->getClass() . ' '; + } else if ($param->isArray()) { + $paramList .= 'array '; + } + + if ($param->isPassedByReference()) { + $paramList .= '&'; + } + + $paramList .= self::repairParameterName($param->getName(), $i); + + if ($param->isOptional()) { + $paramList .= ' = '; + if ($param->isDefaultValueAvailable()) { + $paramList .= var_export($param->getDefaultValue(), true); + } else { + $paramList .= 'null'; + } + } + + $paramList .= ','; + } + + return rtrim($paramList, ', '); + } + + private static repairParameterName($name, $position) { + if (empty($name)) { + $name = 'param' . $position; + } + + return $name; + } + + public static function buildParameterNameList(ReflectionMethod $method) { + $list = ''; + foreach ($method->getParameters() as $param) { + $list .= '$' . self::repairParamterName($param->getName()) . ', '; + } + + return rtrim($list, ', '); + } + } ?> \ No newline at end of file