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 15563cf

Browse files
Context
1 parent b0ca966 commit 15563cf

File tree

9 files changed

+453
-0
lines changed

9 files changed

+453
-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: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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 static function fromInputAndExercise(Input $input, ExerciseInterface $exercise): ExecutionContext
21+
{
22+
$program = $input->hasArgument('program') ? dirname($input->getRequiredArgument('program')) : (string) getcwd();
23+
24+
return new self(
25+
$program,
26+
System::randomTempDir(),
27+
$exercise,
28+
$input
29+
);
30+
}
31+
32+
public function getExercise(): ExerciseInterface
33+
{
34+
return $this->exercise;
35+
}
36+
37+
public function getInput(): Input
38+
{
39+
return $this->input;
40+
}
41+
42+
public function hasStudentSolution(): bool
43+
{
44+
return $this->input->hasArgument('program');
45+
}
46+
47+
public function getEntryPoint(): string
48+
{
49+
if (!$this->hasStudentSolution()) {
50+
throw new NoEntryPoint();
51+
}
52+
53+
return Path::join(
54+
$this->studentExecutionDirectory,
55+
basename($this->input->getRequiredArgument('program'))
56+
);
57+
}
58+
59+
public function getStudentExecutionDirectory(): string
60+
{
61+
return $this->studentExecutionDirectory;
62+
}
63+
64+
public function getReferenceExecutionDirectory(): string
65+
{
66+
return $this->referenceExecutionDirectory;
67+
}
68+
}
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: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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 PhpSchool\PhpWorkshop\Utils\System;
10+
use PHPUnit\Framework\TestCase;
11+
12+
class ExecutionContextTest extends TestCase
13+
{
14+
public function testGetters(): void
15+
{
16+
$exercise = new MockExercise();
17+
$input = new Input('test', ['program' => 'solution.php']);
18+
$context = new ExecutionContext(
19+
'/student-dir',
20+
'/reference-dir',
21+
$exercise,
22+
$input
23+
);
24+
25+
static::assertSame($exercise, $context->getExercise());
26+
static::assertSame($input, $context->getInput());
27+
static::assertSame('/student-dir', $context->getStudentExecutionDirectory());
28+
static::assertSame('/reference-dir', $context->getReferenceExecutionDirectory());
29+
}
30+
31+
public function testHasStudentSolution(): void
32+
{
33+
$exercise = new MockExercise();
34+
$input = new Input('test', ['program' => 'solution.php']);
35+
$context = new ExecutionContext(
36+
'/student-dir',
37+
'/reference-dir',
38+
$exercise,
39+
$input
40+
);
41+
42+
static::assertTrue($context->hasStudentSolution());
43+
44+
$exercise = new MockExercise();
45+
$input = new Input('test');
46+
$context = new ExecutionContext(
47+
'/student-dir',
48+
'/reference-dir',
49+
$exercise,
50+
$input
51+
);
52+
53+
static::assertFalse($context->hasStudentSolution());
54+
}
55+
56+
public function testGetEntryPoint(): void
57+
{
58+
$exercise = new MockExercise();
59+
$input = new Input('test', ['program' => 'solution.php']);
60+
$context = new ExecutionContext(
61+
'/student-dir',
62+
'/reference-dir',
63+
$exercise,
64+
$input
65+
);
66+
67+
static::assertSame('/student-dir/solution.php', $context->getEntryPoint());
68+
}
69+
70+
public function testGetEntryPointThrowsExceptionWhenNoStudentSolution(): void
71+
{
72+
static::expectException(NoEntryPoint::class);
73+
74+
$exercise = new MockExercise();
75+
$input = new Input('test');
76+
$context = new ExecutionContext(
77+
'/student-dir',
78+
'/reference-dir',
79+
$exercise,
80+
$input
81+
);
82+
83+
$context->getEntryPoint();
84+
}
85+
86+
public function testFactory(): void
87+
{
88+
$temporaryDirectory = System::randomTempDir();
89+
90+
$input = new Input('test', ['program' => $temporaryDirectory . '/solution.php']);
91+
$exercise = new MockExercise();
92+
93+
$context = ExecutionContext::fromInputAndExercise($input, $exercise);
94+
95+
//check that student execution directory uses the parent directory of the program from the input
96+
static::assertSame($temporaryDirectory, $context->getStudentExecutionDirectory());
97+
static::assertSame($temporaryDirectory . '/solution.php', $context->getEntryPoint());
98+
99+
//check that reference execution directory is a random temporary directory
100+
static::assertTrue(str_starts_with($context->getReferenceExecutionDirectory(), System::tempDir()));
101+
}
102+
}
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 によって変換されたページ (->オリジナル) /