PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/unit-test/phpunit-portable/Util/Skeleton/Class.php

http://buddypress-media.googlecode.com/
PHP | 327 lines | 191 code | 43 blank | 93 comment | 48 complexity | d9963761156a88c30f4958040e65be96 MD5 | raw file
Possible License(s): AGPL-1.0, Apache-2.0, GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * PHPUnit
  4. *
  5. * Copyright (c) 2002-2011, 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 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
  44. */
  45. require_once ( PHPU_BASE_PATH . '/Text/Template.php' );
  46. /**
  47. * Generator for class skeletons from test classes.
  48. *
  49. * @package PHPUnit
  50. * @subpackage Util_Skeleton
  51. * @author Sebastian Bergmann <sebastian@phpunit.de>
  52. * @copyright 2002-2011 Sebastian Bergmann <sebastian@phpunit.de>
  53. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  54. * @version Release: 3.5.13
  55. * @link http://www.phpunit.de/
  56. * @since Class available since Release 3.3.0
  57. */
  58. class PHPUnit_Util_Skeleton_Class extends PHPUnit_Util_Skeleton
  59. {
  60. /**
  61. * Constructor.
  62. *
  63. * @param string $inClassName
  64. * @param string $inSourceFile
  65. * @param string $outClassName
  66. * @param string $outSourceFile
  67. * @throws RuntimeException
  68. */
  69. public function __construct($inClassName, $inSourceFile = '', $outClassName = '', $outSourceFile = '')
  70. {
  71. if (empty($inSourceFile)) {
  72. $inSourceFile = $inClassName . '.php';
  73. }
  74. if (!is_file($inSourceFile)) {
  75. throw new PHPUnit_Framework_Exception(
  76. sprintf(
  77. '"%s" could not be opened.',
  78. $inSourceFile
  79. )
  80. );
  81. }
  82. if (empty($outClassName)) {
  83. $outClassName = substr($inClassName, 0, strlen($inClassName) - 4);
  84. }
  85. if (empty($outSourceFile)) {
  86. $outSourceFile = dirname($inSourceFile) . DIRECTORY_SEPARATOR .
  87. $outClassName . '.php';
  88. }
  89. parent::__construct(
  90. $inClassName, $inSourceFile, $outClassName, $outSourceFile
  91. );
  92. }
  93. /**
  94. * Generates the class' source.
  95. *
  96. * @return mixed
  97. */
  98. public function generate()
  99. {
  100. $methods = '';
  101. foreach ($this->findTestedMethods() as $method) {
  102. $methodTemplate = new Text_Template(
  103. sprintf(
  104. '%s%sTemplate%sMethod.tpl',
  105. dirname(__FILE__),
  106. DIRECTORY_SEPARATOR,
  107. DIRECTORY_SEPARATOR
  108. )
  109. );
  110. $methodTemplate->setVar(
  111. array(
  112. 'methodName' => $method,
  113. )
  114. );
  115. $methods .= $methodTemplate->render();
  116. }
  117. $classTemplate = new Text_Template(
  118. sprintf(
  119. '%s%sTemplate%sClass.tpl',
  120. dirname(__FILE__),
  121. DIRECTORY_SEPARATOR,
  122. DIRECTORY_SEPARATOR
  123. )
  124. );
  125. $classTemplate->setVar(
  126. array(
  127. 'className' => $this->outClassName['fullyQualifiedClassName'],
  128. 'methods' => $methods,
  129. 'date' => date('Y-m-d'),
  130. 'time' => date('H:i:s')
  131. )
  132. );
  133. return $classTemplate->render();
  134. }
  135. /**
  136. * Returns the methods of the class under test
  137. * that are called from the test methods.
  138. *
  139. * @return array
  140. */
  141. protected function findTestedMethods()
  142. {
  143. $setUpVariables = array();
  144. $testedMethods = array();
  145. $classes = PHPUnit_Util_File::getClassesInFile(
  146. $this->inSourceFile
  147. );
  148. $testMethods = $classes[$this->inClassName['fullyQualifiedClassName']]['methods'];
  149. unset($classes);
  150. foreach ($testMethods as $name => $testMethod) {
  151. if (strtolower($name) == 'setup') {
  152. $setUpVariables = $this->findVariablesThatReferenceClass(
  153. $testMethod['tokens']
  154. );
  155. break;
  156. }
  157. }
  158. foreach ($testMethods as $name => $testMethod) {
  159. $argVariables = array();
  160. if (strtolower($name) == 'setup') {
  161. continue;
  162. }
  163. $start = strpos($testMethod['signature'], '(') + 1;
  164. $end = strlen($testMethod['signature']) - $start - 1;
  165. $args = substr($testMethod['signature'], $start, $end);
  166. foreach (explode(',', $args) as $arg) {
  167. $arg = explode(' ', trim($arg));
  168. if (count($arg) == 2) {
  169. $type = $arg[0];
  170. $var = $arg[1];
  171. } else {
  172. $type = NULL;
  173. $var = $arg[0];
  174. }
  175. if ($type == $this->outClassName['fullyQualifiedClassName']) {
  176. $argVariables[] = $var;
  177. }
  178. }
  179. $variables = array_unique(
  180. array_merge(
  181. $setUpVariables,
  182. $argVariables,
  183. $this->findVariablesThatReferenceClass($testMethod['tokens'])
  184. )
  185. );
  186. foreach ($testMethod['tokens'] as $i => $token) {
  187. // Class::method()
  188. if (is_array($token) && $token[0] == T_DOUBLE_COLON &&
  189. is_array($testMethod['tokens'][$i-1]) &&
  190. $testMethod['tokens'][$i-1][0] == T_STRING &&
  191. $testMethod['tokens'][$i-1][1] == $this->outClassName['fullyQualifiedClassName'] &&
  192. is_array($testMethod['tokens'][$i+1]) &&
  193. $testMethod['tokens'][$i+1][0] == T_STRING &&
  194. $testMethod['tokens'][$i+2] == '(') {
  195. $testedMethods[] = $testMethod['tokens'][$i+1][1];
  196. }
  197. // $this->object->method()
  198. else if (is_array($token) && $token[0] == T_OBJECT_OPERATOR &&
  199. in_array($this->findVariableName($testMethod['tokens'], $i), $variables) &&
  200. is_array($testMethod['tokens'][$i+2]) &&
  201. $testMethod['tokens'][$i+2][0] == T_OBJECT_OPERATOR &&
  202. is_array($testMethod['tokens'][$i+3]) &&
  203. $testMethod['tokens'][$i+3][0] == T_STRING &&
  204. $testMethod['tokens'][$i+4] == '(') {
  205. $testedMethods[] = $testMethod['tokens'][$i+3][1];
  206. }
  207. // $object->method()
  208. else if (is_array($token) && $token[0] == T_OBJECT_OPERATOR &&
  209. in_array($this->findVariableName($testMethod['tokens'], $i), $variables) &&
  210. is_array($testMethod['tokens'][$i+1]) &&
  211. $testMethod['tokens'][$i+1][0] == T_STRING &&
  212. $testMethod['tokens'][$i+2] == '(') {
  213. $testedMethods[] = $testMethod['tokens'][$i+1][1];
  214. }
  215. }
  216. }
  217. $testedMethods = array_unique($testedMethods);
  218. sort($testedMethods);
  219. return $testedMethods;
  220. }
  221. /**
  222. * Returns the variables used in test methods
  223. * that reference the class under test.
  224. *
  225. * @param array $tokens
  226. * @return array
  227. */
  228. protected function findVariablesThatReferenceClass(array $tokens)
  229. {
  230. $inNew = FALSE;
  231. $variables = array();
  232. foreach ($tokens as $i => $token) {
  233. if (is_string($token)) {
  234. if (trim($token) == ';') {
  235. $inNew = FALSE;
  236. }
  237. continue;
  238. }
  239. list ($token, $value) = $token;
  240. switch ($token) {
  241. case T_NEW: {
  242. $inNew = TRUE;
  243. }
  244. break;
  245. case T_STRING: {
  246. if ($inNew) {
  247. if ($value == $this->outClassName['fullyQualifiedClassName']) {
  248. $variables[] = $this->findVariableName(
  249. $tokens, $i
  250. );
  251. }
  252. }
  253. $inNew = FALSE;
  254. }
  255. break;
  256. }
  257. }
  258. return $variables;
  259. }
  260. /**
  261. * Finds the variable name of the object for the method call
  262. * that is currently being processed.
  263. *
  264. * @param array $tokens
  265. * @param integer $start
  266. * @return mixed
  267. */
  268. protected function findVariableName(array $tokens, $start)
  269. {
  270. for ($i = $start - 1; $i >= 0; $i--) {
  271. if (is_array($tokens[$i]) && $tokens[$i][0] == T_VARIABLE) {
  272. $variable = $tokens[$i][1];
  273. if (is_array($tokens[$i+1]) &&
  274. $tokens[$i+1][0] == T_OBJECT_OPERATOR &&
  275. $tokens[$i+2] != '(' &&
  276. $tokens[$i+3] != '(') {
  277. $variable .= '->' . $tokens[$i+2][1];
  278. }
  279. return $variable;
  280. }
  281. }
  282. return FALSE;
  283. }
  284. }