Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Filesystem and add Directory Check for logs path. #40

Merged
merged 4 commits into from
Sep 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/container.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
};
Expand Down
32 changes: 32 additions & 0 deletions src/Filesystem/Exception/IOException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
/**
* Copyright © 2017 Maks Rafalko
*
* License: https://opensource.org/licenses/BSD-3-Clause New BSD License
*/
declare(strict_types=1);

namespace Infection\Filesystem\Exception;

class IOException extends \RuntimeException
{
/**
* @var null|string
*/
private $path;

public function __construct($message, $code = 0, \Exception $previous = null, $path = null)
{
$this->path = $path;

parent::__construct($message, $code, $previous);
}

/**
* {@inheritdoc}
*/
public function getPath()
{
return $this->path;
}
}
17 changes: 17 additions & 0 deletions src/Filesystem/Exception/IOExceptionInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php
/**
* Copyright © 2017 Maks Rafalko
*
* License: https://opensource.org/licenses/BSD-3-Clause New BSD License
*/
namespace Infection\Filesystem\Exception;

interface IOExceptionInterface
{
/**
* Returns the associated path for the exception.
*
* @return string The path
*/
public function getPath();
}
39 changes: 39 additions & 0 deletions src/Filesystem/Filesystem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
/**
* Copyright © 2017 Maks Rafalko
*
* License: https://opensource.org/licenses/BSD-3-Clause New BSD License
*/
declare(strict_types=1);

namespace Infection\Filesystem;

use Infection\Filesystem\Exception\IOException;

class Filesystem
{
/**
* Create a directory recursively.
*
* @param string $path The directory path
* @param int $mode The directory mode
*
* @throws IOException On any directory creation failure
*/
public function mkdir($path, int $mode = 0755)
{
if (\is_dir($path)) {
return;
}

if (true !== @\mkdir($path, $mode, true)) {
$error = \error_get_last();

if ($error) {
throw new IOException(\sprintf('Failed to create "%s": %s', $path, $error['message']), 0, null, $path);
}

throw new IOException(\sprintf('Failed to create "%s"', $path), 0, null, $path);
}
}
}
2 changes: 1 addition & 1 deletion src/InfectionApplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ private function addSubscribers(EventDispatcher $eventDispatcher, MetricsCalcula
$eventDispatcher->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
Expand Down
43 changes: 22 additions & 21 deletions src/Process/Listener/TextFileLoggerSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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()
Expand All @@ -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"
)
);
}
}

Expand Down
7 changes: 5 additions & 2 deletions src/StreamWrapper/IncludeInterceptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
14 changes: 11 additions & 3 deletions src/Utils/TempDirectoryCreator.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
32 changes: 29 additions & 3 deletions tests/Config/ValueProvider/ExcludeDirsProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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('?');

Expand All @@ -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);
}
}
100 changes: 100 additions & 0 deletions tests/Filesystem/FilesystemTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php
/**
* Copyright © 2017 Maks Rafalko
*
* License: https://opensource.org/licenses/BSD-3-Clause New BSD License
*/
declare(strict_types=1);

namespace Infection\Tests\Filesystem;

use Infection\Filesystem\Exception\IOException;
use Infection\Filesystem\Filesystem;
use PHPUnit\Framework\TestCase;

class FilesystemTest extends TestCase
{
/**
* @var Filesystem
*/
private $filesystem;

/**
* @var string
*/
private $workspace;

private $umask;

protected function setUp()
{
$this->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
* @expectedExceptionCode 0
*/
public function test_mkdir_creates_directory_fails()
{
$basePath = $this->workspace.DIRECTORY_SEPARATOR;
$dir = $basePath.'2';

\file_put_contents($dir, '');

$this->filesystem->mkdir($dir);
}

public function test_mkdir_passes_path_to_io_exceptino()
{
$basePath = $this->workspace.DIRECTORY_SEPARATOR;
$dir = $basePath.'2';

\file_put_contents($dir, '');

try {
$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));
}
}