]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - tests/PHPUnit/PHPUnit/Util/Skeleton/Class.php
Release 6.2.1
[Github/sugarcrm.git] / tests / PHPUnit / PHPUnit / Util / Skeleton / Class.php
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
46 require_once 'Text/Template.php';
47
48 /**
49  * Generator for class skeletons from test classes.
50  *
51  * @package    PHPUnit
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.14
57  * @link       http://www.phpunit.de/
58  * @since      Class available since Release 3.3.0
59  */
60 class PHPUnit_Util_Skeleton_Class extends PHPUnit_Util_Skeleton
61 {
62     /**
63      * Constructor.
64      *
65      * @param string $inClassName
66      * @param string $inSourceFile
67      * @param string $outClassName
68      * @param string $outSourceFile
69      * @throws RuntimeException
70      */
71     public function __construct($inClassName, $inSourceFile = '', $outClassName = '', $outSourceFile = '')
72     {
73         if (empty($inSourceFile)) {
74             $inSourceFile = $inClassName . '.php';
75         }
76
77         if (!is_file($inSourceFile)) {
78             throw new PHPUnit_Framework_Exception(
79               sprintf(
80                 '"%s" could not be opened.',
81
82                 $inSourceFile
83               )
84             );
85         }
86
87         if (empty($outClassName)) {
88             $outClassName = substr($inClassName, 0, strlen($inClassName) - 4);
89         }
90
91         if (empty($outSourceFile)) {
92             $outSourceFile = dirname($inSourceFile) . DIRECTORY_SEPARATOR .
93                              $outClassName . '.php';
94         }
95
96         parent::__construct(
97           $inClassName, $inSourceFile, $outClassName, $outSourceFile
98         );
99     }
100
101     /**
102      * Generates the class' source.
103      *
104      * @return mixed
105      */
106     public function generate()
107     {
108         $methods = '';
109
110         foreach ($this->findTestedMethods() as $method) {
111             $methodTemplate = new Text_Template(
112               sprintf(
113                 '%s%sTemplate%sMethod.tpl',
114
115                 dirname(__FILE__),
116                 DIRECTORY_SEPARATOR,
117                 DIRECTORY_SEPARATOR
118               )
119             );
120
121             $methodTemplate->setVar(
122               array(
123                 'methodName' => $method,
124               )
125             );
126
127             $methods .= $methodTemplate->render();
128         }
129
130         $classTemplate = new Text_Template(
131           sprintf(
132             '%s%sTemplate%sClass.tpl',
133
134             dirname(__FILE__),
135             DIRECTORY_SEPARATOR,
136             DIRECTORY_SEPARATOR
137           )
138         );
139
140         $classTemplate->setVar(
141           array(
142             'className' => $this->outClassName['fullyQualifiedClassName'],
143             'methods'   => $methods,
144             'date'      => date('Y-m-d'),
145             'time'      => date('H:i:s')
146           )
147         );
148
149         return $classTemplate->render();
150     }
151
152     /**
153      * Returns the methods of the class under test
154      * that are called from the test methods.
155      *
156      * @return array
157      */
158     protected function findTestedMethods()
159     {
160         $setUpVariables = array();
161         $testedMethods  = array();
162         $classes        = PHPUnit_Util_File::getClassesInFile(
163                             $this->inSourceFile
164                           );
165         $testMethods    = $classes[$this->inClassName['fullyQualifiedClassName']]['methods'];
166         unset($classes);
167
168         foreach ($testMethods as $name => $testMethod) {
169             if (strtolower($name) == 'setup') {
170                 $setUpVariables = $this->findVariablesThatReferenceClass(
171                   $testMethod['tokens']
172                 );
173
174                 break;
175             }
176         }
177
178         foreach ($testMethods as $name => $testMethod) {
179             $argVariables = array();
180
181             if (strtolower($name) == 'setup') {
182                 continue;
183             }
184
185             $start = strpos($testMethod['signature'], '(') + 1;
186             $end   = strlen($testMethod['signature']) - $start - 1;
187             $args  = substr($testMethod['signature'], $start, $end);
188
189             foreach (explode(',', $args) as $arg) {
190                 $arg = explode(' ', trim($arg));
191
192                 if (count($arg) == 2) {
193                     $type = $arg[0];
194                     $var  = $arg[1];
195                 } else {
196                     $type = NULL;
197                     $var  = $arg[0];
198                 }
199
200                 if ($type == $this->outClassName['fullyQualifiedClassName']) {
201                     $argVariables[] = $var;
202                 }
203             }
204
205             $variables = array_unique(
206               array_merge(
207                 $setUpVariables,
208                 $argVariables,
209                 $this->findVariablesThatReferenceClass($testMethod['tokens'])
210               )
211             );
212
213             foreach ($testMethod['tokens'] as $i => $token) {
214                 // Class::method()
215                 if (is_array($token) && $token[0] == T_DOUBLE_COLON &&
216                     is_array($testMethod['tokens'][$i-1]) &&
217                     $testMethod['tokens'][$i-1][0] == T_STRING &&
218                     $testMethod['tokens'][$i-1][1] == $this->outClassName['fullyQualifiedClassName'] &&
219                     is_array($testMethod['tokens'][$i+1]) &&
220                     $testMethod['tokens'][$i+1][0] == T_STRING &&
221                     $testMethod['tokens'][$i+2] == '(') {
222                     $testedMethods[] = $testMethod['tokens'][$i+1][1];
223                 }
224
225                 // $this->object->method()
226                 else if (is_array($token) && $token[0] == T_OBJECT_OPERATOR &&
227                     in_array($this->findVariableName($testMethod['tokens'], $i), $variables) &&
228                     is_array($testMethod['tokens'][$i+2]) &&
229                     $testMethod['tokens'][$i+2][0] == T_OBJECT_OPERATOR &&
230                     is_array($testMethod['tokens'][$i+3]) &&
231                     $testMethod['tokens'][$i+3][0] == T_STRING &&
232                     $testMethod['tokens'][$i+4] == '(') {
233                     $testedMethods[] = $testMethod['tokens'][$i+3][1];
234                 }
235
236                 // $object->method()
237                 else if (is_array($token) && $token[0] == T_OBJECT_OPERATOR &&
238                     in_array($this->findVariableName($testMethod['tokens'], $i), $variables) &&
239                     is_array($testMethod['tokens'][$i+1]) &&
240                     $testMethod['tokens'][$i+1][0] == T_STRING &&
241                     $testMethod['tokens'][$i+2] == '(') {
242                     $testedMethods[] = $testMethod['tokens'][$i+1][1];
243                 }
244             }
245         }
246
247         $testedMethods = array_unique($testedMethods);
248         sort($testedMethods);
249
250         return $testedMethods;
251     }
252
253     /**
254      * Returns the variables used in test methods
255      * that reference the class under test.
256      *
257      * @param  array $tokens
258      * @return array
259      */
260     protected function findVariablesThatReferenceClass(array $tokens)
261     {
262         $inNew     = FALSE;
263         $variables = array();
264
265         foreach ($tokens as $i => $token) {
266             if (is_string($token)) {
267                 if (trim($token) == ';') {
268                     $inNew = FALSE;
269                 }
270
271                 continue;
272             }
273
274             list ($token, $value) = $token;
275
276             switch ($token) {
277                 case T_NEW: {
278                     $inNew = TRUE;
279                 }
280                 break;
281
282                 case T_STRING: {
283                     if ($inNew) {
284                         if ($value == $this->outClassName['fullyQualifiedClassName']) {
285                             $variables[] = $this->findVariableName(
286                               $tokens, $i
287                             );
288                         }
289                     }
290
291                     $inNew = FALSE;
292                 }
293                 break;
294             }
295         }
296
297         return $variables;
298     }
299
300     /**
301      * Finds the variable name of the object for the method call
302      * that is currently being processed.
303      *
304      * @param  array   $tokens
305      * @param  integer $start
306      * @return mixed
307      */
308     protected function findVariableName(array $tokens, $start)
309     {
310         for ($i = $start - 1; $i >= 0; $i--) {
311             if (is_array($tokens[$i]) && $tokens[$i][0] == T_VARIABLE) {
312                 $variable = $tokens[$i][1];
313
314                 if (is_array($tokens[$i+1]) &&
315                     $tokens[$i+1][0] == T_OBJECT_OPERATOR &&
316                     $tokens[$i+2] != '(' &&
317                     $tokens[$i+3] != '(') {
318                     $variable .= '->' . $tokens[$i+2][1];
319                 }
320
321                 return $variable;
322             }
323         }
324
325         return FALSE;
326     }
327 }