PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/phpunit-skeleton-generator/PHPUnit/SkeletonGenerator/Test.php

https://github.com/EHER/phpunit-all-in-one
PHP | 372 lines | 267 code | 38 blank | 67 comment | 36 complexity | 486dff823fc271c1a5bb71eb7b44bc78 MD5 | raw file
  1. <?php
  2. /**
  3. * PHPUnit_SkeletonGenerator
  4. *
  5. * Copyright (c) 2012, Sebastian Bergmann <sebastian@phpunit.de>.
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * * Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  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
  18. * distribution.
  19. *
  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.
  23. *
  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.
  36. *
  37. * @package PHPUnit
  38. * @subpackage SkeletonGenerator
  39. * @author Sebastian Bergmann <sebastian@phpunit.de>
  40. * @copyright 2012 Sebastian Bergmann <sebastian@phpunit.de>
  41. * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
  42. * @link http://www.phpunit.de/
  43. * @since File available since Release 1.0.0
  44. */
  45. /**
  46. * Generator for test class skeletons from classes.
  47. *
  48. * @package PHPUnit
  49. * @subpackage SkeletonGenerator
  50. * @author Sebastian Bergmann <sebastian@phpunit.de>
  51. * @copyright 2012 Sebastian Bergmann <sebastian@phpunit.de>
  52. * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
  53. * @version Release: 1.1.0
  54. * @link http://www.phpunit.de/
  55. * @since Class available since Release 1.0.0
  56. */
  57. class PHPUnit_SkeletonGenerator_Test extends PHPUnit_SkeletonGenerator
  58. {
  59. /**
  60. * @var array
  61. */
  62. protected $methodNameCounter = array();
  63. /**
  64. * Constructor.
  65. *
  66. * @param string $inClassName
  67. * @param string $inSourceFile
  68. * @param string $outClassName
  69. * @param string $outSourceFile
  70. * @throws RuntimeException
  71. */
  72. public function __construct($inClassName, $inSourceFile = '', $outClassName = '', $outSourceFile = '')
  73. {
  74. if (class_exists($inClassName)) {
  75. $reflector = new ReflectionClass($inClassName);
  76. $inSourceFile = $reflector->getFileName();
  77. if ($inSourceFile === FALSE) {
  78. $inSourceFile = '<internal>';
  79. }
  80. unset($reflector);
  81. } else {
  82. if (empty($inSourceFile)) {
  83. $possibleFilenames = array(
  84. $inClassName . '.php',
  85. str_replace(
  86. array('_', '\\'),
  87. DIRECTORY_SEPARATOR,
  88. $inClassName
  89. ) . '.php'
  90. );
  91. foreach ($possibleFilenames as $possibleFilename) {
  92. if (is_file($possibleFilename)) {
  93. $inSourceFile = $possibleFilename;
  94. }
  95. }
  96. }
  97. if (empty($inSourceFile)) {
  98. throw new RuntimeException(
  99. sprintf(
  100. 'Neither "%s" nor "%s" could be opened.',
  101. $possibleFilenames[0],
  102. $possibleFilenames[1]
  103. )
  104. );
  105. }
  106. if (!is_file($inSourceFile)) {
  107. throw new RuntimeException(
  108. sprintf(
  109. '"%s" could not be opened.',
  110. $inSourceFile
  111. )
  112. );
  113. }
  114. $inSourceFile = realpath($inSourceFile);
  115. include_once $inSourceFile;
  116. if (!class_exists($inClassName)) {
  117. throw new RuntimeException(
  118. sprintf(
  119. 'Could not find class "%s" in "%s".',
  120. $inClassName,
  121. $inSourceFile
  122. )
  123. );
  124. }
  125. }
  126. if (empty($outClassName)) {
  127. $outClassName = $inClassName . 'Test';
  128. }
  129. if (empty($outSourceFile)) {
  130. $outSourceFile = dirname($inSourceFile) . DIRECTORY_SEPARATOR . $outClassName . '.php';
  131. }
  132. parent::__construct(
  133. $inClassName, $inSourceFile, $outClassName, $outSourceFile
  134. );
  135. }
  136. /**
  137. * Generates the test class' source.
  138. *
  139. * @param boolean $verbose
  140. * @return mixed
  141. */
  142. public function generate($verbose = FALSE)
  143. {
  144. $class = new ReflectionClass(
  145. $this->inClassName['fullyQualifiedClassName']
  146. );
  147. $methods = '';
  148. $incompleteMethods = '';
  149. foreach ($class->getMethods() as $method) {
  150. if (!$method->isConstructor() &&
  151. !$method->isAbstract() &&
  152. $method->isPublic() &&
  153. $method->getDeclaringClass()->getName() == $this->inClassName['fullyQualifiedClassName']) {
  154. $assertAnnotationFound = FALSE;
  155. if (preg_match_all('/@assert(.*)$/Um', $method->getDocComment(), $annotations)) {
  156. foreach ($annotations[1] as $annotation) {
  157. if (preg_match('/\((.*)\)\s+([^\s]*)\s+(.*)/', $annotation, $matches)) {
  158. switch ($matches[2]) {
  159. case '==': {
  160. $assertion = 'Equals';
  161. }
  162. break;
  163. case '!=': {
  164. $assertion = 'NotEquals';
  165. }
  166. break;
  167. case '===': {
  168. $assertion = 'Same';
  169. }
  170. break;
  171. case '!==': {
  172. $assertion = 'NotSame';
  173. }
  174. break;
  175. case '>': {
  176. $assertion = 'GreaterThan';
  177. }
  178. break;
  179. case '>=': {
  180. $assertion = 'GreaterThanOrEqual';
  181. }
  182. break;
  183. case '<': {
  184. $assertion = 'LessThan';
  185. }
  186. break;
  187. case '<=': {
  188. $assertion = 'LessThanOrEqual';
  189. }
  190. break;
  191. case 'throws': {
  192. $assertion = 'exception';
  193. }
  194. break;
  195. default: {
  196. throw new RuntimeException(
  197. sprintf(
  198. 'Token "%s" could not be parsed in @assert annotation.',
  199. $matches[2]
  200. )
  201. );
  202. }
  203. }
  204. if ($assertion == 'exception') {
  205. $template = 'TestMethodException';
  206. }
  207. else if ($assertion == 'Equals' &&
  208. strtolower($matches[3]) == 'true') {
  209. $assertion = 'True';
  210. $template = 'TestMethodBool';
  211. }
  212. else if ($assertion == 'NotEquals' &&
  213. strtolower($matches[3]) == 'true') {
  214. $assertion = 'False';
  215. $template = 'TestMethodBool';
  216. }
  217. else if ($assertion == 'Equals' &&
  218. strtolower($matches[3]) == 'false') {
  219. $assertion = 'False';
  220. $template = 'TestMethodBool';
  221. }
  222. else if ($assertion == 'NotEquals' &&
  223. strtolower($matches[3]) == 'false') {
  224. $assertion = 'True';
  225. $template = 'TestMethodBool';
  226. }
  227. else {
  228. $template = 'TestMethod';
  229. }
  230. if ($method->isStatic()) {
  231. $template .= 'Static';
  232. }
  233. $methodTemplate = new Text_Template(
  234. sprintf(
  235. '%s%sTemplate%s%s.tpl',
  236. dirname(__FILE__),
  237. DIRECTORY_SEPARATOR,
  238. DIRECTORY_SEPARATOR,
  239. $template
  240. )
  241. );
  242. $origMethodName = $method->getName();
  243. $methodName = ucfirst($origMethodName);
  244. if (isset($this->methodNameCounter[$methodName])) {
  245. $this->methodNameCounter[$methodName]++;
  246. } else {
  247. $this->methodNameCounter[$methodName] = 1;
  248. }
  249. if ($this->methodNameCounter[$methodName] > 1) {
  250. $methodName .= $this->methodNameCounter[$methodName];
  251. }
  252. $methodTemplate->setVar(
  253. array(
  254. 'annotation' => trim($annotation),
  255. 'arguments' => $matches[1],
  256. 'assertion' => isset($assertion) ? $assertion : '',
  257. 'expected' => $matches[3],
  258. 'origMethodName' => $origMethodName,
  259. 'className' => $this->inClassName['fullyQualifiedClassName'],
  260. 'methodName' => $methodName
  261. )
  262. );
  263. $methods .= $methodTemplate->render();
  264. $assertAnnotationFound = TRUE;
  265. }
  266. }
  267. }
  268. if (!$assertAnnotationFound) {
  269. $methodTemplate = new Text_Template(
  270. sprintf(
  271. '%s%sTemplate%sIncompleteTestMethod.tpl',
  272. dirname(__FILE__),
  273. DIRECTORY_SEPARATOR,
  274. DIRECTORY_SEPARATOR
  275. )
  276. );
  277. $methodTemplate->setVar(
  278. array(
  279. 'className' => $this->inClassName['fullyQualifiedClassName'],
  280. 'methodName' => ucfirst($method->getName()),
  281. 'origMethodName' => $method->getName()
  282. )
  283. );
  284. $incompleteMethods .= $methodTemplate->render();
  285. }
  286. }
  287. }
  288. $classTemplate = new Text_Template(
  289. sprintf(
  290. '%s%sTemplate%sTestClass.tpl',
  291. dirname(__FILE__),
  292. DIRECTORY_SEPARATOR,
  293. DIRECTORY_SEPARATOR
  294. )
  295. );
  296. if ($this->outClassName['namespace'] != '') {
  297. $namespace = "\nnamespace " .
  298. $this->outClassName['namespace'] . ";\n";
  299. } else {
  300. $namespace = '';
  301. }
  302. $classTemplate->setVar(
  303. array(
  304. 'namespace' => $namespace,
  305. 'namespaceSeparator' => !empty($namespace) ? '\\' : '',
  306. 'className' => $this->inClassName['className'],
  307. 'testClassName' => $this->outClassName['className'],
  308. 'methods' => $methods . $incompleteMethods,
  309. 'date' => date('Y-m-d'),
  310. 'time' => date('H:i:s')
  311. )
  312. );
  313. if (!$verbose) {
  314. return $classTemplate->render();
  315. } else {
  316. return array(
  317. 'code' => $classTemplate->render(),
  318. 'incomplete' => empty($methods)
  319. );
  320. }
  321. }
  322. }