/** * 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; }
/** * 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; }