]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - tests/PHPUnit/Util/Metrics/Class.php
Added unit tests.
[Github/sugarcrm.git] / tests / PHPUnit / Util / Metrics / Class.php
1 <?php
2 /**
3  * PHPUnit
4  *
5  * Copyright (c) 2002-2009, Sebastian Bergmann <sb@sebastian-bergmann.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  * @category   Testing
38  * @package    PHPUnit
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
42
43  * @link       http://www.phpunit.de/
44  * @since      File available since Release 3.2.0
45  */
46
47 require_once 'PHPUnit/Util/Class.php';
48 require_once 'PHPUnit/Util/Metrics.php';
49 require_once 'PHPUnit/Util/Filter.php';
50
51 PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT');
52
53 /**
54  * Class-Level Metrics.
55  *
56  * @category   Testing
57  * @package    PHPUnit
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.2.0
64  */
65 class PHPUnit_Util_Metrics_Class extends PHPUnit_Util_Metrics
66 {
67     protected $aif           = 0;
68     protected $ahf           = 0;
69     protected $ca            = 0;
70     protected $ce            = 0;
71     protected $coverage      = 0;
72     protected $dit           = 0;
73     protected $i             = 0;
74     protected $impl          = 0;
75     protected $loc           = 0;
76     protected $locExecutable = 0;
77     protected $locExecuted   = 0;
78     protected $mif           = 0;
79     protected $mhf           = 0;
80     protected $noc           = 0;
81     protected $pf            = 0;
82     protected $vars          = 0;
83     protected $varsNp        = 0;
84     protected $varsI         = 0;
85     protected $wmc           = 0;
86     protected $wmcNp         = 0;
87     protected $wmcI          = 0;
88
89     protected $project;
90     protected $package = '';
91     protected $class;
92     protected $methods = array();
93     protected $inheritedMethods = array();
94     protected $dependencies = array();
95     protected $publicMethods = 0;
96
97     protected static $cache = array();
98     protected static $nocCache = array();
99
100     /**
101      * Constructor.
102      *
103      * @param  ReflectionClass $class
104      * @param  array           $codeCoverage
105      */
106     protected function __construct(ReflectionClass $class, &$codeCoverage = array())
107     {
108         $this->class = $class;
109
110         $className = $class->getName();
111
112         $packageInformation = PHPUnit_Util_Class::getPackageInformation($className);
113
114         if (!empty($packageInformation['fullPackage'])) {
115             $this->package = $packageInformation['fullPackage'];
116         }
117
118         $this->setCoverage($codeCoverage);
119
120         $this->dit  = count(PHPUnit_Util_Class::getHierarchy($class->getName())) - 1;
121         $this->impl = count($class->getInterfaces());
122
123         foreach ($this->class->getMethods() as $method) {
124             if ($method->getDeclaringClass()->getName() == $className) {
125                 $this->methods[$method->getName()] = PHPUnit_Util_Metrics_Function::factory($method, $codeCoverage);
126             } else {
127                 $this->inheritedMethods[$method->getName()] = PHPUnit_Util_Metrics_Function::factory($method, $codeCoverage);
128             }
129         }
130
131         $this->calculateAttributeMetrics();
132         $this->calculateMethodMetrics();
133         $this->calculateNumberOfChildren();
134         $this->calculatePolymorphismFactor();
135         $this->calculateDependencies();
136     }
137
138     /**
139      * Factory.
140      *
141      * @param  ReflectionClass $class
142      * @param  array           $codeCoverage
143      * @return PHPUnit_Util_Metrics_Class
144      */
145     public static function factory(ReflectionClass $class, &$codeCoverage = array())
146     {
147         $className = $class->getName();
148
149         if (!isset(self::$cache[$className])) {
150             self::$cache[$className] = new PHPUnit_Util_Metrics_Class($class, $codeCoverage);
151         }
152
153         else if (!empty($codeCoverage) && self::$cache[$className]->getCoverage() == 0) {
154             self::$cache[$className]->setCoverage($codeCoverage);
155         }
156
157         return self::$cache[$className];
158     }
159
160     /**
161      * @param  array $codeCoverage
162      */
163     public function setCoverage(array &$codeCoverage)
164     {
165         if (!empty($codeCoverage)) {
166             $this->calculateCodeCoverage($codeCoverage);
167
168             foreach ($this->methods as $method) {
169                 $method->setCoverage($codeCoverage);
170             }
171         }
172     }
173
174     /**
175      * @param  PHPUnit_Util_Metrics_Project $project
176      */
177     public function setProject(PHPUnit_Util_Metrics_Project $project)
178     {
179         $this->project = $project;
180
181         $this->ca = 0;
182         $this->ce = 0;
183         $this->i  = 0;
184     }
185
186     /**
187      * Returns the class.
188      *
189      * @return ReflectionClass
190      */
191     public function getClass()
192     {
193         return $this->class;
194     }
195
196     /**
197      * Returns the package of this class.
198      *
199      * @return string
200      */
201     public function getPackage()
202     {
203         return $this->package;
204     }
205
206     /**
207      * Returns the methods of this class.
208      *
209      * @return array
210      */
211     public function getMethods()
212     {
213         return $this->methods;
214     }
215
216     /**
217      * Returns the names of the classes this class depends on.
218      *
219      * @return array
220      */
221     public function getDependencies()
222     {
223         return $this->dependencies;
224     }
225
226     /**
227      * Lines of Code (LOC).
228      *
229      * @return int
230      */
231     public function getLoc()
232     {
233         return $this->loc;
234     }
235
236     /**
237      * Executable Lines of Code (ELOC).
238      *
239      * @return int
240      */
241     public function getLocExecutable()
242     {
243         return $this->locExecutable;
244     }
245
246     /**
247      * Executed Lines of Code.
248      *
249      * @return int
250      */
251     public function getLocExecuted()
252     {
253         return $this->locExecuted;
254     }
255
256     /**
257      * Returns the Number of Public Methods of the class.
258      *
259      * @return integer
260      */
261     public function getPublicMethods()
262     {
263         return $this->publicMethods;
264     }
265
266     /**
267      * Returns the Attribute Inheritance Factor (AIF) for the class.
268      *
269      * @return integer
270      * @see    http://www.aivosto.com/project/help/pm-oo-mood.html
271      */
272     public function getAIF()
273     {
274         return $this->aif;
275     }
276
277     /**
278      * Returns the Attribute Hiding Factor (AHF) for the class.
279      *
280      * @return integer
281      * @see    http://www.aivosto.com/project/help/pm-oo-mood.html
282      */
283     public function getAHF()
284     {
285         return $this->ahf;
286     }
287
288     /**
289      * Returns the Afferent Couplings (Ca) for the class.
290      *
291      * The number of other classes that depend upon a class is an indicator of
292      * the class' responsibility.
293      *
294      * @return integer
295      */
296     public function getCa()
297     {
298         $this->calculateDependencyMetrics();
299
300         return $this->ca;
301     }
302
303     /**
304      * Returns the Efferent Couplings (Ce) for the class.
305      *
306      * The number of other classes that the class depends upon is an indicator
307      * of the class' independence.
308      *
309      * @return integer
310      */
311     public function getCe()
312     {
313         $this->calculateDependencyMetrics();
314
315         return $this->ce;
316     }
317
318     /**
319      * Returns the Class Size (CSZ) of the class.
320      *
321      * @return integer
322      * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
323      */
324     public function getCSZ()
325     {
326         return count($this->methods) + $this->vars;
327     }
328
329     /**
330      * Returns the Class Interface Size (CIS) of the class.
331      *
332      * @return integer
333      * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
334      */
335     public function getCIS()
336     {
337         return $this->publicMethods + $this->varsNp;
338     }
339
340     /**
341      * Returns the Code Coverage for the class.
342      *
343      * @return float
344      */
345     public function getCoverage()
346     {
347         return $this->coverage;
348     }
349
350     /**
351      * Returns the Depth of Inheritance Tree (DIT) for the class.
352      *
353      * @return integer
354      * @see    http://www.aivosto.com/project/help/pm-oo-ck.html
355      */
356     public function getDIT()
357     {
358         return $this->dit;
359     }
360
361     /**
362      * Returns the Instability (I) for the class.
363      *
364      * The ratio of efferent coupling (Ce) to total coupling (Ce + Ca) such that
365      * I = Ce / (Ce + Ca). This metric is an indicator of the class' resilience
366      * to change.
367      *
368      * The range for this metric is 0 to 1, with I=0 indicating a completely
369      * stable class and I=1 indicating a completely instable class.
370      *
371      * @return float
372      */
373     public function getI()
374     {
375         $this->calculateDependencyMetrics();
376
377         return $this->i;
378     }
379
380     /**
381      * Returns the Number of Interfaces Implemented by the class (IMPL).
382      *
383      * @return integer
384      * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
385      */
386     public function getIMPL()
387     {
388         return $this->impl;
389     }
390
391     /**
392      * Returns the Method Inheritance Factor (MIF) for the class.
393      *
394      * @return float
395      * @see    http://www.aivosto.com/project/help/pm-oo-mood.html
396      */
397     public function getMIF()
398     {
399         return $this->mif;
400     }
401
402     /**
403      * Returns the Method Hiding Factor (MHF) for the class.
404      *
405      * @return float
406      * @see    http://www.aivosto.com/project/help/pm-oo-mood.html
407      */
408     public function getMHF()
409     {
410         return $this->mhf;
411     }
412
413     /**
414      * Returns the Number of Children (NOC) for the class.
415      *
416      * @return integer
417      * @see    http://www.aivosto.com/project/help/pm-oo-ck.html
418      */
419     public function getNOC()
420     {
421         return $this->noc;
422     }
423
424     /**
425      * Returns the Polymorphism Factor (PF) for the class.
426      *
427      * @return float
428      * @see    http://www.aivosto.com/project/help/pm-oo-mood.html
429      */
430     public function getPF()
431     {
432         return $this->pf;
433     }
434
435     /**
436      * Returns the Number of Variables (VARS) defined by the class.
437      *
438      * @return integer
439      * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
440      */
441     public function getVARS()
442     {
443         return $this->vars;
444     }
445
446     /**
447      * Returns the Number of Non-Private Variables (VARSnp) defined by the class.
448      *
449      * @return integer
450      * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
451      */
452     public function getVARSnp()
453     {
454         return $this->varsNp;
455     }
456
457     /**
458      * Returns the Number of Variables (VARSi) defined and inherited by the class.
459      *
460      * @return integer
461      * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
462      */
463     public function getVARSi()
464     {
465         return $this->varsI;
466     }
467
468     /**
469      * Returns the Weighted Methods Per Class (WMC) for the class.
470      *
471      * @return integer
472      * @see    http://www.aivosto.com/project/help/pm-oo-ck.html
473      */
474     public function getWMC()
475     {
476         return $this->wmc;
477     }
478
479     /**
480      * Returns the Weighted Non-Private Methods Per Class (WMCnp) for the class.
481      *
482      * @return integer
483      * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
484      */
485     public function getWMCnp()
486     {
487         return $this->wmcNp;
488     }
489
490     /**
491      * Returns the Weighted Inherited Methods Per Class (WMCi) for the class.
492      *
493      * @return integer
494      * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
495      */
496     public function getWMCi()
497     {
498         return $this->wmcI;
499     }
500
501     /**
502      * Calculates the Attribute Inheritance Factor (AIF) and
503      * Attribute Hiding Factor (AHF) metrics for the class.
504      *
505      */
506     protected function calculateAttributeMetrics()
507     {
508         $attributes          = 0;
509         $hiddenAttributes    = 0;
510         $inheritedAttributes = 0;
511
512         foreach ($this->class->getProperties() as $attribute) {
513             if ($attribute->isPublic()) {
514                 $this->varsNp++;
515             } else {
516                 $hiddenAttributes++;
517             }
518
519             if ($attribute->getDeclaringClass()->getName() == $this->class->getName()) {
520                 $this->vars++;
521             } else {
522                 $inheritedAttributes++;
523             }
524
525             $this->varsI++;
526             $attributes++;
527         }
528
529         if ($attributes > 0) {
530             $this->aif = (100 * $inheritedAttributes) / $attributes;
531             $this->ahf = (100 * $hiddenAttributes) / $attributes;
532         }
533     }
534
535     /**
536      * Calculates the Method Inheritance Factor (MIF)
537      * Method Hiding Factor (MHF), Weighted Methods Per Class (WMC),
538      * Weighted Non-Private Methods Per Class (WMCnp), and
539      * Weighted Inherited Methods Per Class (WMCi) metrics for the class.
540      *
541      */
542     protected function calculateMethodMetrics()
543     {
544         $numMethods       = 0;
545         $hiddenMethods    = 0;
546         $inheritedMethods = 0;
547
548         $methods = array_merge($this->methods, $this->inheritedMethods);
549
550         foreach ($methods as $method) {
551             $ccn = $method->getCCN();
552
553             if ($method->getMethod()->getDeclaringClass()->getName() == $this->class->getName()) {
554                 $this->wmc += $ccn;
555
556                 if ($method->getMethod()->isPublic()) {
557                     $this->publicMethods++;
558                     $this->wmcNp += $ccn;
559                 }
560             } else {
561                 $inheritedMethods++;
562             }
563
564             if (!$method->getMethod()->isPublic()) {
565                 $hiddenMethods++;
566             }
567
568             $this->wmcI += $ccn;
569             $numMethods++;
570         }
571
572         if ($numMethods > 0) {
573             $this->mif = (100 * $inheritedMethods) / $numMethods;
574             $this->mhf = (100 * $hiddenMethods) / $numMethods;
575         }
576     }
577
578     /**
579      * Calculates the Number of Children (NOC) metric for the class.
580      *
581      */
582     protected function calculateNumberOfChildren()
583     {
584         $className = $this->class->getName();
585
586         if (!isset(self::$nocCache[$className])) {
587             self::$nocCache = array();
588         }
589
590         if (empty(self::$nocCache)) {
591             foreach (get_declared_classes() as $_className) {
592                 $class  = new ReflectionClass($_className);
593                 $parent = $class->getParentClass();
594
595                 if ($parent !== FALSE) {
596                     $parentName = $parent->getName();
597
598                     if (isset(self::$nocCache[$parentName])) {
599                         self::$nocCache[$parentName]++;
600                     } else {
601                         self::$nocCache[$parentName] = 1;
602                     }
603                 }
604             }
605         }
606
607         if (isset(self::$nocCache[$className])) {
608             $this->noc = self::$nocCache[$className];
609         }
610     }
611
612     /**
613      * Calculates the Polymorphism Factor (PF) metric for the class.
614      *
615      * @param  ReflectionClass $class
616      */
617     protected function calculatePolymorphismFactor()
618     {
619         $parentClass = $this->class->getParentClass();
620
621         if ($parentClass !== FALSE) {
622             $overridableMethods = array();
623
624             foreach ($parentClass->getMethods() as $method) {
625                 if (!$method->isPrivate() && !$method->isFinal() && !$method->isAbstract()) {
626                     $overridableMethods[] = $method->getName();
627                 }
628             }
629
630             if (!empty($overridableMethods)) {
631                 $overriddenMethods = 0;
632
633                 foreach ($this->class->getMethods() as $method) {
634                     if ($method->getDeclaringClass()->getName() == $this->class->getName()) {
635                         $methodName = $method->getName();
636
637                         if (in_array($methodName, $overridableMethods)) {
638                             $overriddenMethods++;
639                         }
640                     }
641                 }
642
643                 $this->pf = (100 * $overriddenMethods) / count($overridableMethods);
644             }
645         }
646     }
647
648     /**
649      * Calculates the Code Coverage for the class.
650      *
651      * @param  array $codeCoverage
652      */
653     protected function calculateCodeCoverage(&$codeCoverage)
654     {
655         $statistics = PHPUnit_Util_CodeCoverage::getStatistics(
656           $codeCoverage,
657           $this->class->getFileName(),
658           $this->class->getStartLine(),
659           $this->class->getEndLine()
660         );
661
662         $this->coverage      = $statistics['coverage'];
663         $this->loc           = $statistics['loc'];
664         $this->locExecutable = $statistics['locExecutable'];
665         $this->locExecuted   = $statistics['locExecuted'];
666     }
667
668     /**
669      * Calculates the dependencies for this class.
670      *
671      */
672     protected function calculateDependencies()
673     {
674         $parent = $this->class->getParentClass();
675
676         if ($parent && $parent->isUserDefined() && !in_array($parent->getName(), $this->dependencies)) {
677             $this->dependencies[] = $parent->getName();
678         }
679
680         $interfaces = $this->class->getInterfaces();
681
682         foreach ($interfaces as $interface) {
683             if ($interface->isUserDefined() && !in_array($interface->getName(), $this->dependencies)) {
684                 $this->dependencies[] = $interface->getName();
685             }
686         }
687
688         $methods = array_merge($this->methods, $this->inheritedMethods);
689
690         foreach ($methods as $method) {
691             foreach ($method->getDependencies() as $dependency) {
692                 if (!in_array($dependency, $this->dependencies)) {
693                     $this->dependencies[] = $dependency;
694                 }
695             }
696         }
697     }
698
699     /**
700      * Calculates the dependency-based metrics for this class.
701      *
702      */
703     protected function calculateDependencyMetrics()
704     {
705         if ($this->ca == 0 && $this->ce == 0 && $this->i == 0) {
706             $className    = $this->class->getName();
707             $dependencies = $this->project->getDependencies();
708
709             foreach ($dependencies[$className] as $dependency) {
710                 if ($dependency > 0) {
711                     $this->ce++;
712                 }
713             }
714
715             unset($dependencies[$className]);
716
717             foreach ($dependencies as $_className => $_dependencies) {
718                 if ($_dependencies[$className] > 0) {
719                     $this->ca++;
720                 }
721             }
722
723             $sum = $this->ce + $this->ca;
724
725             if ($sum > 0) {
726                 $this->i = $this->ce / $sum;
727             }
728         }
729     }
730 }
731 ?>