@@ -234,19 +234,26 @@ public function start($id, $clear = FALSE)
234234 * Stop collection of code coverage information.
235235 *
236236 * @param boolean $append
237+ * @param mixed $linesToBeCovered
237238 * @return array
238239 * @throws PHP_CodeCoverage_Exception
239240 */
240- public function stop ($ append = TRUE )
241+ public function stop ($ append = TRUE , $ linesToBeCovered = array () )
241242 {
242243 if (!is_bool ($ append )) {
243244 throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory (
244245 1 , 'boolean '
245246 );
246247 }
247248
249+ if (!is_array ($ linesToBeCovered ) && $ linesToBeCovered !== FALSE ) {
250+ throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory (
251+ 2 , 'array or false '
252+ );
253+ }
254+
248255 $ data = $ this ->driver ->stop ();
249- $ this ->append ($ data , NULL , $ append );
256+ $ this ->append ($ data , NULL , $ append, $ linesToBeCovered );
250257
251258 $ this ->currentId = NULL ;
252259
@@ -259,8 +266,9 @@ public function stop($append = TRUE)
259266 * @param array $data
260267 * @param mixed $id
261268 * @param boolean $append
269+ * @param mixed $linesToBeCovered
262270 */
263- public function append (array $ data , $ id = NULL , $ append = TRUE )
271+ public function append (array $ data , $ id = NULL , $ append = TRUE , $ linesToBeCovered = array () )
264272 {
265273 if ($ id === NULL ) {
266274 $ id = $ this ->currentId ;
@@ -279,7 +287,7 @@ public function append(array $data, $id = NULL, $append = TRUE)
279287 }
280288
281289 if ($ id != 'UNCOVERED_FILES_FROM_WHITELIST ' ) {
282- $ this ->applyCoversAnnotationFilter ($ data , $ id );
290+ $ this ->applyCoversAnnotationFilter ($ data , $ id, $ linesToBeCovered );
283291 }
284292
285293 if (empty ($ data )) {
@@ -450,39 +458,16 @@ public function setProcessUncoveredFilesFromWhitelist($flag)
450458 *
451459 * @param array $data
452460 * @param mixed $id
461+ * @param mixed $linesToBeCovered
453462 * @throws PHP_CodeCoverage_Exception_UnintentionallyCoveredCode
454463 */
455- protected function applyCoversAnnotationFilter (&$ data , $ id )
464+ protected function applyCoversAnnotationFilter (&$ data , $ id, $ linesToBeCovered = array () )
456465 {
457466 $ unintentionallyCoveredCode = FALSE ;
458467
459- if ($ id instanceof PHPUnit_Framework_TestCase) {
460- $ testClassName = get_class ($ id );
461- $ linesToBeCovered = $ this ->getLinesToBeCovered (
462- $ testClassName , $ id ->getName ()
463- );
464-
465- if ($ linesToBeCovered === FALSE ) {
466- $ data = array ();
467- return ;
468- }
469-
470- if ($ this ->mapTestClassNameToCoveredClassName &&
471- empty ($ linesToBeCovered )) {
472- $ testedClass = substr ($ testClassName , 0 , -4 );
473-
474- if (class_exists ($ testedClass )) {
475- $ class = new ReflectionClass ($ testedClass );
476-
477- $ linesToBeCovered = array (
478- $ class ->getFileName () => range (
479- $ class ->getStartLine (), $ class ->getEndLine ()
480- )
481- );
482- }
483- }
484- } else {
485- $ linesToBeCovered = array ();
468+ if ($ linesToBeCovered === FALSE ) {
469+ $ data = array ();
470+ return ;
486471 }
487472
488473 if (!empty ($ linesToBeCovered )) {
@@ -626,233 +611,6 @@ protected function processUncoveredFileFromWhitelist($uncoveredFile, array &$dat
626611 }
627612 }
628613
629- /**
630- * Returns the files and lines a test method wants to cover.
631- *
632- * @param string $className
633- * @param string $methodName
634- * @return array
635- * @since Method available since Release 1.2.0
636- */
637- protected function getLinesToBeCovered ($ className , $ methodName )
638- {
639- $ codeToCoverList = array ();
640- $ result = array ();
641-
642- // @codeCoverageIgnoreStart
643- if (($ pos = strpos ($ methodName , ' ' )) !== FALSE ) {
644- $ methodName = substr ($ methodName , 0 , $ pos );
645- }
646- // @codeCoverageIgnoreEnd
647-
648- $ class = new ReflectionClass ($ className );
649-
650- try {
651- $ method = new ReflectionMethod ($ className , $ methodName );
652- }
653-
654- catch (ReflectionException $ e ) {
655- return array ();
656- }
657-
658- $ docComment = substr ($ class ->getDocComment (), 3 , -2 ) . PHP_EOL . substr ($ method ->getDocComment (), 3 , -2 );
659-
660- $ templateMethods = array (
661- 'setUp ' , 'assertPreConditions ' , 'assertPostConditions ' , 'tearDown '
662- );
663-
664- foreach ($ templateMethods as $ templateMethod ) {
665- if ($ class ->hasMethod ($ templateMethod )) {
666- $ reflector = $ class ->getMethod ($ templateMethod );
667- $ docComment .= PHP_EOL . substr ($ reflector ->getDocComment (), 3 , -2 );
668- unset($ reflector );
669- }
670- }
671-
672- if (strpos ($ docComment , '@coversNothing ' ) !== FALSE ) {
673- return FALSE ;
674- }
675-
676- $ classShortcut = preg_match_all (
677- '(@coversDefaultClass\s+(?P<coveredClass>[^\s]++)\s*$)m ' ,
678- $ class ->getDocComment (),
679- $ matches
680- );
681-
682- if ($ classShortcut ) {
683- if ($ classShortcut > 1 ) {
684- throw new PHP_CodeCoverage_Exception (
685- sprintf (
686- 'More than one @coversClass annotation in class or interface "%s". ' ,
687- $ className
688- )
689- );
690- }
691-
692- $ classShortcut = $ matches ['coveredClass ' ][0 ];
693- }
694-
695- $ match = preg_match_all (
696- '(@covers\s+(?P<coveredElement>[^\s()]++)[\s()]*$)m ' ,
697- $ docComment ,
698- $ matches
699- );
700-
701- if ($ match ) {
702- foreach ($ matches ['coveredElement ' ] as $ coveredElement ) {
703- if ($ classShortcut && strncmp ($ coveredElement , ':: ' , 2 ) === 0 ) {
704- $ coveredElement = $ classShortcut . $ coveredElement ;
705- }
706-
707- $ codeToCoverList = array_merge (
708- $ codeToCoverList ,
709- $ this ->resolveCoversToReflectionObjects ($ coveredElement )
710- );
711- }
712-
713- foreach ($ codeToCoverList as $ codeToCover ) {
714- $ fileName = $ codeToCover ->getFileName ();
715-
716- if (!isset ($ result [$ fileName ])) {
717- $ result [$ fileName ] = array ();
718- }
719-
720- $ result [$ fileName ] = array_unique (
721- array_merge (
722- $ result [$ fileName ],
723- range (
724- $ codeToCover ->getStartLine (), $ codeToCover ->getEndLine ()
725- )
726- )
727- );
728- }
729- }
730-
731- return $ result ;
732- }
733-
734- /**
735- * @param string $coveredElement
736- * @return array
737- * @since Method available since Release 1.2.0
738- */
739- protected function resolveCoversToReflectionObjects ($ coveredElement )
740- {
741- $ codeToCoverList = array ();
742-
743- if (strpos ($ coveredElement , ':: ' ) !== FALSE ) {
744- list ($ className , $ methodName ) = explode (':: ' , $ coveredElement );
745-
746- if (isset ($ methodName [0 ]) && $ methodName [0 ] == '< ' ) {
747- $ classes = array ($ className );
748-
749- foreach ($ classes as $ className ) {
750- if (!class_exists ($ className ) &&
751- !interface_exists ($ className )) {
752- throw new PHP_CodeCoverage_Exception_InvalidCoversTarget (
753- sprintf (
754- 'Trying to @cover not existing class or ' .
755- 'interface "%s". ' ,
756- $ className
757- )
758- );
759- }
760-
761- $ class = new ReflectionClass ($ className );
762- $ methods = $ class ->getMethods ();
763- $ inverse = isset ($ methodName [1 ]) && $ methodName [1 ] == '! ' ;
764-
765- if (strpos ($ methodName , 'protected ' )) {
766- $ visibility = 'isProtected ' ;
767- }
768-
769- else if (strpos ($ methodName , 'private ' )) {
770- $ visibility = 'isPrivate ' ;
771- }
772-
773- else if (strpos ($ methodName , 'public ' )) {
774- $ visibility = 'isPublic ' ;
775- }
776-
777- foreach ($ methods as $ method ) {
778- if ($ inverse && !$ method ->$ visibility ()) {
779- $ codeToCoverList [] = $ method ;
780- }
781-
782- else if (!$ inverse && $ method ->$ visibility ()) {
783- $ codeToCoverList [] = $ method ;
784- }
785- }
786- }
787- } else {
788- $ classes = array ($ className );
789-
790- foreach ($ classes as $ className ) {
791- if ($ className == '' && function_exists ($ methodName )) {
792- $ codeToCoverList [] = new ReflectionFunction (
793- $ methodName
794- );
795- } else {
796- if (!((class_exists ($ className ) ||
797- interface_exists ($ className ) ||
798- trait_exists ($ className )) &&
799- method_exists ($ className , $ methodName ))) {
800- throw new PHP_CodeCoverage_Exception_InvalidCoversTarget (
801- sprintf (
802- 'Trying to @cover not existing method "%s::%s". ' ,
803- $ className ,
804- $ methodName
805- )
806- );
807- }
808-
809- $ codeToCoverList [] = new ReflectionMethod (
810- $ className , $ methodName
811- );
812- }
813- }
814- }
815- } else {
816- $ extended = FALSE ;
817-
818- if (strpos ($ coveredElement , '<extended> ' ) !== FALSE ) {
819- $ coveredElement = str_replace (
820- '<extended> ' , '' , $ coveredElement
821- );
822-
823- $ extended = TRUE ;
824- }
825-
826- $ classes = array ($ coveredElement );
827-
828- if ($ extended ) {
829- $ classes = array_merge (
830- $ classes ,
831- class_implements ($ coveredElement ),
832- class_parents ($ coveredElement )
833- );
834- }
835-
836- foreach ($ classes as $ className ) {
837- if (!class_exists ($ className ) &&
838- !interface_exists ($ className ) &&
839- !trait_exists ($ className )) {
840- throw new PHP_CodeCoverage_Exception_InvalidCoversTarget (
841- sprintf (
842- 'Trying to @cover not existing class or ' .
843- 'interface "%s". ' ,
844- $ className
845- )
846- );
847- }
848-
849- $ codeToCoverList [] = new ReflectionClass ($ className );
850- }
851- }
852-
853- return $ codeToCoverList ;
854- }
855-
856614 /**
857615 * Returns the lines of a source file that should be ignored.
858616 *
0 commit comments