From 70f3103c83b9806ba0723e467782adb3cfb4a6ea Mon Sep 17 00:00:00 2001 From: SiD Date: Thu, 7 Sep 2017 23:35:11 +0300 Subject: [PATCH 1/4] Add Filesystem and add Directory Check for logs path. For cases when path has inner dirs. --- app/container.php | 5 ++ src/Filesystem/Exception/IOException.php | 32 ++++++++ .../Exception/IOExceptionInterface.php | 17 +++++ src/Filesystem/Filesystem.php | 39 ++++++++++ src/InfectionApplication.php | 2 +- .../Listener/TextFileLoggerSubscriber.php | 43 +++++------ src/Utils/TempDirectoryCreator.php | 14 +++- tests/Filesystem/FilesystemTest.php | 74 +++++++++++++++++++ 8 files changed, 201 insertions(+), 25 deletions(-) create mode 100644 src/Filesystem/Exception/IOException.php create mode 100644 src/Filesystem/Exception/IOExceptionInterface.php create mode 100644 src/Filesystem/Filesystem.php create mode 100644 tests/Filesystem/FilesystemTest.php diff --git a/app/container.php b/app/container.php index 6ebbe23cf..52948d081 100644 --- a/app/container.php +++ b/app/container.php @@ -15,6 +15,7 @@ use Infection\Command\InfectionCommand; use Infection\Process\Runner\Parallel\ParallelProcessRunner; use Infection\EventDispatcher\EventDispatcher; +use Infection\Filesystem\Filesystem; use Infection\Finder\Locator; use Infection\TestFramework\PhpUnit\Config\Path\PathReplacer; use Infection\TestFramework\Config\TestFrameworkConfigLocator; @@ -46,6 +47,10 @@ return $c['temp.dir.creator']->createAndGet(); }; +$c['filesystem'] = function (Container $c): Filesystem { + return new Filesystem(); +}; + $c['temp.dir.creator'] = function (): TempDirectoryCreator { return new TempDirectoryCreator(); }; diff --git a/src/Filesystem/Exception/IOException.php b/src/Filesystem/Exception/IOException.php new file mode 100644 index 000000000..2aeeaaac1 --- /dev/null +++ b/src/Filesystem/Exception/IOException.php @@ -0,0 +1,32 @@ +path = $path; + + parent::__construct($message, $code, $previous); + } + + /** + * {@inheritdoc} + */ + public function getPath() + { + return $this->path; + } +} diff --git a/src/Filesystem/Exception/IOExceptionInterface.php b/src/Filesystem/Exception/IOExceptionInterface.php new file mode 100644 index 000000000..e9e9e5e30 --- /dev/null +++ b/src/Filesystem/Exception/IOExceptionInterface.php @@ -0,0 +1,17 @@ +addSubscriber(new MutationGeneratingConsoleLoggerSubscriber($this->output, $mutationGeneratingProgressBar)); $eventDispatcher->addSubscriber(new MutantCreatingConsoleLoggerSubscriber($this->output, $mutantCreatingProgressBar)); $eventDispatcher->addSubscriber(new MutationTestingConsoleLoggerSubscriber($this->output, $this->getOutputFormatter(), $metricsCalculator, $this->get('diff.colorizer'), $this->input->getOption('show-mutations'))); - $eventDispatcher->addSubscriber(new TextFileLoggerSubscriber($this->get('infection.config'), $metricsCalculator)); + $eventDispatcher->addSubscriber(new TextFileLoggerSubscriber($this->get('infection.config'), $metricsCalculator, $this->get('filesystem'))); } private function getCodeCoverageData(string $testFrameworkKey): CodeCoverageData diff --git a/src/Process/Listener/TextFileLoggerSubscriber.php b/src/Process/Listener/TextFileLoggerSubscriber.php index d4da332b7..a37c62cdb 100644 --- a/src/Process/Listener/TextFileLoggerSubscriber.php +++ b/src/Process/Listener/TextFileLoggerSubscriber.php @@ -11,6 +11,7 @@ use Infection\Config\InfectionConfig; use Infection\EventDispatcher\EventSubscriberInterface; use Infection\Events\MutationTestingFinished; +use Infection\Filesystem\Filesystem; use Infection\Mutant\MetricsCalculator; use Infection\Process\MutantProcess; @@ -26,10 +27,16 @@ class TextFileLoggerSubscriber implements EventSubscriberInterface */ private $metricsCalculator; - public function __construct(InfectionConfig $infectionConfig, MetricsCalculator $metricsCalculator) + /** + * @var Filesystem + */ + private $fs; + + public function __construct(InfectionConfig $infectionConfig, MetricsCalculator $metricsCalculator, Filesystem $fs) { $this->infectionConfig = $infectionConfig; $this->metricsCalculator = $metricsCalculator; + $this->fs = $fs; } public function getSubscribedEvents() @@ -41,32 +48,26 @@ public function getSubscribedEvents() public function onMutationTestingFinished(MutationTestingFinished $event) { - $textFileLogPath = $this->infectionConfig->getTextFileLogPath(); + $logFilePath = $this->infectionConfig->getTextFileLogPath(); - if ($textFileLogPath) { - $logParts = []; + if ($logFilePath) { + $this->fs->mkdir(\dirname($logFilePath)); - $logParts = array_merge( - $logParts, - $this->getLogParts($this->metricsCalculator->getEscapedMutantProcesses(), 'Escaped') - ); + $escapedParts = $this->getLogParts($this->metricsCalculator->getEscapedMutantProcesses(), 'Escaped'); - $logParts = array_merge( - $logParts, - $this->getLogParts($this->metricsCalculator->getTimedOutProcesses(), 'Timeout') - ); + $timedOutParts = $this->getLogParts($this->metricsCalculator->getTimedOutProcesses(), 'Timeout'); - $logParts = array_merge( - $logParts, - $this->getLogParts($this->metricsCalculator->getKilledMutantProcesses(), 'Killed') - ); + $killedParts = $this->getLogParts($this->metricsCalculator->getKilledMutantProcesses(), 'Killed'); - $logParts = array_merge( - $logParts, - $this->getNotCoveredLogParts($this->metricsCalculator->getNotCoveredMutantProcesses(), 'Not covered') - ); + $notCoveredParts = $this->getNotCoveredLogParts($this->metricsCalculator->getNotCoveredMutantProcesses(), 'Not covered'); - file_put_contents($textFileLogPath, implode($logParts, "\n")); + file_put_contents( + $logFilePath, + implode( + array_merge($escapedParts, $timedOutParts, $killedParts, $notCoveredParts), + "\n" + ) + ); } } diff --git a/src/Utils/TempDirectoryCreator.php b/src/Utils/TempDirectoryCreator.php index 722f45910..0b445a24d 100644 --- a/src/Utils/TempDirectoryCreator.php +++ b/src/Utils/TempDirectoryCreator.php @@ -15,11 +15,19 @@ class TempDirectoryCreator */ private $tempDirectory; - public function createAndGet($dirName = null): string + /** + * @param string|null $dir + * + * @return string + */ + public function createAndGet(string $dirName = null): string { if ($this->tempDirectory === null) { - $root = sys_get_temp_dir(); - $path = $root . sprintf('/%s', $dirName ?: 'infection'); + $path = sprintf( + '%s/%s', + sys_get_temp_dir(), + $dirName ?: 'infection' + ); if (!@mkdir($path, 0777, true) && !is_dir($path)) { throw new \RuntimeException('Can not create temp dir'); diff --git a/tests/Filesystem/FilesystemTest.php b/tests/Filesystem/FilesystemTest.php new file mode 100644 index 000000000..fc22170bf --- /dev/null +++ b/tests/Filesystem/FilesystemTest.php @@ -0,0 +1,74 @@ +umask = \umask(0); + $this->filesystem = new Filesystem(); + $this->workspace = \sys_get_temp_dir() . '/' . \microtime(true) . \random_int(100, 999); + \mkdir($this->workspace, 0777, true); + } + + protected function tearDown() + { + @\unlink($this->workspace); + \umask($this->umask); + } + + public function test_mkdir_creates_directory() + { + $dir = $this->workspace . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR; + + $this->filesystem->mkdir($dir); + + $this->assertTrue(\is_dir($dir)); + } + + public function test_mkdir_creates_directory_recursively() + { + $dir = $this->workspace + . DIRECTORY_SEPARATOR . 'test' + . DIRECTORY_SEPARATOR . 'sub_directory'; + + $this->filesystem->mkdir($dir); + + $this->assertTrue(\is_dir($dir)); + } + + /** + * @expectedException \Infection\Filesystem\Exception\IOException + */ + public function test_mkdir_creates_directory_fails() + { + $basePath = $this->workspace.DIRECTORY_SEPARATOR; + $dir = $basePath.'2'; + + \file_put_contents($dir, ''); + + $this->filesystem->mkdir($dir); + } +} From 70f350e6eb9d2c072aa1035062a42a537136cb5f Mon Sep 17 00:00:00 2001 From: borNfreee Date: Wed, 13 Sep 2017 00:28:00 +0300 Subject: [PATCH 2/4] Rewrite test with tmp dir --- .../ValueProvider/ExcludeDirsProviderTest.php | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/tests/Config/ValueProvider/ExcludeDirsProviderTest.php b/tests/Config/ValueProvider/ExcludeDirsProviderTest.php index 59af7df03..243fcdfc0 100644 --- a/tests/Config/ValueProvider/ExcludeDirsProviderTest.php +++ b/tests/Config/ValueProvider/ExcludeDirsProviderTest.php @@ -16,6 +16,26 @@ class ExcludeDirsProviderTest extends AbstractBaseProviderTest { + /** + * @var string + */ + private $workspace; + + private $umask; + + protected function setUp() + { + $this->umask = \umask(0); + $this->workspace = \sys_get_temp_dir() . '/exclude' . \microtime(true) . \random_int(100, 999); + \mkdir($this->workspace, 0777, true); + } + + protected function tearDown() + { + @\unlink($this->workspace); + \umask($this->umask); + } + public function test_it_contains_vendors_when_sources_contains_current_dir() { $consoleMock = Mockery::mock(ConsoleHelper::class); @@ -64,6 +84,12 @@ public function test_passes_when_correct_dir_typed() $this->markTestSkipped("Stty is not available"); } + $dir1 = $this->workspace . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR; + $dir2 = $this->workspace . DIRECTORY_SEPARATOR . 'foo' . DIRECTORY_SEPARATOR; + + \mkdir($dir1); + \mkdir($dir2); + $consoleMock = Mockery::mock(ConsoleHelper::class); $consoleMock->shouldReceive('getQuestion')->once()->andReturn('?'); @@ -72,12 +98,12 @@ public function test_passes_when_correct_dir_typed() $provider = new ExcludeDirsProvider($consoleMock, $dialog); $excludeDirs = $provider->get( - $this->createStreamableInputInterfaceMock($this->getInputStream("Files\n")), + $this->createStreamableInputInterfaceMock($this->getInputStream("foo\n")), $this->createOutputInterface(), ['src'], - ['tests'] + [$this->workspace] ); - $this->assertContains('Files', $excludeDirs); + $this->assertContains('foo', $excludeDirs); } } \ No newline at end of file From 979d80ba0bade62c94a23e7395f3c06ff4611284 Mon Sep 17 00:00:00 2001 From: borNfreee Date: Wed, 13 Sep 2017 13:46:50 +0300 Subject: [PATCH 3/4] Fix critical bug with IncludeInterceptor - parameter was used incorrectly. Refactor to use it as a bit mask. Add more tests to increase MSI --- src/Filesystem/Filesystem.php | 2 +- src/StreamWrapper/IncludeInterceptor.php | 7 +++++-- tests/Filesystem/FilesystemTest.php | 26 ++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/Filesystem/Filesystem.php b/src/Filesystem/Filesystem.php index 2d5490024..b7d2c6f56 100644 --- a/src/Filesystem/Filesystem.php +++ b/src/Filesystem/Filesystem.php @@ -18,7 +18,7 @@ class Filesystem * @param string $path The directory path * @param int $mode The directory mode * - * @throws \RuntimeException On any directory creation failure + * @throws IOException On any directory creation failure */ public function mkdir($path, int $mode = 0755) { diff --git a/src/StreamWrapper/IncludeInterceptor.php b/src/StreamWrapper/IncludeInterceptor.php index 648b3412d..3ec658921 100644 --- a/src/StreamWrapper/IncludeInterceptor.php +++ b/src/StreamWrapper/IncludeInterceptor.php @@ -108,10 +108,13 @@ public function dir_rewinddir() public function mkdir($path, $mode, $options) { self::disable(); + + $isRecursive = (bool) ($options & STREAM_MKDIR_RECURSIVE); + if (isset($this->context)) { - $return = mkdir($path, $mode, $options, $this->context); + $return = mkdir($path, $mode, $isRecursive, $this->context); } else { - $return = mkdir($path, $mode, $options); + $return = mkdir($path, $mode, $isRecursive); } self::enable(); diff --git a/tests/Filesystem/FilesystemTest.php b/tests/Filesystem/FilesystemTest.php index fc22170bf..7820d68e5 100644 --- a/tests/Filesystem/FilesystemTest.php +++ b/tests/Filesystem/FilesystemTest.php @@ -8,6 +8,7 @@ namespace Infection\Tests\Filesystem; +use Infection\Filesystem\Exception\IOException; use Infection\Filesystem\Filesystem; use PHPUnit\Framework\TestCase; @@ -61,6 +62,7 @@ public function test_mkdir_creates_directory_recursively() /** * @expectedException \Infection\Filesystem\Exception\IOException + * @expectedExceptionCode 0 */ public function test_mkdir_creates_directory_fails() { @@ -71,4 +73,28 @@ public function test_mkdir_creates_directory_fails() $this->filesystem->mkdir($dir); } + + public function test_mkdir_passes_path_to_io_exceptino() + { + try { + $basePath = $this->workspace.DIRECTORY_SEPARATOR; + $dir = $basePath.'2'; + + \file_put_contents($dir, ''); + + $this->filesystem->mkdir($dir); + } catch (IOException $e) { + $this->assertSame($dir, $e->getPath()); + } + } + + public function test_mkdir_does_not_fail_when_dir_already_exists() + { + $dir = $this->workspace . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR; + + $this->filesystem->mkdir($dir); + $this->filesystem->mkdir($dir); + + $this->assertTrue(\is_dir($dir)); + } } From cc4d5ef90440b69d1b0e6abe774d632369c2e61a Mon Sep 17 00:00:00 2001 From: borNfreee Date: Wed, 13 Sep 2017 13:52:48 +0300 Subject: [PATCH 4/4] Fix phpstan errors --- tests/Filesystem/FilesystemTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Filesystem/FilesystemTest.php b/tests/Filesystem/FilesystemTest.php index 7820d68e5..5df690f0f 100644 --- a/tests/Filesystem/FilesystemTest.php +++ b/tests/Filesystem/FilesystemTest.php @@ -76,12 +76,12 @@ public function test_mkdir_creates_directory_fails() public function test_mkdir_passes_path_to_io_exceptino() { - try { - $basePath = $this->workspace.DIRECTORY_SEPARATOR; - $dir = $basePath.'2'; + $basePath = $this->workspace.DIRECTORY_SEPARATOR; + $dir = $basePath.'2'; - \file_put_contents($dir, ''); + \file_put_contents($dir, ''); + try { $this->filesystem->mkdir($dir); } catch (IOException $e) { $this->assertSame($dir, $e->getPath());