Clear cache - one position or all of them.
public static clearCache ( string | null $key = null ) | ||
$key | string | null | position to clear, when null clear all |
/** * @param int $expected * @param string $code * @param int $index * * @dataProvider provideCommentBlockStartDetectionCases */ public function testCommentBlockStartDetection($expected, $code, $index) { Tokens::clearCache(); $tokens = Tokens::fromCode($code); $fixer = $this->getFixer(); $method = new \ReflectionMethod($fixer, 'findCommentBlockStart'); $method->setAccessible(true); if ($expected !== ($result = $method->invoke($fixer, $tokens, $index))) { $this->fail(sprintf('Expected index %d (%s) got index %d (%s).', $expected, $tokens[$expected]->toJson(), $result, $tokens[$result]->toJson())); } }
/** * @return array */ public function fix() { $changed = array(); $config = $this->config; $finder = $config->getFinder(); $finderIterator = $finder instanceof \IteratorAggregate ? $finder->getIterator() : $finder; $fileFilteredFileIterator = new FileFilterIterator($finderIterator, $this->eventDispatcher, $this->cacheManager); $collection = $this->linter->isAsync() ? new FileCachingLintingIterator($fileFilteredFileIterator, $this->linter) : new FileLintingIterator($fileFilteredFileIterator, $this->linter); foreach ($collection as $file) { $fixInfo = $this->fixFile($file, $collection->currentLintingResult()); if ($fixInfo) { $name = $this->getFileRelativePathname($file); $changed[$name] = $fixInfo; } // we do not need Tokens to still caching just fixed file - so clear the cache Tokens::clearCache(); } return $changed; }
/** * @dataProvider provideFindHeaderCommentInsertionIndexCases */ public function testFindHeaderCommentInsertionIndex($expected, $code, array $config) { Tokens::clearCache(); $tokens = Tokens::fromCode($code); $fixer = $this->getFixer(); $fixer->configure($config); $method = new \ReflectionMethod($fixer, 'findHeaderCommentInsertionIndex'); $method->setAccessible(true); $this->assertSame($expected, $method->invoke($fixer, $tokens)); }
/** * @param string $source * @param int[] $indexes * @param Token[] $expected */ private function doTestClearTokens($source, array $indexes, array $expected) { Tokens::clearCache(); $tokens = Tokens::fromCode($source); foreach ($indexes as $index) { $tokens->clearTokenAndMergeSurroundingWhitespace($index); } $this->assertSame(count($expected), $tokens->count()); foreach ($expected as $index => $expectedToken) { $token = $tokens[$index]; $expectedPrototype = $expectedToken->getPrototype(); if (is_array($expectedPrototype)) { unset($expectedPrototype[2]); // don't compare token lines as our token mutations don't deal with line numbers } $this->assertTrue($token->equals($expectedPrototype), sprintf('The token at index %d should be %s, got %s', $index, json_encode($expectedPrototype), $token->toJson())); } }
/** * Tests if a fixer fixes a given string to match the expected result. * * It is used both if you want to test if something is fixed or if it is not touched by the fixer. * It also makes sure that the expected output does not change when run through the fixer. That means that you * do not need two test cases like [$expected] and [$expected, $input] (where $expected is the same in both cases) * as the latter covers both of them. * This method throws an exception if $expected and $input are equal to prevent test cases that accidentally do * not test anything. * * @param string $expected The expected fixer output. * @param string|null $input The fixer input, or null if it should intentionally be equal to the output. * @param \SplFileInfo|null $file The file to fix, or null if unneeded. * @param FixerInterface|null $fixer The fixer to be used, or null if it should be inferred from the test name. */ protected function doTest($expected, $input = null, \SplFileInfo $file = null, FixerInterface $fixer = null) { if ($expected === $input) { throw new \InvalidArgumentException('Input parameter must not be equal to expected parameter.'); } $fixer = $fixer ?: $this->getFixer(); $file = $file ?: $this->getTestFile(); $fileIsSupported = $fixer->supports($file); if (null !== $input) { $this->assertNull($this->lintSource($input)); Tokens::clearCache(); $tokens = Tokens::fromCode($input); if ($fileIsSupported) { $this->assertTrue($fixer->isCandidate($tokens), 'Fixer must be a candidate for input code.'); $fixResult = $fixer->fix($file, $tokens); $this->assertNull($fixResult, '->fix method must return null.'); } $this->assertTrue($tokens->isChanged(), 'Tokens collection built on input code must be marked as changed after fixing.'); $this->assertSame($expected, $tokens->generateCode(), 'Code build on input code must match expected code.'); Tokens::clearCache(); $expectedTokens = Tokens::fromCode($expected); $tokens->clearEmptyTokens(); $this->assertTokens($expectedTokens, $tokens); } $this->assertNull($this->lintSource($expected)); Tokens::clearCache(); $tokens = Tokens::fromCode($expected); if ($fileIsSupported) { $fixResult = $fixer->fix($file, $tokens); $this->assertNull($fixResult, '->fix method must return null.'); } $this->assertFalse($tokens->isChanged(), 'Tokens collection built on expected code must not be marked as changed after fixing.'); $this->assertSame($expected, $tokens->generateCode(), 'Code build on expected code must not change.'); }
private function fixFile(\SplFileInfo $file, LintingResultInterface $lintingResult) { $name = $this->getFileRelativePathname($file); try { $lintingResult->check(); } catch (LintingException $e) { $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus(FixerFileProcessedEvent::STATUS_INVALID)); $this->errorsManager->report(new Error(Error::TYPE_INVALID, $name)); return; } $fixers = $this->config->getFixers(); $old = file_get_contents($file->getRealPath()); $new = $old; $name = $this->getFileRelativePathname($file); $appliedFixers = array(); // we do not need Tokens to still caching previously fixed file - so clear the cache Tokens::clearCache(); $tokens = Tokens::fromCode($old); $newHash = $oldHash = $tokens->getCodeHash(); try { foreach ($fixers as $fixer) { if (!$fixer->supports($file) || !$fixer->isCandidate($tokens)) { continue; } $fixer->fix($file, $tokens); if ($tokens->isChanged()) { $tokens->clearEmptyTokens(); $tokens->clearChanged(); $appliedFixers[] = $fixer->getName(); } } } catch (\Exception $e) { $this->processException($name); return; } catch (\Throwable $e) { $this->processException($name); return; } $fixInfo = null; if (!empty($appliedFixers)) { $new = $tokens->generateCode(); $newHash = $tokens->getCodeHash(); } // We need to check if content was changed and then applied changes. // But we can't simple check $appliedFixers, because one fixer may revert // work of other and both of them will mark collection as changed. // Therefore we need to check if code hashes changed. if ($oldHash !== $newHash) { try { $this->linter->lintSource($new)->check(); } catch (LintingException $e) { $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus(FixerFileProcessedEvent::STATUS_LINT)); $this->errorsManager->report(new Error(Error::TYPE_LINT, $name)); return; } if (!$this->isDryRun) { if (false === @file_put_contents($file->getRealPath(), $new)) { $error = error_get_last(); if ($error) { throw new IOException(sprintf('Failed to write file "%s", "%s".', $file->getRealPath(), $error['message']), 0, null, $file->getRealPath()); } throw new IOException(sprintf('Failed to write file "%s".', $file->getRealPath()), 0, null, $file->getRealPath()); } } $fixInfo = array('appliedFixers' => $appliedFixers, 'diff' => $this->differ->diff($old, $new)); } $this->cacheManager->setFile($name, $new); $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus($fixInfo ? FixerFileProcessedEvent::STATUS_FIXED : FixerFileProcessedEvent::STATUS_NO_CHANGES)); return $fixInfo; }
/** * Tests if a fixer fixes a given string to match the expected result. * * It is used both if you want to test if something is fixed or if it is not touched by the fixer. * It also makes sure that the expected output does not change when run through the fixer. That means that you * do not need two test cases like [$expected] and [$expected, $input] (where $expected is the same in both cases) * as the latter covers both of them. * This method throws an exception if $expected and $input are equal to prevent test cases that accidentally do * not test anything. * * @param string $expected The expected fixer output * @param string|null $input The fixer input, or null if it should intentionally be equal to the output * @param \SplFileInfo|null $file The file to fix, or null if unneeded * @param FixerInterface|null $fixer The fixer to be used, or null if it should be inferred from the test name */ protected function doTest($expected, $input = null, \SplFileInfo $file = null, FixerInterface $fixer = null) { if ($expected === $input) { throw new \InvalidArgumentException('Input parameter must not be equal to expected parameter.'); } $fixer = $fixer ?: $this->getFixer(); $file = $file ?: $this->getTestFile(); $fileIsSupported = $fixer->supports($file); if (null !== $input) { $this->assertNull($this->lintSource($input)); Tokens::clearCache(); $tokens = Tokens::fromCode($input); if ($fileIsSupported) { $this->assertTrue($fixer->isCandidate($tokens), 'Fixer must be a candidate for input code.'); $fixResult = $fixer->fix($file, $tokens); $this->assertNull($fixResult, '->fix method must return null.'); } $this->assertSame($expected, $tokens->generateCode(), 'Code build on input code must match expected code.'); $this->assertTrue($tokens->isChanged(), 'Tokens collection built on input code must be marked as changed after fixing.'); $tokens->clearEmptyTokens(); $this->assertSame(count($tokens), count(array_unique(array_map(function (Token $token) { return spl_object_hash($token); }, $tokens->toArray()))), 'Token items inside Tokens collection must be unique.'); Tokens::clearCache(); $expectedTokens = Tokens::fromCode($expected); $this->assertTokens($expectedTokens, $tokens); } $this->assertNull($this->lintSource($expected)); Tokens::clearCache(); $tokens = Tokens::fromCode($expected); $isCandidate = $fixer->isCandidate($tokens); $this->assertFalse($tokens->isChanged(), 'Fixer should not touch Tokens on candidate check.'); if (!$isCandidate) { return; } if ($fileIsSupported) { $fixResult = $fixer->fix($file, $tokens); $this->assertNull($fixResult, '->fix method must return null.'); } $this->assertSame($expected, $tokens->generateCode(), 'Code build on expected code must not change.'); $this->assertFalse($tokens->isChanged(), 'Tokens collection built on expected code must not be marked as changed after fixing.'); }
/** * @dataProvider provideBlockDetectionCases */ public function testBlockDetection(array $expected, $source, $index) { Tokens::clearCache(); $tokens = Tokens::fromCode($source); $fixer = $this->getFixer(); $method = new \ReflectionMethod($fixer, 'getPreviousBlock'); $method->setAccessible(true); $result = $method->invoke($fixer, $tokens, $index); $this->assertSame($expected, $result); }
public function fixFile(\SplFileInfo $file, array $fixers, $dryRun, $diff, FileCacheManager $fileCacheManager) { $new = $old = file_get_contents($file->getRealPath()); $name = $this->getFileRelativePathname($file); if ('' === $old || !$fileCacheManager->needFixing($name, $old) || PHP_VERSION_ID >= 50306 && PHP_VERSION_ID < 50400 && false !== stripos($old, '__halt_compiler()')) { $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus(FixerFileProcessedEvent::STATUS_SKIPPED)); return; } try { $this->linter->lintFile($file->getRealPath()); } catch (LintingException $e) { $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus(FixerFileProcessedEvent::STATUS_INVALID)); $this->errorsManager->report(new Error(Error::TYPE_INVALID, $name)); return; } $appliedFixers = array(); // we do not need Tokens to still caching previously fixed file - so clear the cache Tokens::clearCache(); $tokens = Tokens::fromCode($old); $newHash = $oldHash = $tokens->getCodeHash(); try { foreach ($fixers as $fixer) { if (!$fixer->supports($file) || !$fixer->isCandidate($tokens)) { continue; } $fixer->fix($file, $tokens); if ($tokens->isChanged()) { $tokens->clearEmptyTokens(); $tokens->clearChanged(); $appliedFixers[] = $fixer->getName(); } } } catch (\Exception $e) { $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus(FixerFileProcessedEvent::STATUS_EXCEPTION)); $this->errorsManager->report(new Error(Error::TYPE_EXCEPTION, $name)); return; } $fixInfo = null; if (!empty($appliedFixers)) { $new = $tokens->generateCode(); $newHash = $tokens->getCodeHash(); } // We need to check if content was changed and then applied changes. // But we can't simple check $appliedFixers, because one fixer may revert // work of other and both of them will mark collection as changed. // Therefore we need to check if code hashes changed. if ($oldHash !== $newHash) { try { $this->linter->lintSource($new); } catch (LintingException $e) { $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus(FixerFileProcessedEvent::STATUS_LINT)); $this->errorsManager->report(new Error(Error::TYPE_LINT, $name)); return; } if (!$dryRun && false === @file_put_contents($file->getRealPath(), $new)) { $error = error_get_last(); if ($error) { throw new IOException(sprintf('Failed to write file "%s", "%s".', $file->getRealpath(), $error['message']), 0, null, $file->getRealpath()); } throw new IOException(sprintf('Failed to write file "%s".', $file->getRealpath()), 0, null, $file->getRealpath()); } $fixInfo = array('appliedFixers' => $appliedFixers); if ($diff) { $fixInfo['diff'] = $this->stringDiff($old, $new); } } $fileCacheManager->setFile($name, $new); $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus($fixInfo ? FixerFileProcessedEvent::STATUS_FIXED : FixerFileProcessedEvent::STATUS_NO_CHANGES)); return $fixInfo; }
/** * @param string $source valid PHP source code * @param int $startIndex start index of the comment block * @param int $endIndex expected index of the last token of the block * @param bool $isEmpty expected value of empty flag returned * * @dataProvider provideCommentBlockCases */ public function testGetCommentBlock($source, $startIndex, $endIndex, $isEmpty) { Tokens::clearCache(); $tokens = Tokens::fromCode($source); $this->assertTrue($tokens[$startIndex]->isComment(), sprintf('Misconfiguration of test, expected comment token at index "%d".', $startIndex)); $fixer = $this->getFixer(); $method = new \ReflectionMethod($fixer, 'getCommentBlock'); $method->setAccessible(true); list($foundStart, $foundEnd, $foundIsEmpty) = $method->invoke($fixer, $tokens, $startIndex); $this->assertSame($startIndex, $foundStart, 'Find start index of block failed.'); $this->assertSame($endIndex, $foundEnd, 'Find end index of block failed.'); $this->assertSame($isEmpty, $foundIsEmpty, 'Is empty comment block detection failed.'); }