Skip to content

Commit 3eaf6ae

Browse files
authored
Merge pull request #209 from php-school/feature/in-temp-solution-mapping
Pushes all solution files into temp when created
2 parents e0e4a93 + 08af37a commit 3eaf6ae

File tree

7 files changed

+252
-142
lines changed

7 files changed

+252
-142
lines changed

src/Solution/DirectorySolution.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public function __construct(string $directory, string $entryPoint, array $exclus
8585
*/
8686
public static function fromDirectory(string $directory, array $exclusions = [], $entryPoint = 'solution.php'): self
8787
{
88+
$directory = InTempSolutionMapper::mapDirectory($directory);
8889
return new self($directory, $entryPoint, array_merge($exclusions, ['composer.lock', 'vendor']));
8990
}
9091

src/Solution/InTempSolutionMapper.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpSchool\PhpWorkshop\Solution;
6+
7+
use PhpSchool\PhpWorkshop\Utils\Path;
8+
use PhpSchool\PhpWorkshop\Utils\System;
9+
use Symfony\Component\Filesystem\Filesystem;
10+
11+
class InTempSolutionMapper
12+
{
13+
public static function mapDirectory(string $directory): string
14+
{
15+
$fileSystem = new Filesystem();
16+
$tempDir = self::getDeterministicTempDir($directory);
17+
18+
$fileSystem->mkdir($tempDir);
19+
20+
$dirIterator = new \RecursiveDirectoryIterator($directory, \RecursiveDirectoryIterator::SKIP_DOTS);
21+
$iterator = new \RecursiveIteratorIterator($dirIterator, \RecursiveIteratorIterator::SELF_FIRST);
22+
23+
foreach ($iterator as $file) {
24+
$target = Path::join($tempDir, $iterator->getSubPathName());
25+
26+
if ($fileSystem->exists($target)) {
27+
continue;
28+
}
29+
30+
$file->isDir()
31+
? $fileSystem->mkdir($target)
32+
: $fileSystem->copy($file->getPathname(), $target);
33+
}
34+
35+
return $tempDir;
36+
}
37+
38+
public static function mapFile(string $file): string
39+
{
40+
$fileSystem = new Filesystem();
41+
$tempFile = Path::join(self::getDeterministicTempDir($file), basename($file));
42+
43+
if ($fileSystem->exists($tempFile)) {
44+
return $tempFile;
45+
}
46+
47+
$fileSystem->mkdir(System::tempDir());
48+
$fileSystem->copy($file, $tempFile);
49+
50+
return $tempFile;
51+
}
52+
53+
private static function getDeterministicTempDir(string $path): string
54+
{
55+
return Path::join(System::tempDir(), 'php-school', md5($path));
56+
}
57+
}

src/Solution/SingleFileSolution.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public function __construct(string $file)
3838
*/
3939
public static function fromFile(string $file): self
4040
{
41-
return new self($file);
41+
return new self(InTempSolutionMapper::mapFile($file));
4242
}
4343

4444
/**

test/Exercise/AbstractExerciseTest.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,10 @@ public function testGetSolution(string $name): void
2626
$path = __DIR__ . '/../../exercises/array-we-go/solution/solution.php';
2727
mkdir(dirname($path), 0777, true);
2828
touch($path);
29-
$solution = $exercise->getSolution();
30-
$this->assertInstanceOf(SolutionInterface::class, $solution);
31-
$files = $solution->getFiles();
32-
$this->assertCount(1, $files);
33-
$this->assertInstanceOf(SolutionFile::class, $files[0]);
34-
$this->assertSame(realpath($path), $files[0]->__toString());
29+
$files = $exercise->getSolution()->getFiles();
30+
self::assertCount(1, $files);
31+
self::assertInstanceOf(SolutionFile::class, $files[0]);
32+
self::assertFileEquals(realpath($path), $files[0]->__toString());
3533
unlink($path);
3634
rmdir(__DIR__ . '/../../exercises/array-we-go/solution');
3735
rmdir(__DIR__ . '/../../exercises/array-we-go');

test/Solution/DirectorySolutionTest.php

Lines changed: 89 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -4,194 +4,154 @@
44

55
use InvalidArgumentException;
66
use PhpSchool\PhpWorkshop\Solution\DirectorySolution;
7+
use PhpSchool\PhpWorkshop\Utils\Path;
78
use PHPUnit\Framework\TestCase;
9+
use Symfony\Component\Filesystem\Filesystem;
810

911
class DirectorySolutionTest extends TestCase
1012
{
13+
/**
14+
* @var string
15+
*/
16+
private $tempPath;
17+
18+
public function setUp(): void
19+
{
20+
$this->tempPath = sprintf('%s/%s', realpath(sys_get_temp_dir()), $this->getName());
21+
@mkdir($this->tempPath);
22+
}
23+
24+
public function tearDown(): void
25+
{
26+
$fileSystem = new Filesystem();
27+
$fileSystem->remove(Path::join(realpath(sys_get_temp_dir()), 'php-school'));
28+
$fileSystem->remove($this->tempPath);
29+
}
30+
1131
public function testExceptionIsThrownIfEntryPointDoesNotExist(): void
1232
{
13-
$tempPath = sprintf('%s/%s', realpath(sys_get_temp_dir()), $this->getName());
14-
@mkdir($tempPath, 0775, true);
15-
touch(sprintf('%s/some-class.php', $tempPath));
33+
touch(sprintf('%s/some-class.php', $this->tempPath));
1634

1735
$this->expectException(InvalidArgumentException::class);
18-
$this->expectExceptionMessage(sprintf('Entry point: "solution.php" does not exist in: "%s"', $tempPath));
36+
$this->expectExceptionMessageMatches('/Entry point: "solution.php" does not exist in: ".*"/');
1937

20-
DirectorySolution::fromDirectory($tempPath);
21-
22-
unlink(sprintf('%s/some-class.php', $tempPath));
23-
rmdir($tempPath);
38+
DirectorySolution::fromDirectory($this->tempPath);
2439
}
2540

2641
public function testWithDefaultEntryPoint(): void
2742
{
28-
$tempPath = sprintf('%s/%s', realpath(sys_get_temp_dir()), $this->getName());
29-
@mkdir($tempPath, 0775, true);
30-
touch(sprintf('%s/solution.php', $tempPath));
31-
touch(sprintf('%s/some-class.php', $tempPath));
43+
file_put_contents(sprintf('%s/solution.php', $this->tempPath), 'ENTRYPOINT');
44+
file_put_contents(sprintf('%s/some-class.php', $this->tempPath), 'SOME CLASS');
3245

33-
$solution = DirectorySolution::fromDirectory($tempPath);
46+
$solution = DirectorySolution::fromDirectory($this->tempPath);
3447

35-
$this->assertSame($tempPath, $solution->getBaseDirectory());
36-
$this->assertFalse($solution->hasComposerFile());
37-
$this->assertSame(sprintf('%s/solution.php', $tempPath), $solution->getEntryPoint());
48+
self::assertFalse($solution->hasComposerFile());
49+
self::assertSame('ENTRYPOINT', file_get_contents($solution->getEntryPoint()));
3850
$files = $solution->getFiles();
39-
$this->assertCount(2, $files);
40-
41-
$this->assertSame(sprintf('%s/solution.php', $tempPath), $files[0]->__toString());
42-
$this->assertSame(sprintf('%s/some-class.php', $tempPath), $files[1]->__toString());
51+
self::assertCount(2, $files);
4352

44-
unlink(sprintf('%s/solution.php', $tempPath));
45-
unlink(sprintf('%s/some-class.php', $tempPath));
46-
rmdir($tempPath);
53+
self::assertSame('ENTRYPOINT', file_get_contents($files[0]->__toString()));
54+
self::assertSame('SOME CLASS', file_get_contents($files[1]->__toString()));
4755
}
4856

4957
public function testWithManualEntryPoint(): void
5058
{
51-
$tempPath = sprintf('%s/%s', realpath(sys_get_temp_dir()), $this->getName());
52-
@mkdir($tempPath, 0775, true);
53-
touch(sprintf('%s/index.php', $tempPath));
54-
touch(sprintf('%s/some-class.php', $tempPath));
59+
file_put_contents(sprintf('%s/index.php', $this->tempPath), 'ENTRYPOINT');
60+
file_put_contents(sprintf('%s/some-class.php', $this->tempPath), 'SOME CLASS');
5561

56-
$solution = DirectorySolution::fromDirectory($tempPath, [], 'index.php');
62+
$solution = DirectorySolution::fromDirectory($this->tempPath, [], 'index.php');
5763

58-
$this->assertSame($tempPath, $solution->getBaseDirectory());
59-
$this->assertFalse($solution->hasComposerFile());
60-
$this->assertSame(sprintf('%s/index.php', $tempPath), $solution->getEntryPoint());
64+
self::assertFalse($solution->hasComposerFile());
65+
self::assertSame('ENTRYPOINT', file_get_contents($solution->getEntryPoint()));
6166
$files = $solution->getFiles();
62-
$this->assertCount(2, $files);
67+
self::assertCount(2, $files);
6368

64-
$this->assertSame(sprintf('%s/index.php', $tempPath), $files[0]->__toString());
65-
$this->assertSame(sprintf('%s/some-class.php', $tempPath), $files[1]->__toString());
66-
67-
unlink(sprintf('%s/index.php', $tempPath));
68-
unlink(sprintf('%s/some-class.php', $tempPath));
69-
rmdir($tempPath);
69+
self::assertSame('ENTRYPOINT', file_get_contents($files[0]->__toString()));
70+
self::assertSame('SOME CLASS', file_get_contents($files[1]->__toString()));
7071
}
7172

7273
public function testHasComposerFileReturnsTrueIfPresent(): void
7374
{
74-
$tempPath = sprintf('%s/%s', realpath(sys_get_temp_dir()), $this->getName());
75-
@mkdir($tempPath, 0775, true);
76-
touch(sprintf('%s/solution.php', $tempPath));
77-
touch(sprintf('%s/some-class.php', $tempPath));
78-
touch(sprintf('%s/composer.lock', $tempPath));
75+
file_put_contents(sprintf('%s/solution.php', $this->tempPath), 'ENTRYPOINT');
76+
file_put_contents(sprintf('%s/some-class.php', $this->tempPath), 'SOME CLASS');
77+
touch(sprintf('%s/composer.lock', $this->tempPath));
7978

80-
$solution = DirectorySolution::fromDirectory($tempPath);
79+
$solution = DirectorySolution::fromDirectory($this->tempPath);
8180

82-
$this->assertSame($tempPath, $solution->getBaseDirectory());
83-
$this->assertTrue($solution->hasComposerFile());
84-
$this->assertSame(sprintf('%s/solution.php', $tempPath), $solution->getEntryPoint());
81+
self::assertTrue($solution->hasComposerFile());
82+
self::assertSame('ENTRYPOINT', file_get_contents($solution->getEntryPoint()));
8583
$files = $solution->getFiles();
86-
$this->assertCount(2, $files);
87-
88-
$this->assertSame(sprintf('%s/solution.php', $tempPath), $files[0]->__toString());
89-
$this->assertSame(sprintf('%s/some-class.php', $tempPath), $files[1]->__toString());
84+
self::assertCount(2, $files);
9085

91-
unlink(sprintf('%s/composer.lock', $tempPath));
92-
unlink(sprintf('%s/solution.php', $tempPath));
93-
unlink(sprintf('%s/some-class.php', $tempPath));
86+
self::assertSame('ENTRYPOINT', file_get_contents($files[0]->__toString()));
87+
self::assertSame('SOME CLASS', file_get_contents($files[1]->__toString()));
9488
}
9589

9690
public function testWithExceptions(): void
9791
{
98-
$tempPath = sprintf('%s/%s', realpath(sys_get_temp_dir()), $this->getName());
99-
@mkdir($tempPath, 0775, true);
100-
touch(sprintf('%s/solution.php', $tempPath));
101-
touch(sprintf('%s/some-class.php', $tempPath));
102-
touch(sprintf('%s/exclude.txt', $tempPath));
92+
file_put_contents(sprintf('%s/solution.php', $this->tempPath), 'ENTRYPOINT');
93+
file_put_contents(sprintf('%s/some-class.php', $this->tempPath), 'SOME CLASS');
94+
touch(sprintf('%s/exclude.txt', $this->tempPath));
10395

10496
$exclusions = ['exclude.txt'];
10597

106-
$solution = DirectorySolution::fromDirectory($tempPath, $exclusions);
98+
$solution = DirectorySolution::fromDirectory($this->tempPath, $exclusions);
10799

108-
$this->assertSame(sprintf('%s/solution.php', $tempPath), $solution->getEntryPoint());
100+
self::assertSame('ENTRYPOINT', file_get_contents($solution->getEntryPoint()));
109101
$files = $solution->getFiles();
110-
$this->assertCount(2, $files);
102+
self::assertCount(2, $files);
111103

112-
$this->assertSame(sprintf('%s/solution.php', $tempPath), $files[0]->__toString());
113-
$this->assertSame(sprintf('%s/some-class.php', $tempPath), $files[1]->__toString());
114-
115-
unlink(sprintf('%s/solution.php', $tempPath));
116-
unlink(sprintf('%s/some-class.php', $tempPath));
117-
unlink(sprintf('%s/exclude.txt', $tempPath));
118-
rmdir($tempPath);
104+
self::assertSame('ENTRYPOINT', file_get_contents($files[0]->__toString()));
105+
self::assertSame('SOME CLASS', file_get_contents($files[1]->__toString()));
119106
}
120107

121108
public function testWithNestedDirectories(): void
122109
{
123-
$tempPath = sprintf('%s/%s', realpath(sys_get_temp_dir()), $this->getName());
124-
@mkdir($tempPath, 0775, true);
125-
126-
@mkdir(sprintf('%s/nested', $tempPath), 0775, true);
127-
@mkdir(sprintf('%s/nested/deep', $tempPath), 0775, true);
110+
@mkdir(sprintf('%s/nested', $this->tempPath), 0775, true);
111+
@mkdir(sprintf('%s/nested/deep', $this->tempPath), 0775, true);
128112

129-
touch(sprintf('%s/solution.php', $tempPath));
130-
touch(sprintf('%s/some-class.php', $tempPath));
131-
touch(sprintf('%s/composer.json', $tempPath));
132-
touch(sprintf('%s/nested/another-class.php', $tempPath));
133-
touch(sprintf('%s/nested/deep/even-more.php', $tempPath));
113+
file_put_contents(sprintf('%s/solution.php', $this->tempPath), 'ENTRYPOINT');
114+
file_put_contents(sprintf('%s/some-class.php', $this->tempPath), 'SOME CLASS');
115+
file_put_contents(sprintf('%s/composer.json', $this->tempPath), 'COMPOSER DATA');
116+
file_put_contents(sprintf('%s/nested/another-class.php', $this->tempPath), 'ANOTHER CLASS');
117+
file_put_contents(sprintf('%s/nested/deep/even-more.php', $this->tempPath), 'EVEN MOAR');
134118

135-
$solution = DirectorySolution::fromDirectory($tempPath);
119+
$solution = DirectorySolution::fromDirectory($this->tempPath);
136120

137-
$this->assertSame(sprintf('%s/solution.php', $tempPath), $solution->getEntryPoint());
121+
self::assertSame('ENTRYPOINT', file_get_contents($solution->getEntryPoint()));
138122
$files = $solution->getFiles();
139-
$this->assertCount(5, $files);
140-
141-
$this->assertSame(sprintf('%s/composer.json', $tempPath), $files[0]->__toString());
142-
$this->assertSame(sprintf('%s/nested/another-class.php', $tempPath), $files[1]->__toString());
143-
$this->assertSame(sprintf('%s/nested/deep/even-more.php', $tempPath), $files[2]->__toString());
144-
$this->assertSame(sprintf('%s/solution.php', $tempPath), $files[3]->__toString());
145-
$this->assertSame(sprintf('%s/some-class.php', $tempPath), $files[4]->__toString());
146-
147-
unlink(sprintf('%s/solution.php', $tempPath));
148-
unlink(sprintf('%s/some-class.php', $tempPath));
149-
unlink(sprintf('%s/composer.json', $tempPath));
150-
unlink(sprintf('%s/nested/another-class.php', $tempPath));
151-
unlink(sprintf('%s/nested/deep/even-more.php', $tempPath));
152-
rmdir(sprintf('%s/nested/deep', $tempPath));
153-
rmdir(sprintf('%s/nested', $tempPath));
154-
rmdir($tempPath);
123+
self::assertCount(5, $files);
124+
125+
self::assertSame('COMPOSER DATA', file_get_contents($files[0]->__toString()));
126+
self::assertSame('ANOTHER CLASS', file_get_contents($files[1]->__toString()));
127+
self::assertSame('EVEN MOAR', file_get_contents($files[2]->__toString()));
128+
self::assertSame('ENTRYPOINT', file_get_contents($files[3]->__toString()));
129+
self::assertSame('SOME CLASS', file_get_contents($files[4]->__toString()));
155130
}
156131

157132
public function testExceptionsWithNestedDirectories(): void
158133
{
159-
$tempPath = sprintf('%s/%s', realpath(sys_get_temp_dir()), $this->getName());
160-
@mkdir($tempPath, 0775, true);
161-
162-
@mkdir(sprintf('%s/nested', $tempPath), 0775, true);
163-
@mkdir(sprintf('%s/nested/deep', $tempPath), 0775, true);
164-
@mkdir(sprintf('%s/vendor', $tempPath), 0775, true);
165-
@mkdir(sprintf('%s/vendor/somelib', $tempPath), 0775, true);
166-
167-
touch(sprintf('%s/solution.php', $tempPath));
168-
touch(sprintf('%s/some-class.php', $tempPath));
169-
touch(sprintf('%s/exclude.txt', $tempPath));
170-
touch(sprintf('%s/nested/exclude.txt', $tempPath));
171-
touch(sprintf('%s/nested/deep/exclude.txt', $tempPath));
172-
touch(sprintf('%s/vendor/somelib/app.php', $tempPath));
134+
@mkdir(sprintf('%s/nested', $this->tempPath), 0775, true);
135+
@mkdir(sprintf('%s/nested/deep', $this->tempPath), 0775, true);
136+
@mkdir(sprintf('%s/vendor', $this->tempPath), 0775, true);
137+
@mkdir(sprintf('%s/vendor/somelib', $this->tempPath), 0775, true);
138+
139+
file_put_contents(sprintf('%s/solution.php', $this->tempPath), 'ENTRYPOINT');
140+
file_put_contents(sprintf('%s/some-class.php', $this->tempPath), 'SOME CLASS');
141+
touch(sprintf('%s/exclude.txt', $this->tempPath));
142+
touch(sprintf('%s/nested/exclude.txt', $this->tempPath));
143+
touch(sprintf('%s/nested/deep/exclude.txt', $this->tempPath));
144+
touch(sprintf('%s/vendor/somelib/app.php', $this->tempPath));
173145

174146
$exclusions = ['exclude.txt', 'vendor'];
175147

176-
$solution = DirectorySolution::fromDirectory($tempPath, $exclusions);
148+
$solution = DirectorySolution::fromDirectory($this->tempPath, $exclusions);
177149

178-
$this->assertSame(sprintf('%s/solution.php', $tempPath), $solution->getEntryPoint());
150+
self::assertSame('ENTRYPOINT', file_get_contents($solution->getEntryPoint()));
179151
$files = $solution->getFiles();
180-
$this->assertCount(2, $files);
181-
182-
$this->assertSame(sprintf('%s/solution.php', $tempPath), $files[0]->__toString());
183-
$this->assertSame(sprintf('%s/some-class.php', $tempPath), $files[1]->__toString());
184-
185-
unlink(sprintf('%s/solution.php', $tempPath));
186-
unlink(sprintf('%s/some-class.php', $tempPath));
187-
unlink(sprintf('%s/exclude.txt', $tempPath));
188-
unlink(sprintf('%s/nested/exclude.txt', $tempPath));
189-
unlink(sprintf('%s/nested/deep/exclude.txt', $tempPath));
190-
unlink(sprintf('%s/vendor/somelib/app.php', $tempPath));
191-
rmdir(sprintf('%s/nested/deep', $tempPath));
192-
rmdir(sprintf('%s/nested', $tempPath));
193-
rmdir(sprintf('%s/vendor/somelib', $tempPath));
194-
rmdir(sprintf('%s/vendor', $tempPath));
195-
rmdir($tempPath);
152+
self::assertCount(2, $files);
153+
154+
self::assertSame('ENTRYPOINT', file_get_contents($files[0]->__toString()));
155+
self::assertSame('SOME CLASS', file_get_contents($files[1]->__toString()));
196156
}
197157
}

0 commit comments

Comments
 (0)