Exemple #1
0
 /**
  * Generates a mutant file from a mutation
  * @param Mutation $mutation
  *
  * @return string
  */
 public function generateFile(Mutation $mutation)
 {
     $id = $this->createId($mutation);
     // uniqid()
     $file = $this->tempDirectory . '/mutant.humbug.' . $id . '.php';
     // generate mutated file
     $mutatorClass = $mutation->getMutator();
     $originalFileContent = file_get_contents($mutation->getFile());
     $tokens = Tokenizer::getTokens($originalFileContent);
     $mutatedFileContent = $mutatorClass::mutate($tokens, $mutation->getIndex());
     file_put_contents($file, $mutatedFileContent);
     return $file;
 }
 /**
  * Replace any return statement contained in brackets with null (but retain
  * the statement and move to before the return call).
  * This isn't perfect - the statement might evaluate to null anyway.
  *
  * @param array $tokens
  * @param int $index
  * @return array
  */
 public static function getMutation(array &$tokens, $index)
 {
     $replace = [];
     $last = null;
     $tokenCount = count($tokens);
     for ($i = $index + 1; $i < $tokenCount; $i++) {
         if (is_array($tokens[$i]) && $tokens[$i][0] == T_WHITESPACE) {
             continue;
         } elseif (!is_array($tokens[$i]) && $tokens[$i] == '(') {
             // collect statement tokens (skipping one whitespace after 'return')
             for ($j = $index + 2; $j < $tokenCount; $j++) {
                 if (!is_array($tokens[$j]) && $tokens[$j] == ';') {
                     $last = $j - 1;
                     break;
                 }
                 $replace[$j] = $tokens[$j];
             }
             // replace them all with blanks and set last to 'null'
             foreach ($replace as $k => $t) {
                 if ($k == $last) {
                     $tokens[$k] = [T_STRING, 'null'];
                 } else {
                     $tokens[$k] = '';
                 }
             }
             // shift the instantiation prior to the return statement to
             // preserve instantiation behaviour without overwriting anything
             // and without upsetting line count.
             $replace[] = ';';
             $replace[] = [T_WHITESPACE, ' '];
             $string = ['-1' => Tokenizer::reconstructFromTokens($replace)];
             array_splice($tokens, $index, 0, $string);
             break;
         }
     }
 }
Exemple #3
0
 /**
  * Based on the current file, generate mutations
  *
  * @return void
  */
 public function generate()
 {
     $source = file_get_contents($this->getFilename());
     $tokens = Tokenizer::getTokens($source);
     $lineNumber = 1;
     $methodName = '???';
     $className = '???';
     $namespace = '';
     $inMethod = false;
     $inMethodBlock = false;
     $methodCurlyCount = 0;
     $tokenCount = count($tokens);
     foreach ($tokens as $index => $token) {
         if (is_array($token) && $token[0] == Tokenizer::T_NEWLINE) {
             $lineNumber = $token[2] + 1;
             continue;
         }
         if (is_array($token) && $token[0] == T_NAMESPACE) {
             for ($j = $index + 1; $j < $tokenCount; $j++) {
                 if ($tokens[$j][0] == T_STRING) {
                     $namespace .= '\\' . $tokens[$j][1];
                 } elseif ($tokens[$j] == '{' || $tokens[$j] == ';') {
                     break;
                 }
             }
             continue;
         }
         if (is_array($token) && ($token[0] == T_CLASS || $token[0] == T_INTERFACE) && $tokens[$index - 1][0] !== T_DOUBLE_COLON) {
             $className = $namespace . '\\' . $tokens[$index + 2][1];
             continue;
         }
         //TODO: handle whitespace!
         if (is_array($token) && $token[0] == T_FUNCTION) {
             if (!isset($tokens[$index + 2][1])) {
                 continue;
                 // ignore closure
             }
             $methodName = $tokens[$index + 2][1];
             $inMethod = true;
             continue;
         }
         /**
          * Limit mutation generation to the interior of methods (for now!)
          */
         if (true === $inMethod && false === $inMethodBlock && $methodCurlyCount == 0 && !($token == '{' || is_array($token) && $token[0] == T_CURLY_OPEN)) {
             continue;
             //skip over argument list
         }
         if ($inMethod) {
             if ($token == '{' || is_array($token) && $token[0] == T_CURLY_OPEN) {
                 $methodCurlyCount += 1;
                 $inMethodBlock = true;
                 continue;
             } elseif ($token == '}') {
                 $methodCurlyCount -= 1;
                 continue;
             }
             if ($methodCurlyCount == 0) {
                 $inMethodBlock = false;
                 $inMethod = false;
                 continue;
             }
         }
         if (true === $inMethodBlock) {
             foreach ($this->mutators as $mutator) {
                 if ($mutator::mutates($tokens, $index)) {
                     $this->mutations[] = new Mutation($this->getFilename(), $lineNumber, $className, $methodName, $index, $mutator);
                 }
             }
         }
     }
     return $this;
 }
 /**
  * Perform a mutation against the given original source code tokens for
  * a mutable element
  *
  * @param array $tokens
  * @param int $index
  * @return string
  */
 public static function mutate(array &$tokens, $index)
 {
     static::getMutation($tokens, $index);
     return Tokenizer::reconstructFromTokens($tokens);
 }