@@ -407,7 +407,7 @@ protected function applyCoversAnnotationFilter(&$data, $id)
407407 {
408408 if ($ id instanceof PHPUnit_Framework_TestCase) {
409409 $ testClassName = get_class ($ id );
410- $ linesToBeCovered = PHP_CodeCoverage_Util:: getLinesToBeCovered (
410+ $ linesToBeCovered = $ this -> getLinesToBeCovered (
411411 $ testClassName , $ id ->getName ()
412412 );
413413
@@ -565,4 +565,231 @@ protected function processUncoveredFileFromWhitelist($uncoveredFile, array &$dat
565565 }
566566 }
567567 }
568+
569+ /**
570+ * Returns the files and lines a test method wants to cover.
571+ *
572+ * @param string $className
573+ * @param string $methodName
574+ * @return array
575+ * @since Method available since Release 1.2.0
576+ */
577+ protected function getLinesToBeCovered ($ className , $ methodName )
578+ {
579+ $ codeToCoverList = array ();
580+ $ result = array ();
581+
582+ // @codeCoverageIgnoreStart
583+ if (($ pos = strpos ($ methodName , ' ' )) !== FALSE ) {
584+ $ methodName = substr ($ methodName , 0 , $ pos );
585+ }
586+ // @codeCoverageIgnoreEnd
587+
588+ $ class = new ReflectionClass ($ className );
589+
590+ try {
591+ $ method = new ReflectionMethod ($ className , $ methodName );
592+ }
593+
594+ catch (ReflectionException $ e ) {
595+ return array ();
596+ }
597+
598+ $ docComment = $ class ->getDocComment () . $ method ->getDocComment ();
599+
600+ $ templateMethods = array (
601+ 'setUp ' , 'assertPreConditions ' , 'assertPostConditions ' , 'tearDown '
602+ );
603+
604+ foreach ($ templateMethods as $ templateMethod ) {
605+ if ($ class ->hasMethod ($ templateMethod )) {
606+ $ reflector = $ class ->getMethod ($ templateMethod );
607+ $ docComment .= $ reflector ->getDocComment ();
608+ unset($ reflector );
609+ }
610+ }
611+
612+ if (strpos ($ docComment , '@coversNothing ' ) !== FALSE ) {
613+ return $ result ;
614+ }
615+
616+ $ classShortcut = preg_match_all (
617+ '(@coversDefaultClass\s+(?P<coveredClass>.*?)\s*$)m ' ,
618+ $ class ->getDocComment (),
619+ $ matches
620+ );
621+
622+ if ($ classShortcut ) {
623+ if ($ classShortcut > 1 ) {
624+ throw new PHP_CodeCoverage_Exception (
625+ sprintf (
626+ 'More than one @coversClass annotation in class or interface "%s". ' ,
627+ $ className
628+ )
629+ );
630+ }
631+
632+ $ classShortcut = $ matches ['coveredClass ' ][0 ];
633+ }
634+
635+ $ match = preg_match_all (
636+ '(@covers\s+(?P<coveredElement>.*?)\s*$)m ' ,
637+ $ docComment ,
638+ $ matches
639+ );
640+
641+ if ($ match ) {
642+ foreach ($ matches ['coveredElement ' ] as $ coveredElement ) {
643+ if ($ classShortcut && strncmp ($ coveredElement , ':: ' , 2 ) === 0 ) {
644+ $ coveredElement = $ classShortcut . $ coveredElement ;
645+ }
646+
647+ $ codeToCoverList = array_merge (
648+ $ codeToCoverList ,
649+ $ this ->resolveCoversToReflectionObjects ($ coveredElement )
650+ );
651+ }
652+
653+ foreach ($ codeToCoverList as $ codeToCover ) {
654+ $ fileName = $ codeToCover ->getFileName ();
655+
656+ if (!isset ($ result [$ fileName ])) {
657+ $ result [$ fileName ] = array ();
658+ }
659+
660+ $ result [$ fileName ] = array_unique (
661+ array_merge (
662+ $ result [$ fileName ],
663+ range (
664+ $ codeToCover ->getStartLine (), $ codeToCover ->getEndLine ()
665+ )
666+ )
667+ );
668+ }
669+ }
670+
671+ return $ result ;
672+ }
673+
674+ /**
675+ * @param string $coveredElement
676+ * @return array
677+ * @since Method available since Release 1.2.0
678+ */
679+ protected function resolveCoversToReflectionObjects ($ coveredElement )
680+ {
681+ $ codeToCoverList = array ();
682+
683+ if (strpos ($ coveredElement , ':: ' ) !== FALSE ) {
684+ list ($ className , $ methodName ) = explode (':: ' , $ coveredElement );
685+
686+ if (isset ($ methodName [0 ]) && $ methodName [0 ] == '< ' ) {
687+ $ classes = array ($ className );
688+
689+ foreach ($ classes as $ className ) {
690+ if (!class_exists ($ className ) &&
691+ !interface_exists ($ className )) {
692+ throw new PHP_CodeCoverage_Exception (
693+ sprintf (
694+ 'Trying to @cover not existing class or ' .
695+ 'interface "%s". ' ,
696+ $ className
697+ )
698+ );
699+ }
700+
701+ $ class = new ReflectionClass ($ className );
702+ $ methods = $ class ->getMethods ();
703+ $ inverse = isset ($ methodName [1 ]) && $ methodName [1 ] == '! ' ;
704+
705+ if (strpos ($ methodName , 'protected ' )) {
706+ $ visibility = 'isProtected ' ;
707+ }
708+
709+ else if (strpos ($ methodName , 'private ' )) {
710+ $ visibility = 'isPrivate ' ;
711+ }
712+
713+ else if (strpos ($ methodName , 'public ' )) {
714+ $ visibility = 'isPublic ' ;
715+ }
716+
717+ foreach ($ methods as $ method ) {
718+ if ($ inverse && !$ method ->$ visibility ()) {
719+ $ codeToCoverList [] = $ method ;
720+ }
721+
722+ else if (!$ inverse && $ method ->$ visibility ()) {
723+ $ codeToCoverList [] = $ method ;
724+ }
725+ }
726+ }
727+ } else {
728+ $ classes = array ($ className );
729+
730+ foreach ($ classes as $ className ) {
731+ if ($ className == '' && function_exists ($ methodName )) {
732+ $ codeToCoverList [] = new ReflectionFunction (
733+ $ methodName
734+ );
735+ } else {
736+ if (!((class_exists ($ className ) ||
737+ interface_exists ($ className ) ||
738+ trait_exists ($ className )) &&
739+ method_exists ($ className , $ methodName ))) {
740+ throw new PHP_CodeCoverage_Exception (
741+ sprintf (
742+ 'Trying to @cover not existing method "%s::%s". ' ,
743+ $ className ,
744+ $ methodName
745+ )
746+ );
747+ }
748+
749+ $ codeToCoverList [] = new ReflectionMethod (
750+ $ className , $ methodName
751+ );
752+ }
753+ }
754+ }
755+ } else {
756+ $ extended = FALSE ;
757+
758+ if (strpos ($ coveredElement , '<extended> ' ) !== FALSE ) {
759+ $ coveredElement = str_replace (
760+ '<extended> ' , '' , $ coveredElement
761+ );
762+
763+ $ extended = TRUE ;
764+ }
765+
766+ $ classes = array ($ coveredElement );
767+
768+ if ($ extended ) {
769+ $ classes = array_merge (
770+ $ classes ,
771+ class_implements ($ coveredElement ),
772+ class_parents ($ coveredElement )
773+ );
774+ }
775+
776+ foreach ($ classes as $ className ) {
777+ if (!class_exists ($ className ) &&
778+ !interface_exists ($ className ) &&
779+ !trait_exists ($ className )) {
780+ throw new PHP_CodeCoverage_Exception (
781+ sprintf (
782+ 'Trying to @cover not existing class or ' .
783+ 'interface "%s". ' ,
784+ $ className
785+ )
786+ );
787+ }
788+
789+ $ codeToCoverList [] = new ReflectionClass ($ className );
790+ }
791+ }
792+
793+ return $ codeToCoverList ;
794+ }
568795}
0 commit comments