5 * Copyright (c) 2002-2009, Sebastian Bergmann <sb@sebastian-bergmann.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.
39 * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
40 * @copyright 2002-2009 Sebastian Bergmann <sb@sebastian-bergmann.de>
41 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 * @link http://www.phpunit.de/
44 * @since File available since Release 3.3.0
47 require_once 'PHPUnit/Util/Filter.php';
48 require_once 'PHPUnit/Util/Template.php';
49 require_once 'PHPUnit/Util/Skeleton.php';
51 PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT');
54 * Generator for test class skeletons from classes.
58 * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
59 * @copyright 2002-2009 Sebastian Bergmann <sb@sebastian-bergmann.de>
60 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
61 * @version Release: 3.3.17
62 * @link http://www.phpunit.de/
63 * @since Class available since Release 3.3.0
65 class PHPUnit_Util_Skeleton_Test extends PHPUnit_Util_Skeleton
70 protected $methodNameCounter = array();
75 * @param string $inClassName
76 * @param string $inSourceFile
77 * @throws RuntimeException
79 public function __construct($inClassName, $inSourceFile = '')
81 $this->inClassName = $inClassName;
82 $this->outClassName = $inClassName . 'Test';
84 if (class_exists($inClassName)) {
85 $this->inSourceFile = '<internal>';
88 else if (empty($inSourceFile) && is_file($inClassName . '.php')) {
89 $this->inSourceFile = $inClassName . '.php';
92 else if (empty($inSourceFile) ||
93 is_file(str_replace('_', '/', $inClassName) . '.php')) {
94 $this->inSourceFile = str_replace('_', '/', $inClassName) . '.php';
95 $this->outSourceFile = str_replace('_', '/', $inClassName) . 'Test.php';
98 else if (empty($inSourceFile)) {
99 throw new RuntimeException(
101 'Neither "%s.php" nor "%s.php" could be opened.',
103 str_replace('_', '/', $inClassName)
108 else if (!is_file($inSourceFile)) {
109 throw new RuntimeException(
111 '"%s" could not be opened.',
117 $this->inSourceFile = $inSourceFile;
120 if ($this->inSourceFile != '<internal>') {
121 include_once $this->inSourceFile;
124 if (!class_exists($inClassName)) {
125 throw new RuntimeException(
127 'Could not find class "%s" in "%s".',
130 realpath($this->inSourceFile)
135 $this->outSourceFile = dirname($this->inSourceFile) . DIRECTORY_SEPARATOR . $this->inClassName . 'Test.php';
139 * Generates the test class' source.
141 * @param boolean $verbose
144 public function generate($verbose = FALSE)
146 $class = new ReflectionClass($this->inClassName);
148 $incompleteMethods = '';
150 foreach ($class->getMethods() as $method) {
151 if (!$method->isConstructor() &&
152 !$method->isAbstract() &&
153 $method->isPublic() &&
154 $method->getDeclaringClass()->getName() == $this->inClassName) {
155 $assertAnnotationFound = FALSE;
157 if (preg_match_all('/@assert(.*)$/Um', $method->getDocComment(), $annotations)) {
158 foreach ($annotations[1] as $annotation) {
159 if (preg_match('/\((.*)\)\s+([^\s]*)\s+(.*)/', $annotation, $matches)) {
160 switch ($matches[2]) {
162 $assertion = 'Equals';
167 $assertion = 'NotEquals';
177 $assertion = 'NotSame';
182 $assertion = 'GreaterThan';
187 $assertion = 'GreaterThanOrEqual';
192 $assertion = 'LessThan';
197 $assertion = 'LessThanOrEqual';
202 $assertion = 'exception';
207 throw new RuntimeException;
211 if ($assertion == 'exception') {
212 $template = 'TestMethodException';
215 else if ($assertion == 'Equals' && strtolower($matches[3]) == 'true') {
217 $template = 'TestMethodBool';
220 else if ($assertion == 'NotEquals' && strtolower($matches[3]) == 'true') {
221 $assertion = 'False';
222 $template = 'TestMethodBool';
225 else if ($assertion == 'Equals' && strtolower($matches[3]) == 'false') {
226 $assertion = 'False';
227 $template = 'TestMethodBool';
230 else if ($assertion == 'NotEquals' && strtolower($matches[3]) == 'false') {
232 $template = 'TestMethodBool';
236 $template = 'TestMethod';
239 if ($method->isStatic()) {
240 $template .= 'Static';
243 $methodTemplate = new PHPUnit_Util_Template(
245 '%s%sTemplate%s%s.tpl',
254 $origMethodName = $method->getName();
255 $methodName = ucfirst($origMethodName);
257 if (isset($this->methodNameCounter[$methodName])) {
258 $this->methodNameCounter[$methodName]++;
260 $this->methodNameCounter[$methodName] = 1;
263 if ($this->methodNameCounter[$methodName] > 1) {
264 $methodName .= $this->methodNameCounter[$methodName];
267 $methodTemplate->setVar(
269 'annotation' => trim($annotation),
270 'arguments' => $matches[1],
271 'assertion' => isset($assertion) ? $assertion : '',
272 'expected' => $matches[3],
273 'origMethodName' => $origMethodName,
274 'className' => $this->inClassName,
275 'methodName' => $methodName
279 $methods .= $methodTemplate->render();
281 $assertAnnotationFound = TRUE;
286 if (!$assertAnnotationFound) {
287 $methodTemplate = new PHPUnit_Util_Template(
289 '%s%sTemplate%sIncompleteTestMethod.tpl',
297 $methodTemplate->setVar(
299 'methodName' => ucfirst($method->getName())
303 $incompleteMethods .= $methodTemplate->render();
308 $classTemplate = new PHPUnit_Util_Template(
310 '%s%sTemplate%sTestClass.tpl',
318 if ($this->inSourceFile != '<internal>') {
319 $requireClassFile = sprintf(
320 "\n\nrequire_once '%s';",
325 $requireClassFile = '';
328 $classTemplate->setVar(
330 'className' => $this->inClassName,
331 'requireClassFile' => $requireClassFile,
332 'methods' => $methods . $incompleteMethods,
333 'date' => date('Y-m-d'),
334 'time' => date('H:i:s')
339 return $classTemplate->render();
342 'code' => $classTemplate->render(),
343 'incomplete' => empty($methods)