5 * Copyright (c) 2002-2011, Sebastian Bergmann <sebastian@phpunit.de>.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
20 * * Neither the name of Sebastian Bergmann nor the names of his
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
38 * @subpackage Util_Skeleton
39 * @author Sebastian Bergmann <sebastian@phpunit.de>
40 * @copyright 2002-2011 Sebastian Bergmann <sebastian@phpunit.de>
41 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
42 * @link http://www.phpunit.de/
43 * @since File available since Release 3.3.0
46 require_once 'Text/Template.php';
49 * Generator for test class skeletons from classes.
52 * @subpackage Util_Skeleton
53 * @author Sebastian Bergmann <sebastian@phpunit.de>
54 * @copyright 2002-2011 Sebastian Bergmann <sebastian@phpunit.de>
55 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
56 * @version Release: 3.5.13
57 * @link http://www.phpunit.de/
58 * @since Class available since Release 3.3.0
60 class PHPUnit_Util_Skeleton_Test extends PHPUnit_Util_Skeleton
65 protected $methodNameCounter = array();
70 * @param string $inClassName
71 * @param string $inSourceFile
72 * @param string $outClassName
73 * @param string $outSourceFile
74 * @throws RuntimeException
76 public function __construct($inClassName, $inSourceFile = '', $outClassName = '', $outSourceFile = '')
78 if (class_exists($inClassName)) {
79 $reflector = new ReflectionClass($inClassName);
80 $inSourceFile = $reflector->getFileName();
82 if ($inSourceFile === FALSE) {
83 $inSourceFile = '<internal>';
88 if (empty($inSourceFile)) {
89 $possibleFilenames = array(
90 $inClassName . '.php',
91 PHPUnit_Util_Filesystem::classNameToFilename($inClassName)
94 foreach ($possibleFilenames as $possibleFilename) {
95 if (is_file($possibleFilename)) {
96 $inSourceFile = $possibleFilename;
101 if (empty($inSourceFile)) {
102 throw new PHPUnit_Framework_Exception(
104 'Neither "%s" nor "%s" could be opened.',
105 $possibleFilenames[0],
106 $possibleFilenames[1]
111 if (!is_file($inSourceFile)) {
112 throw new PHPUnit_Framework_Exception(
114 '"%s" could not be opened.',
121 $inSourceFile = realpath($inSourceFile);
122 include_once $inSourceFile;
124 if (!class_exists($inClassName)) {
125 throw new PHPUnit_Framework_Exception(
127 'Could not find class "%s" in "%s".',
136 if (empty($outClassName)) {
137 $outClassName = $inClassName . 'Test';
140 if (empty($outSourceFile)) {
141 $outSourceFile = dirname($inSourceFile) . DIRECTORY_SEPARATOR . $outClassName . '.php';
145 $inClassName, $inSourceFile, $outClassName, $outSourceFile
150 * Generates the test class' source.
152 * @param boolean $verbose
155 public function generate($verbose = FALSE)
157 $class = new ReflectionClass(
158 $this->inClassName['fullyQualifiedClassName']
161 $incompleteMethods = '';
163 foreach ($class->getMethods() as $method) {
164 if (!$method->isConstructor() &&
165 !$method->isAbstract() &&
166 $method->isPublic() &&
167 $method->getDeclaringClass()->getName() == $this->inClassName['fullyQualifiedClassName']) {
168 $assertAnnotationFound = FALSE;
170 if (preg_match_all('/@assert(.*)$/Um', $method->getDocComment(), $annotations)) {
171 foreach ($annotations[1] as $annotation) {
172 if (preg_match('/\((.*)\)\s+([^\s]*)\s+(.*)/', $annotation, $matches)) {
173 switch ($matches[2]) {
175 $assertion = 'Equals';
180 $assertion = 'NotEquals';
190 $assertion = 'NotSame';
195 $assertion = 'GreaterThan';
200 $assertion = 'GreaterThanOrEqual';
205 $assertion = 'LessThan';
210 $assertion = 'LessThanOrEqual';
215 $assertion = 'exception';
220 throw new PHPUnit_Framework_Exception(
222 'Token "%s" could not be parsed in @assert annotation.',
229 if ($assertion == 'exception') {
230 $template = 'TestMethodException';
233 else if ($assertion == 'Equals' &&
234 strtolower($matches[3]) == 'true') {
236 $template = 'TestMethodBool';
239 else if ($assertion == 'NotEquals' &&
240 strtolower($matches[3]) == 'true') {
241 $assertion = 'False';
242 $template = 'TestMethodBool';
245 else if ($assertion == 'Equals' &&
246 strtolower($matches[3]) == 'false') {
247 $assertion = 'False';
248 $template = 'TestMethodBool';
251 else if ($assertion == 'NotEquals' &&
252 strtolower($matches[3]) == 'false') {
254 $template = 'TestMethodBool';
258 $template = 'TestMethod';
261 if ($method->isStatic()) {
262 $template .= 'Static';
265 $methodTemplate = new Text_Template(
267 '%s%sTemplate%s%s.tpl',
276 $origMethodName = $method->getName();
277 $methodName = ucfirst($origMethodName);
279 if (isset($this->methodNameCounter[$methodName])) {
280 $this->methodNameCounter[$methodName]++;
282 $this->methodNameCounter[$methodName] = 1;
285 if ($this->methodNameCounter[$methodName] > 1) {
286 $methodName .= $this->methodNameCounter[$methodName];
289 $methodTemplate->setVar(
291 'annotation' => trim($annotation),
292 'arguments' => $matches[1],
293 'assertion' => isset($assertion) ? $assertion : '',
294 'expected' => $matches[3],
295 'origMethodName' => $origMethodName,
296 'className' => $this->inClassName['fullyQualifiedClassName'],
297 'methodName' => $methodName
301 $methods .= $methodTemplate->render();
303 $assertAnnotationFound = TRUE;
308 if (!$assertAnnotationFound) {
309 $methodTemplate = new Text_Template(
311 '%s%sTemplate%sIncompleteTestMethod.tpl',
319 $methodTemplate->setVar(
321 'methodName' => ucfirst($method->getName())
325 $incompleteMethods .= $methodTemplate->render();
330 $classTemplate = new Text_Template(
332 '%s%sTemplate%sTestClass.tpl',
340 if ($this->inSourceFile != '<internal>') {
341 $requireClassFile = sprintf(
342 "\n\nrequire_once '%s';",
347 $requireClassFile = '';
350 if ($this->outClassName['namespace'] != '') {
351 $namespace = "\nnamespace " .
352 $this->outClassName['namespace'] . ";\n";
357 $classTemplate->setVar(
359 'namespace' => $namespace,
360 'namespaceSeparator' => !empty($namespace) ? '\\' : '',
361 'className' => $this->inClassName['className'],
362 'testClassName' => $this->outClassName['className'],
363 'requireClassFile' => $requireClassFile,
364 'methods' => $methods . $incompleteMethods,
365 'date' => date('Y-m-d'),
366 'time' => date('H:i:s')
371 return $classTemplate->render();
374 'code' => $classTemplate->render(),
375 'incomplete' => empty($methods)