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 5c95d08

Browse files
Context
1 parent be53db0 commit 5c95d08

File tree

9 files changed

+423
-0
lines changed

9 files changed

+423
-0
lines changed

‎src/Exercise/MockExercise.php‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshop\Exercise;
4+
5+
use PhpSchool\PhpWorkshop\ExerciseDispatcher;
6+
7+
class MockExercise extends AbstractExercise implements ExerciseInterface
8+
{
9+
public function getName(): string
10+
{
11+
return 'Mock Exercise';
12+
}
13+
14+
public function getDescription(): string
15+
{
16+
return 'Mock Exercise';
17+
}
18+
19+
public function getType(): ExerciseType
20+
{
21+
return ExerciseType::CUSTOM();
22+
}
23+
24+
public function getProblem(): string
25+
{
26+
return 'problem-file.md';
27+
}
28+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshop\ExerciseRunner\Context;
4+
5+
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
6+
use PhpSchool\PhpWorkshop\Input\Input;
7+
use PhpSchool\PhpWorkshop\Utils\Path;
8+
use PhpSchool\PhpWorkshop\Utils\System;
9+
10+
class ExecutionContext
11+
{
12+
public function __construct(
13+
private string $studentExecutionDirectory,
14+
private string $referenceExecutionDirectory,
15+
private ExerciseInterface $exercise,
16+
private Input $input,
17+
) {
18+
}
19+
20+
public function getExercise(): ExerciseInterface
21+
{
22+
return $this->exercise;
23+
}
24+
25+
public function getInput(): Input
26+
{
27+
return $this->input;
28+
}
29+
30+
public function hasStudentSolution(): bool
31+
{
32+
return $this->input->hasArgument('program');
33+
}
34+
35+
public function getEntryPoint(): string
36+
{
37+
if (!$this->hasStudentSolution()) {
38+
throw new NoEntryPoint();
39+
}
40+
41+
return Path::join(
42+
$this->studentExecutionDirectory,
43+
basename($this->input->getRequiredArgument('program'))
44+
);
45+
}
46+
47+
public function getStudentExecutionDirectory(): string
48+
{
49+
return $this->studentExecutionDirectory;
50+
}
51+
52+
public function getReferenceExecutionDirectory(): string
53+
{
54+
return $this->referenceExecutionDirectory;
55+
}
56+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshop\ExerciseRunner\Context;
4+
5+
use PhpSchool\PhpWorkshop\Exception\RuntimeException;
6+
7+
class NoEntryPoint extends RuntimeException
8+
{
9+
public function __construct()
10+
{
11+
parent::__construct('No entry point provided');
12+
}
13+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshop\ExerciseRunner\Context;
4+
5+
use PhpSchool\PhpWorkshop\Exception\RuntimeException;
6+
use PhpSchool\PhpWorkshop\Exercise\CgiExercise;
7+
use PhpSchool\PhpWorkshop\Exercise\CliExercise;
8+
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
9+
use PhpSchool\PhpWorkshop\Exercise\MockExercise;
10+
use PhpSchool\PhpWorkshop\Input\Input;
11+
use PhpSchool\PhpWorkshop\Solution\SolutionInterface;
12+
use PhpSchool\PhpWorkshop\Utils\System;
13+
use Symfony\Component\Filesystem\Filesystem;
14+
use PhpSchool\PhpWorkshop\Utils\Path;
15+
16+
class TestContext extends ExecutionContext
17+
{
18+
private Filesystem $filesystem;
19+
private ExerciseInterface $exercise;
20+
private bool $studentSolutionDirWasCreated = false;
21+
private bool $referenceSolutionDirWasCreated = false;
22+
23+
public function __construct(
24+
ExerciseInterface $exercise = null,
25+
Input $input = null,
26+
string $studentDirectory = null,
27+
) {
28+
$this->exercise = $exercise ?? new MockExercise();
29+
30+
$this->filesystem = new Filesystem();
31+
32+
if ($studentDirectory === null) {
33+
$studentDirectory = System::randomTempDir();
34+
}
35+
36+
parent::__construct(
37+
$studentDirectory,
38+
System::randomTempDir(),
39+
$this->exercise,
40+
$input ? $input : new Input('test', ['program' => 'solution.php']),
41+
);
42+
}
43+
44+
public function createStudentSolutionDirectory(): void
45+
{
46+
$this->filesystem->mkdir($this->getStudentExecutionDirectory());
47+
$this->studentSolutionDirWasCreated = true;
48+
}
49+
50+
public function createReferenceSolutionDirectory(): void
51+
{
52+
$this->filesystem->mkdir($this->getReferenceExecutionDirectory());
53+
$this->referenceSolutionDirWasCreated = true;
54+
}
55+
56+
public function importStudentFileFromString(string $content, string $filename = 'solution.php'): void
57+
{
58+
if (!$this->studentSolutionDirWasCreated) {
59+
throw new RuntimeException(
60+
sprintf('Student execution directory not created. Call %s::createStudentSolutionDirectory() first.', self::class)
61+
);
62+
}
63+
64+
file_put_contents(Path::join($this->getStudentExecutionDirectory(), $filename), $content);
65+
}
66+
67+
public function importReferenceFileFromString(string $content, string $filename = 'solution.php'): void
68+
{
69+
if (!$this->referenceSolutionDirWasCreated) {
70+
throw new RuntimeException(
71+
sprintf('Reference execution directory not created. Call %s::createReferenceSolutionDirectory() first.', self::class)
72+
);
73+
}
74+
75+
file_put_contents(Path::join($this->getReferenceExecutionDirectory(), $filename), $content);
76+
}
77+
78+
public static function fromExerciseAndStudentSolution(ExerciseInterface $exercise, string $file): self
79+
{
80+
if (file_exists($file)) {
81+
$file = (string) realpath($file);
82+
}
83+
84+
$input = new Input('test', ['program' => $file]);
85+
return new self(
86+
exercise: $exercise,
87+
input: $input,
88+
studentDirectory: dirname($file)
89+
);
90+
}
91+
92+
public function __destruct()
93+
{
94+
if ($this->studentSolutionDirWasCreated) {
95+
$this->filesystem->remove($this->getStudentExecutionDirectory());
96+
}
97+
98+
if ($this->referenceSolutionDirWasCreated) {
99+
$this->filesystem->remove($this->getReferenceExecutionDirectory());
100+
}
101+
}
102+
}

‎src/Utils/System.php‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,9 @@ public static function tempDir(string $path = ''): string
2323
{
2424
return Path::join(self::realpath(sys_get_temp_dir()), 'php-school', $path);
2525
}
26+
27+
public static function randomTempDir(): string
28+
{
29+
return Path::join(self::realpath(sys_get_temp_dir()), 'php-school', bin2hex(random_bytes(4)));
30+
}
2631
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshopTest\ExerciseRunner\Context;
4+
5+
use PhpSchool\PhpWorkshop\Exercise\MockExercise;
6+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext;
7+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\NoEntryPoint;
8+
use PhpSchool\PhpWorkshop\Input\Input;
9+
use PHPUnit\Framework\TestCase;
10+
11+
class ExecutionContextTest extends TestCase
12+
{
13+
public function testGetters(): void
14+
{
15+
$exercise = new MockExercise();
16+
$input = new Input('test', ['program' => 'solution.php']);
17+
$context = new ExecutionContext(
18+
'/student-dir',
19+
'/reference-dir',
20+
$exercise,
21+
$input
22+
);
23+
24+
static::assertSame($exercise, $context->getExercise());
25+
static::assertSame($input, $context->getInput());
26+
static::assertSame('/student-dir', $context->getStudentExecutionDirectory());
27+
static::assertSame('/reference-dir', $context->getReferenceExecutionDirectory());
28+
}
29+
30+
public function testHasStudentSolution(): void
31+
{
32+
$exercise = new MockExercise();
33+
$input = new Input('test', ['program' => 'solution.php']);
34+
$context = new ExecutionContext(
35+
'/student-dir',
36+
'/reference-dir',
37+
$exercise,
38+
$input
39+
);
40+
41+
static::assertTrue($context->hasStudentSolution());
42+
43+
$exercise = new MockExercise();
44+
$input = new Input('test');
45+
$context = new ExecutionContext(
46+
'/student-dir',
47+
'/reference-dir',
48+
$exercise,
49+
$input
50+
);
51+
52+
static::assertFalse($context->hasStudentSolution());
53+
}
54+
55+
public function testGetEntryPoint(): void
56+
{
57+
$exercise = new MockExercise();
58+
$input = new Input('test', ['program' => 'solution.php']);
59+
$context = new ExecutionContext(
60+
'/student-dir',
61+
'/reference-dir',
62+
$exercise,
63+
$input
64+
);
65+
66+
static::assertSame('/student-dir/solution.php', $context->getEntryPoint());
67+
}
68+
69+
public function testGetEntryPointThrowsExceptionWhenNoStudentSolution(): void
70+
{
71+
static::expectException(NoEntryPoint::class);
72+
73+
$exercise = new MockExercise();
74+
$input = new Input('test');
75+
$context = new ExecutionContext(
76+
'/student-dir',
77+
'/reference-dir',
78+
$exercise,
79+
$input
80+
);
81+
82+
$context->getEntryPoint();
83+
}
84+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshopTest\ExerciseRunner\Context;
4+
5+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\NoEntryPoint;
6+
use PHPUnit\Framework\TestCase;
7+
8+
class NoEntryPointTest extends TestCase
9+
{
10+
public function testException(): void
11+
{
12+
$e = new NoEntryPoint();
13+
static::assertSame('No entry point provided', $e->getMessage());
14+
}
15+
}

0 commit comments

Comments
(0)

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