Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit adaa0d2

Browse files
Introduce new class to prepare environment files
1 parent 0e24fd9 commit adaa0d2

File tree

4 files changed

+172
-0
lines changed

4 files changed

+172
-0
lines changed

‎app/config.php‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@
186186
EventDispatcher::class => factory(EventDispatcherFactory::class),
187187
EventDispatcherFactory::class => create(),
188188

189+
EnvironmentManager::class => function (ContainerInterface $c) {
190+
return new EnvironmentManager($c->get(Filesystem::class), $c->get(EventDispatcher::class));
191+
},
192+
189193
//Exercise Runners
190194
RunnerManager::class => function (ContainerInterface $c) {
191195
$manager = new RunnerManager();
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshop\ExerciseRunner;
4+
5+
use PhpSchool\PhpWorkshop\Event\EventDispatcher;
6+
use PhpSchool\PhpWorkshop\Exercise\ProvidesSolution;
7+
use PhpSchool\PhpWorkshop\Exercise\Scenario\ExerciseScenario;
8+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext;
9+
use PhpSchool\PhpWorkshop\Utils\Path;
10+
use Symfony\Component\Filesystem\Filesystem;
11+
12+
class EnvironmentManager
13+
{
14+
public function __construct(private Filesystem $filesystem, private EventDispatcher $eventDispatcher)
15+
{
16+
}
17+
18+
public function prepareStudent(ExecutionContext $context, ExerciseScenario $scenario): void
19+
{
20+
$this->copyExerciseFiles($scenario, $context->getStudentExecutionDirectory());
21+
22+
//cleanup the files when the run or verification process is finished
23+
//we do this at late as possible in case any checks or other event listeners need to access the files
24+
$this->eventDispatcher->listen(['run.finish', 'verify.finish'], function () use ($context, $scenario) {
25+
foreach ($scenario->getFiles() as $fileName => $content) {
26+
$this->filesystem->remove(Path::join($context->getStudentExecutionDirectory(), $fileName));
27+
}
28+
});
29+
}
30+
31+
public function prepareReference(ExecutionContext $context, ExerciseScenario $scenario): void
32+
{
33+
$exercise = $context->getExercise();
34+
35+
if (!$exercise instanceof ProvidesSolution) {
36+
return;
37+
}
38+
39+
$this->filesystem->mkdir($context->getReferenceExecutionDirectory());
40+
41+
$solution = $exercise->getSolution();
42+
43+
foreach ($solution->getFiles() as $file) {
44+
$this->filesystem->copy(
45+
$file->getAbsolutePath(),
46+
Path::join($context->getReferenceExecutionDirectory(), $file->getRelativePath())
47+
);
48+
}
49+
50+
$this->copyExerciseFiles($scenario, $context->getReferenceExecutionDirectory());
51+
52+
//cleanup the files when the run or verification process is finished
53+
//we do this at late as possible in case any checks or other event listeners need to access the files
54+
$this->eventDispatcher->listen(['run.finish', 'verify.finish'], function () use ($context) {
55+
$this->filesystem->remove($context->getReferenceExecutionDirectory());
56+
});
57+
}
58+
59+
private function copyExerciseFiles(ExerciseScenario $scenario, string $dir): void
60+
{
61+
foreach ($scenario->getFiles() as $fileName => $content) {
62+
$this->filesystem->dumpFile(
63+
Path::join($dir, $fileName),
64+
$content
65+
);
66+
}
67+
}
68+
}

‎src/Listener/CodePatchListener.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ public function revert(EventInterface $event): void
8888

8989
foreach ($this->originalCode as $fileName => $contents) {
9090
file_put_contents($fileName, $contents);
91+
unset($this->originalCode[$fileName]);
9192
}
9293
}
9394
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshopTest\ExerciseRunner;
4+
5+
use PhpSchool\PhpWorkshop\Event\EventDispatcher;
6+
use PhpSchool\PhpWorkshop\Event\ExerciseRunnerEvent;
7+
use PhpSchool\PhpWorkshop\Exercise\MockExercise;
8+
use PhpSchool\PhpWorkshop\Exercise\Scenario\CliScenario;
9+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext;
10+
use PhpSchool\PhpWorkshop\ExerciseRunner\EnvironmentManager;
11+
use PhpSchool\PhpWorkshop\Input\Input;
12+
use PhpSchool\PhpWorkshop\ResultAggregator;
13+
use PhpSchool\PhpWorkshop\Solution\DirectorySolution;
14+
use PhpSchool\PhpWorkshop\Solution\SingleFileSolution;
15+
use PhpSchool\PhpWorkshopTest\Asset\CliExerciseImpl;
16+
use PHPUnit\Framework\TestCase;
17+
use Symfony\Component\Filesystem\Filesystem;
18+
19+
class EnvironmentManagerTest extends TestCase
20+
{
21+
public function testPrepareStudentCopiesAllScenarioFilesToExecutionDirectory(): void
22+
{
23+
$context = new TestContext();
24+
$context->createStudentSolutionDirectory();
25+
26+
$scenario = (new CliScenario())
27+
->withFile('file.txt', 'content')
28+
->withFile('file2.txt', 'content2');
29+
30+
$manager = new EnvironmentManager(new Filesystem(), new EventDispatcher(new ResultAggregator()));
31+
$manager->prepareStudent($context, $scenario);
32+
33+
static::assertStringEqualsFile($context->getStudentExecutionDirectory() . '/file.txt', 'content');
34+
static::assertStringEqualsFile($context->getStudentExecutionDirectory() . '/file2.txt', 'content2');
35+
}
36+
37+
public function testPrepareReferenceCopiesAllScenarioFilesAndSolutionFilesToExecutionDirectory(): void
38+
{
39+
$exercise = new CliExerciseImpl();
40+
$solution = SingleFileSolution::fromFile(realpath(__DIR__ . '/../res/cli/solution.php'));
41+
$exercise->setSolution($solution);
42+
43+
$context = new TestContext($exercise);
44+
45+
$scenario = (new CliScenario())
46+
->withFile('file.txt', 'content')
47+
->withFile('file2.txt', 'content2');
48+
49+
$manager = new EnvironmentManager(new Filesystem(), new EventDispatcher(new ResultAggregator()));
50+
$manager->prepareReference($context, $scenario);
51+
52+
static::assertFileEquals($context->getReferenceExecutionDirectory() . '/solution.php', __DIR__ . '/../res/cli/solution.php');
53+
static::assertStringEqualsFile($context->getReferenceExecutionDirectory() . '/file.txt', 'content');
54+
static::assertStringEqualsFile($context->getReferenceExecutionDirectory() . '/file2.txt', 'content2');
55+
}
56+
57+
/**
58+
* @dataProvider finishEvents
59+
*/
60+
public function testFileAreCleanedUpOnlyWhenFinishEventIsDispatched(string $eventName): void
61+
{
62+
$exercise = new CliExerciseImpl();
63+
$solution = SingleFileSolution::fromFile(realpath(__DIR__ . '/../res/cli/solution.php'));
64+
$exercise->setSolution($solution);
65+
66+
$context = new TestContext($exercise);
67+
$context->createStudentSolutionDirectory();
68+
69+
$scenario = (new CliScenario())
70+
->withFile('file.txt', 'content')
71+
->withFile('file2.txt', 'content2');
72+
73+
$eventDispatcher = new EventDispatcher(new ResultAggregator());
74+
$manager = new EnvironmentManager(new Filesystem(), $eventDispatcher);
75+
$manager->prepareStudent($context, $scenario);
76+
$manager->prepareReference($context, $scenario);
77+
78+
static::assertFileExists($context->getStudentExecutionDirectory());
79+
static::assertFileExists($context->getReferenceExecutionDirectory());
80+
81+
$eventDispatcher->dispatch(new ExerciseRunnerEvent($eventName, $exercise, new Input('app', ['program' => ''])));
82+
83+
static::assertFileExists($context->getStudentExecutionDirectory());
84+
static::assertFileNotExists($context->getReferenceExecutionDirectory() . '/file.txt');
85+
static::assertFileNotExists($context->getReferenceExecutionDirectory() . '/file2.txt');
86+
static::assertFileNotExists($context->getReferenceExecutionDirectory());
87+
}
88+
89+
/**
90+
* @return array<array{0: string}>
91+
*/
92+
public function finishEvents(): array
93+
{
94+
return [
95+
['run.finish'],
96+
['verify.finish'],
97+
];
98+
}
99+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /