Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c9891c8

Browse files
committedMay 11, 2024
Use context in checks
1 parent 894c35a commit c9891c8

18 files changed

+240
-301
lines changed
 

‎src/Check/CodeExistsCheck.php

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,16 @@
1111
use PhpParser\Parser;
1212
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
1313
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
14+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext;
1415
use PhpSchool\PhpWorkshop\Input\Input;
1516
use PhpSchool\PhpWorkshop\Result\Failure;
1617
use PhpSchool\PhpWorkshop\Result\ResultInterface;
1718
use PhpSchool\PhpWorkshop\Result\Success;
1819

1920
class CodeExistsCheck implements SimpleCheckInterface
2021
{
21-
/**
22-
* @var Parser
23-
*/
24-
private $parser;
25-
26-
public function __construct(Parser $parser)
22+
public function __construct(private Parser $parser)
2723
{
28-
$this->parser = $parser;
2924
}
3025

3126
public function getName(): string
@@ -34,18 +29,20 @@ public function getName(): string
3429
}
3530

3631
/**
32+
* @param ExecutionContext $context The current execution context, containing the exercise, input and working directories.
33+
*
3734
* Check solution provided contains code
3835
* Note: We don't care if it's valid code at this point
3936
*/
40-
public function check(ExerciseInterface $exercise, Input $input): ResultInterface
37+
public function check(ExecutionContext $context): ResultInterface
4138
{
4239
$noopHandler = new class implements ErrorHandler {
4340
public function handleError(Error $error): void
4441
{
4542
}
4643
};
4744

48-
$code = (string) file_get_contents($input->getRequiredArgument('program'));
45+
$code = (string) file_get_contents($context->getEntryPoint());
4946
$statements = $this->parser->parse($code, $noopHandler);
5047

5148
$empty = null === $statements || empty($statements);

‎src/Check/CodeParseCheck.php

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PhpParser\Parser;
99
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
1010
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
11+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext;
1112
use PhpSchool\PhpWorkshop\Input\Input;
1213
use PhpSchool\PhpWorkshop\Result\Failure;
1314
use PhpSchool\PhpWorkshop\Result\ResultInterface;
@@ -19,17 +20,8 @@
1920
*/
2021
class CodeParseCheck implements SimpleCheckInterface
2122
{
22-
/**
23-
* @var Parser
24-
*/
25-
private $parser;
26-
27-
/**
28-
* @param Parser $parser
29-
*/
30-
public function __construct(Parser $parser)
23+
public function __construct(private Parser $parser)
3124
{
32-
$this->parser = $parser;
3325
}
3426

3527
/**
@@ -45,18 +37,17 @@ public function getName(): string
4537
* attempts to parse it with `nikic/php-parser`. If any exceptions are thrown
4638
* by the parser, it is treated as a failure.
4739
*
48-
* @param ExerciseInterface $exercise The exercise to check against.
49-
* @param Input $input The command line arguments passed to the command.
40+
* @param ExecutionContext $context The current execution context, containing the exercise, input and working directories.
5041
* @return ResultInterface The result of the check.
5142
*/
52-
public function check(ExerciseInterface $exercise, Input $input): ResultInterface
43+
public function check(ExecutionContext $context): ResultInterface
5344
{
54-
$code = (string) file_get_contents($input->getRequiredArgument('program'));
45+
$code = (string) file_get_contents($context->getEntryPoint());
5546

5647
try {
5748
$this->parser->parse($code);
5849
} catch (Error $e) {
59-
return Failure::fromCheckAndCodeParseFailure($this, $e, $input->getRequiredArgument('program'));
50+
return Failure::fromCheckAndCodeParseFailure($this, $e, $context->getEntryPoint());
6051
}
6152

6253
return Success::fromCheck($this);

‎src/Check/ComposerCheck.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
1010
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
1111
use PhpSchool\PhpWorkshop\ExerciseCheck\ComposerExerciseCheck;
12+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext;
1213
use PhpSchool\PhpWorkshop\Input\Input;
1314
use PhpSchool\PhpWorkshop\Result\ComposerFailure;
1415
use PhpSchool\PhpWorkshop\Result\Failure;
@@ -34,30 +35,29 @@ public function getName(): string
3435
* installed a set of required packages. If they did not a failure is returned, otherwise,
3536
* a success is returned.
3637
*
37-
* @param ExerciseInterface $exercise The exercise to check against.
38-
* @param Input $input The command line arguments passed to the command.
38+
* @param ExecutionContext $context The current execution context, containing the exercise, input and working directories.
3939
* @return ResultInterface The result of the check.
40-
* @noinspection SpellCheckingInspection
4140
*/
42-
public function check(ExerciseInterface $exercise, Input $input): ResultInterface
41+
public function check(ExecutionContext $context): ResultInterface
4342
{
43+
$exercise = $context->getExercise();
4444
if (!$exercise instanceof ComposerExerciseCheck) {
4545
throw new InvalidArgumentException();
4646
}
4747

48-
if (!file_exists(sprintf('%s/composer.json', dirname($input->getRequiredArgument('program'))))) {
48+
if (!file_exists(sprintf('%s/composer.json', $context->getStudentExecutionDirectory()))) {
4949
return ComposerFailure::fromCheckAndMissingFileOrFolder($this, 'composer.json');
5050
}
5151

52-
if (!file_exists(sprintf('%s/composer.lock', dirname($input->getRequiredArgument('program'))))) {
52+
if (!file_exists(sprintf('%s/composer.lock', $context->getStudentExecutionDirectory()))) {
5353
return ComposerFailure::fromCheckAndMissingFileOrFolder($this, 'composer.lock');
5454
}
5555

56-
if (!file_exists(sprintf('%s/vendor', dirname($input->getRequiredArgument('program'))))) {
56+
if (!file_exists(sprintf('%s/vendor', $context->getStudentExecutionDirectory()))) {
5757
return ComposerFailure::fromCheckAndMissingFileOrFolder($this, 'vendor');
5858
}
5959

60-
$lockFile = new LockFileParser(sprintf('%s/composer.lock', dirname($input->getRequiredArgument('program'))));
60+
$lockFile = new LockFileParser(sprintf('%s/composer.lock', $context->getStudentExecutionDirectory()));
6161
$missingPackages = array_filter($exercise->getRequiredPackages(), function ($package) use ($lockFile) {
6262
return !$lockFile->hasInstalledPackage($package);
6363
});

‎src/Check/DatabaseCheck.php

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,30 +25,11 @@ class DatabaseCheck implements ListenableCheckInterface
2525
{
2626
use TemporaryDirectoryTrait;
2727

28-
/**
29-
* @var string
30-
*/
31-
private $databaseDirectory;
32-
33-
/**
34-
* @var string
35-
*/
36-
private $userDatabasePath;
37-
38-
/**
39-
* @var string
40-
*/
41-
private $solutionDatabasePath;
42-
43-
/**
44-
* @var string
45-
*/
46-
private $userDsn;
47-
48-
/**
49-
* @var string
50-
*/
51-
private $solutionDsn;
28+
private string $databaseDirectory;
29+
private string $userDatabasePath;
30+
private string $solutionDatabasePath;
31+
private string $userDsn;
32+
private string $solutionDsn;
5233

5334
/**
5435
* Setup paths and DSN's.

‎src/Check/FileComparisonCheck.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
1111
use PhpSchool\PhpWorkshop\Exercise\ProvidesSolution;
1212
use PhpSchool\PhpWorkshop\ExerciseCheck\FileComparisonExerciseCheck;
13+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext;
1314
use PhpSchool\PhpWorkshop\Input\Input;
1415
use PhpSchool\PhpWorkshop\Result\Failure;
1516
use PhpSchool\PhpWorkshop\Result\FileComparisonFailure;
@@ -34,21 +35,21 @@ public function getName(): string
3435
/**
3536
* Simply check that the file exists.
3637
*
37-
* @param ExerciseInterface&ProvidesSolution $exercise The exercise to check against.
38-
* @param Input $input The command line arguments passed to the command.
38+
* @param ExecutionContext $context The current execution context, containing the exercise, input and working directories.
3939
* @return ResultInterface The result of the check.
4040
*/
41-
public function check(ExerciseInterface $exercise, Input $input): ResultInterface
41+
public function check(ExecutionContext $context): ResultInterface
4242
{
43+
$exercise = $context->getExercise();
4344
if (!$exercise instanceof FileComparisonExerciseCheck) {
4445
throw new InvalidArgumentException();
4546
}
4647

4748
foreach ($exercise->getFilesToCompare() as $key => $file) {
4849
[$options, $file] = $this->getOptionsAndFile($key, $file);
4950

50-
$studentFile = Path::join(dirname($input->getRequiredArgument('program')), $file);
51-
$referenceFile = Path::join($exercise->getSolution()->getBaseDirectory(), $file);
51+
$studentFile = Path::join($context->getStudentExecutionDirectory(), $file);
52+
$referenceFile = Path::join($context->getReferenceExecutionDirectory(), $file);
5253

5354
if (!file_exists($referenceFile)) {
5455
throw SolutionFileDoesNotExistException::fromExpectedFile($file);

‎src/Check/FileExistsCheck.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
88
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
9+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext;
910
use PhpSchool\PhpWorkshop\Input\Input;
1011
use PhpSchool\PhpWorkshop\Result\Failure;
1112
use PhpSchool\PhpWorkshop\Result\ResultInterface;
@@ -27,19 +28,18 @@ public function getName(): string
2728
/**
2829
* Simply check that the file exists.
2930
*
30-
* @param ExerciseInterface $exercise The exercise to check against.
31-
* @param Input $input The command line arguments passed to the command.
31+
* @param ExecutionContext $context The current execution context, containing the exercise, input and working directories.
3232
* @return ResultInterface The result of the check.
3333
*/
34-
public function check(ExerciseInterface $exercise, Input $input): ResultInterface
34+
public function check(ExecutionContext $context): ResultInterface
3535
{
36-
if (file_exists($input->getRequiredArgument('program'))) {
36+
if (file_exists($context->getEntryPoint())) {
3737
return Success::fromCheck($this);
3838
}
3939

4040
return Failure::fromCheckAndReason(
4141
$this,
42-
sprintf('File: "%s" does not exist', $input->getRequiredArgument('program'))
42+
sprintf('File: "%s" does not exist', $context->getEntryPoint())
4343
);
4444
}
4545

‎src/Check/FunctionRequirementsCheck.php

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
1313
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
1414
use PhpSchool\PhpWorkshop\ExerciseCheck\FunctionRequirementsExerciseCheck;
15+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext;
1516
use PhpSchool\PhpWorkshop\Input\Input;
1617
use PhpSchool\PhpWorkshop\NodeVisitor\FunctionVisitor;
1718
use PhpSchool\PhpWorkshop\Result\Failure;
@@ -25,17 +26,8 @@
2526
*/
2627
class FunctionRequirementsCheck implements SimpleCheckInterface
2728
{
28-
/**
29-
* @var Parser
30-
*/
31-
private $parser;
32-
33-
/**
34-
* @param Parser $parser
35-
*/
36-
public function __construct(Parser $parser)
29+
public function __construct(private Parser $parser)
3730
{
38-
$this->parser = $parser;
3931
}
4032

4133
/**
@@ -51,25 +43,25 @@ public function getName(): string
5143
* required functions and that banned functions are not used. The requirements
5244
* are pulled from the exercise.
5345
*
54-
* @param ExerciseInterface $exercise The exercise to check against.
55-
* @param Input $input The command line arguments passed to the command.
46+
* @param ExecutionContext $context The current execution context, containing the exercise, input and working directories.
5647
* @return ResultInterface The result of the check.
5748
*/
58-
public function check(ExerciseInterface $exercise, Input $input): ResultInterface
49+
public function check(ExecutionContext $context): ResultInterface
5950
{
51+
$exercise = $context->getExercise();
6052
if (!$exercise instanceof FunctionRequirementsExerciseCheck) {
6153
throw new InvalidArgumentException();
6254
}
6355

6456
$requiredFunctions = $exercise->getRequiredFunctions();
6557
$bannedFunctions = $exercise->getBannedFunctions();
6658

67-
$code = (string) file_get_contents($input->getRequiredArgument('program'));
59+
$code = (string) file_get_contents($context->getEntryPoint());
6860

6961
try {
7062
$ast = $this->parser->parse($code) ?? [];
7163
} catch (Error $e) {
72-
return Failure::fromCheckAndCodeParseFailure($this, $e, $input->getRequiredArgument('program'));
64+
return Failure::fromCheckAndCodeParseFailure($this, $e, $context->getEntryPoint());
7365
}
7466

7567
$visitor = new FunctionVisitor($requiredFunctions, $bannedFunctions);

‎src/Check/PhpLintCheck.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
88
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
9+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext;
910
use PhpSchool\PhpWorkshop\Input\Input;
1011
use PhpSchool\PhpWorkshop\Result\ResultInterface;
1112
use PhpSchool\PhpWorkshop\Result\Success;
@@ -30,14 +31,13 @@ public function getName(): string
3031
/**
3132
* Simply check the student's solution can be linted with `php -l`.
3233
*
33-
* @param ExerciseInterface $exercise The exercise to check against.
34-
* @param Input $input The command line arguments passed to the command.
34+
* @param ExecutionContext $context The current execution context, containing the exercise, input and working directories.
3535
* @return ResultInterface The result of the check.
3636
*/
37-
public function check(ExerciseInterface $exercise, Input $input): ResultInterface
37+
public function check(ExecutionContext $context): ResultInterface
3838
{
3939
$finder = new ExecutableFinder();
40-
$process = new Process([$finder->find('php'), '-l', $input->getArgument('program')]);
40+
$process = new Process([$finder->find('php'), '-l', $context->getEntryPoint()]);
4141
$process->run();
4242

4343
if ($process->isSuccessful()) {

‎src/Check/SimpleCheckInterface.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
88
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
9+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext;
910
use PhpSchool\PhpWorkshop\Input\Input;
1011
use PhpSchool\PhpWorkshop\Result\ResultInterface;
1112

@@ -46,11 +47,10 @@ public function canRun(ExerciseType $exerciseType): bool;
4647
* successful then an instance of `PhpSchool\PhpWorkshop\Result\FailureInterface`
4748
* should be returned.
4849
*
49-
* @param ExerciseInterface $exercise The exercise to check against.
50-
* @param Input $input The command line arguments passed to the command.
50+
* @param ExecutionContext $context The current execution context, containing the exercise, input and working directories.
5151
* @return ResultInterface The result of the check.
5252
*/
53-
public function check(ExerciseInterface $exercise, Input $input): ResultInterface;
53+
public function check(ExecutionContext $context): ResultInterface;
5454

5555
/**
5656
* Either `static::CHECK_BEFORE` | `static::CHECK_AFTER`.

‎src/ExerciseDispatcher.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public function verify(ExerciseInterface $exercise, Input $input): ResultAggrega
123123
$this->validateChecks($this->checksToRunAfter, $exercise);
124124

125125
foreach ($this->checksToRunBefore as $check) {
126-
$this->results->add($check->check($context->getExercise(), $context->getInput()));
126+
$this->results->add($check->check($context));
127127

128128
if (!$this->results->isSuccessful()) {
129129
return $this->results;
@@ -139,7 +139,7 @@ public function verify(ExerciseInterface $exercise, Input $input): ResultAggrega
139139
}
140140

141141
foreach ($this->checksToRunAfter as $check) {
142-
$this->results->add($check->check($context->getExercise(), $context->getInput()));
142+
$this->results->add($check->check($context));
143143
}
144144

145145
$this->eventDispatcher->dispatch(new ExerciseRunnerEvent('verify.post.check', $exercise, $input));
@@ -167,7 +167,7 @@ public function run(ExerciseInterface $exercise, Input $input, OutputInterface $
167167

168168
/** @var PhpLintCheck $lint */
169169
$lint = $this->checkRepository->getByClass(PhpLintCheck::class);
170-
$result = $lint->check($context->getExercise(), $context->getInput());
170+
$result = $lint->check($context);
171171

172172
if ($result instanceof FailureInterface) {
173173
throw CouldNotRunException::fromFailure($result);

‎test/Check/CodeExistsCheckTest.php

Lines changed: 16 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,81 +6,55 @@
66
use PhpSchool\PhpWorkshop\Check\CodeExistsCheck;
77
use PhpSchool\PhpWorkshop\Check\SimpleCheckInterface;
88
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
9+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext;
910
use PhpSchool\PhpWorkshop\Input\Input;
11+
use PhpSchool\PhpWorkshopTest\BaseTest;
1012
use PHPUnit\Framework\TestCase;
1113
use PhpSchool\PhpWorkshop\Check\FileExistsCheck;
1214
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
1315
use PhpSchool\PhpWorkshop\Result\Failure;
1416
use PhpSchool\PhpWorkshop\Result\Success;
1517

16-
class CodeExistsCheckTest extends TestCase
18+
class CodeExistsCheckTest extends BaseTest
1719
{
18-
/**
19-
* @var string
20-
*/
21-
private $testDir;
22-
23-
/**
24-
* @var FileExistsCheck
25-
*/
26-
private $check;
27-
28-
/**
29-
* @var ExerciseInterface
30-
*/
31-
private $exercise;
32-
33-
/**
34-
* @var string
35-
*/
36-
private $file;
20+
private CodeExistsCheck $check;
3721

3822
public function setUp(): void
3923
{
40-
$this->testDir = sprintf(
41-
'%s/%s/%s',
42-
str_replace('\\', '/', sys_get_temp_dir()),
43-
basename(str_replace('\\', '/', get_class($this))),
44-
$this->getName()
45-
);
46-
47-
mkdir($this->testDir, 0777, true);
4824
$this->check = new CodeExistsCheck((new ParserFactory())->create(ParserFactory::PREFER_PHP7));
49-
$this->exercise = $this->createMock(ExerciseInterface::class);
25+
}
26+
27+
public function testCheckMeta(): void
28+
{
5029
$this->assertEquals('Code Exists Check', $this->check->getName());
5130
$this->assertEquals(ExerciseInterface::class, $this->check->getExerciseInterface());
5231
$this->assertEquals(SimpleCheckInterface::CHECK_BEFORE, $this->check->getPosition());
5332

5433
$this->assertTrue($this->check->canRun(ExerciseType::CGI()));
5534
$this->assertTrue($this->check->canRun(ExerciseType::CLI()));
56-
57-
$this->file = sprintf('%s/submission.php', $this->testDir);
58-
touch($this->file);
5935
}
6036

6137
public function testSuccess(): void
6238
{
63-
file_put_contents($this->file, '<?php echo "Hello World";');
39+
$context = new TestContext();
40+
$context->createStudentSolutionDirectory();
41+
$context->importStudentFileFromString('<?php echo "Hello World";');
6442

6543
$this->assertInstanceOf(
6644
Success::class,
67-
$this->check->check($this->exercise, new Input('app', ['program' => $this->file]))
45+
$this->check->check($context)
6846
);
6947
}
7048

7149
public function testFailure(): void
7250
{
73-
file_put_contents($this->file, '<?php');
51+
$context = new TestContext();
52+
$context->createStudentSolutionDirectory();
53+
$context->importStudentFileFromString('<?php');
7454

75-
$failure = $this->check->check($this->exercise, new Input('app', ['program' => $this->file]));
55+
$failure = $this->check->check($context);
7656

7757
$this->assertInstanceOf(Failure::class, $failure);
7858
$this->assertEquals('No code was found', $failure->getReason());
7959
}
80-
81-
public function tearDown(): void
82-
{
83-
unlink($this->file);
84-
rmdir($this->testDir);
85-
}
8660
}

‎test/Check/CodeParseCheckTest.php

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,74 +7,66 @@
77
use PhpSchool\PhpWorkshop\Check\SimpleCheckInterface;
88
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
99
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
10+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext;
1011
use PhpSchool\PhpWorkshop\Input\Input;
1112
use PhpSchool\PhpWorkshop\Result\Failure;
1213
use PhpSchool\PhpWorkshop\Result\Success;
14+
use PhpSchool\PhpWorkshop\Utils\Path;
15+
use PhpSchool\PhpWorkshopTest\BaseTest;
1316
use PHPUnit\Framework\TestCase;
1417
use Yoast\PHPUnitPolyfills\Polyfills\AssertionRenames;
1518

1619
class CodeParseCheckTest extends TestCase
1720
{
1821
use AssertionRenames;
1922

20-
/**
21-
* @var SimpleCheckInterface
22-
*/
23-
private $check;
24-
25-
/**
26-
* @var string
27-
*/
28-
private $file;
23+
private CodeParseCheck $check;
2924

3025
public function setUp(): void
3126
{
3227
$this->check = new CodeParseCheck((new ParserFactory())->create(ParserFactory::PREFER_PHP7));
28+
}
29+
30+
public function testCheckMeta(): void
31+
{
3332
$this->assertEquals('Code Parse Check', $this->check->getName());
3433
$this->assertEquals(ExerciseInterface::class, $this->check->getExerciseInterface());
3534
$this->assertEquals(SimpleCheckInterface::CHECK_BEFORE, $this->check->getPosition());
3635

3736
$this->assertTrue($this->check->canRun(ExerciseType::CGI()));
3837
$this->assertTrue($this->check->canRun(ExerciseType::CLI()));
39-
40-
$this->file = sprintf('%s/%s/submission.php', str_replace('\\', '/', sys_get_temp_dir()), $this->getName());
41-
mkdir(dirname($this->file), 0775, true);
42-
touch($this->file);
4338
}
4439

4540
public function testUnParseableCodeReturnsFailure(): void
4641
{
47-
file_put_contents($this->file, '<?php $lol');
42+
$context = new TestContext();
43+
$context->createStudentSolutionDirectory();
44+
$context->importStudentFileFromString('<?php $lol');
4845

49-
$result = $this->check->check(
50-
$this->createMock(ExerciseInterface::class),
51-
new Input('app', ['program' => $this->file])
52-
);
46+
$result = $this->check->check($context);
5347
$this->assertInstanceOf(Failure::class, $result);
5448

5549
$this->assertEquals('Code Parse Check', $result->getCheckName());
5650
$this->assertMatchesRegularExpression(
57-
sprintf('|^File: "%s" could not be parsed\. Error: "|', preg_quote($this->file)),
51+
sprintf(
52+
'|^File: "%s" could not be parsed\. Error: "|',
53+
preg_quote(
54+
Path::join($context->getStudentExecutionDirectory(), 'solution.php')
55+
)
56+
),
5857
$result->getReason()
5958
);
6059
}
6160

6261
public function testParseableCodeReturnsSuccess(): void
6362
{
64-
file_put_contents($this->file, '<?php $lol = "lol";');
63+
$context = new TestContext();
64+
$context->createStudentSolutionDirectory();
65+
$context->importStudentFileFromString('<?php $lol = "lol";');
6566

66-
$result = $this->check->check(
67-
$this->createMock(ExerciseInterface::class),
68-
new Input('app', ['program' => $this->file])
69-
);
67+
$result = $this->check->check($context);
7068
$this->assertInstanceOf(Success::class, $result);
7169

7270
$this->assertEquals('Code Parse Check', $result->getCheckName());
7371
}
74-
75-
public function tearDown(): void
76-
{
77-
unlink($this->file);
78-
rmdir(dirname($this->file));
79-
}
8072
}

‎test/Check/ComposerCheckTest.php

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
99
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
1010
use PhpSchool\PhpWorkshop\ExerciseCheck\ComposerExerciseCheck;
11+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext;
1112
use PhpSchool\PhpWorkshop\Input\Input;
1213
use PhpSchool\PhpWorkshop\Result\ComposerFailure;
1314
use PhpSchool\PhpWorkshop\Result\Failure;
@@ -17,20 +18,17 @@
1718

1819
class ComposerCheckTest extends TestCase
1920
{
20-
/**
21-
* @var ComposerCheck
22-
*/
23-
private $check;
24-
25-
/**
26-
* @var ExerciseInterface
27-
*/
28-
private $exercise;
21+
private ComposerCheck $check;
22+
private ComposerExercise $exercise;
2923

3024
public function setUp(): void
3125
{
3226
$this->check = new ComposerCheck();
3327
$this->exercise = new ComposerExercise();
28+
}
29+
30+
public function testCheckMeta(): void
31+
{
3432
$this->assertEquals('Composer Dependency Check', $this->check->getName());
3533
$this->assertEquals(ComposerExerciseCheck::class, $this->check->getExerciseInterface());
3634
$this->assertEquals(SimpleCheckInterface::CHECK_BEFORE, $this->check->getPosition());
@@ -44,14 +42,13 @@ public function testExceptionIsThrownIfNotValidExercise(): void
4442
$exercise = $this->createMock(ExerciseInterface::class);
4543
$this->expectException(InvalidArgumentException::class);
4644

47-
$this->check->check($exercise, new Input('app'));
45+
$this->check->check(new TestContext());
4846
}
4947

5048
public function testCheckReturnsFailureIfNoComposerFile(): void
5149
{
5250
$result = $this->check->check(
53-
$this->exercise,
54-
new Input('app', ['program' => 'invalid/solution'])
51+
new TestContext($this->exercise)
5552
);
5653

5754
$this->assertInstanceOf(ComposerFailure::class, $result);
@@ -62,11 +59,13 @@ public function testCheckReturnsFailureIfNoComposerFile(): void
6259

6360
public function testCheckReturnsFailureIfNoComposerLockFile(): void
6461
{
65-
$result = $this->check->check(
62+
$context = TestContext::fromExerciseAndStudentSolution(
6663
$this->exercise,
67-
new Input('app', ['program' => __DIR__ . '/../res/composer/not-locked/solution.php'])
64+
__DIR__ . '/../res/composer/not-locked/solution.php'
6865
);
6966

67+
$result = $this->check->check($context);
68+
7069
$this->assertInstanceOf(ComposerFailure::class, $result);
7170
$this->assertSame('Composer Dependency Check', $result->getCheckName());
7271
$this->assertTrue($result->isMissingComponent());
@@ -75,11 +74,13 @@ public function testCheckReturnsFailureIfNoComposerLockFile(): void
7574

7675
public function testCheckReturnsFailureIfNoVendorFolder(): void
7776
{
78-
$result = $this->check->check(
77+
$context = TestContext::fromExerciseAndStudentSolution(
7978
$this->exercise,
80-
new Input('app', ['program' => __DIR__ . '/../res/composer/no-vendor/solution.php'])
79+
__DIR__ . '/../res/composer/no-vendor/solution.php'
8180
);
8281

82+
$result = $this->check->check($context);
83+
8384
$this->assertInstanceOf(ComposerFailure::class, $result);
8485
$this->assertSame('Composer Dependency Check', $result->getCheckName());
8586
$this->assertTrue($result->isMissingComponent());
@@ -88,9 +89,6 @@ public function testCheckReturnsFailureIfNoVendorFolder(): void
8889

8990
/**
9091
* @dataProvider dependencyProvider
91-
*
92-
* @param string $dependency
93-
* @param string $solutionFile
9492
*/
9593
public function testCheckReturnsFailureIfDependencyNotRequired(string $dependency, string $solutionFile): void
9694
{
@@ -99,7 +97,9 @@ public function testCheckReturnsFailureIfDependencyNotRequired(string $dependenc
9997
->method('getRequiredPackages')
10098
->willReturn([$dependency]);
10199

102-
$result = $this->check->check($exercise, new Input('app', ['program' => $solutionFile]));
100+
$context = TestContext::fromExerciseAndStudentSolution($exercise, $solutionFile);
101+
102+
$result = $this->check->check($context);
103103

104104
$this->assertInstanceOf(ComposerFailure::class, $result);
105105
$this->assertSame('Composer Dependency Check', $result->getCheckName());
@@ -120,11 +120,13 @@ public function dependencyProvider(): array
120120

121121
public function testCheckReturnsSuccessIfCorrectLockFile(): void
122122
{
123-
$result = $this->check->check(
123+
$context = TestContext::fromExerciseAndStudentSolution(
124124
$this->exercise,
125-
new Input('app', ['program' => __DIR__ . '/../res/composer/good-solution/solution.php'])
125+
__DIR__ . '/../res/composer/good-solution/solution.php'
126126
);
127127

128+
$result = $this->check->check($context);
129+
128130
$this->assertInstanceOf(Success::class, $result);
129131
$this->assertSame('Composer Dependency Check', $result->getCheckName());
130132
}

‎test/Check/FileComparisonCheckTest.php

Lines changed: 35 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,28 @@
77
use PhpSchool\PhpWorkshop\Exception\SolutionFileDoesNotExistException;
88
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
99
use PhpSchool\PhpWorkshop\ExerciseCheck\FileComparisonExerciseCheck;
10+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext;
1011
use PhpSchool\PhpWorkshop\Input\Input;
1112
use PhpSchool\PhpWorkshop\Result\FileComparisonFailure;
1213
use PhpSchool\PhpWorkshop\Solution\SingleFileSolution;
14+
use PhpSchool\PhpWorkshop\Solution\SolutionInterface;
1315
use PhpSchool\PhpWorkshopTest\Asset\FileComparisonExercise;
1416
use PhpSchool\PhpWorkshopTest\BaseTest;
1517
use PhpSchool\PhpWorkshop\Result\Failure;
1618
use PhpSchool\PhpWorkshop\Result\Success;
19+
use PHPUnit\Framework\TestCase;
1720

18-
class FileComparisonCheckTest extends BaseTest
21+
class FileComparisonCheckTest extends TestCase
1922
{
20-
/**
21-
* @var FileComparisonCheck
22-
*/
23-
private $check;
23+
private FileComparisonCheck $check;
2424

2525
public function setUp(): void
2626
{
2727
$this->check = new FileComparisonCheck();
28+
}
29+
30+
public function testCheckMeta(): void
31+
{
2832
$this->assertEquals('File Comparison Check', $this->check->getName());
2933
$this->assertEquals(FileComparisonExerciseCheck::class, $this->check->getExerciseInterface());
3034
$this->assertEquals(SimpleCheckInterface::CHECK_AFTER, $this->check->getPosition());
@@ -39,35 +43,34 @@ public function testExceptionIsThrownIfReferenceFileDoesNotExist(): void
3943
$this->expectExceptionMessage('File: "some-file.txt" does not exist in solution folder');
4044

4145
$exercise = new FileComparisonExercise(['some-file.txt']);
42-
$exercise->setSolution(new SingleFileSolution($this->getTemporaryFile('solution/solution.php')));
46+
$context = new TestContext($exercise);
4347

44-
$this->check->check($exercise, new Input('app', ['program' => 'my-solution.php']));
48+
$this->check->check($context);
4549
}
4650

4751
public function testFailureIsReturnedIfStudentsFileDoesNotExist(): void
4852
{
49-
$referenceFile = $this->getTemporaryFile('solution/some-file.txt', "name,age\nAydin,33\nMichael,29\n");
50-
5153
$exercise = new FileComparisonExercise(['some-file.txt']);
52-
$exercise->setSolution(new SingleFileSolution($this->getTemporaryFile('solution/solution.php')));
54+
$context = new TestContext($exercise);
55+
$context->createReferenceSolutionDirectory();
56+
$context->importReferenceFileFromString("name,age\nAydin,33\nMichael,29\n", 'some-file.txt');
5357

54-
$failure = $this->check->check($exercise, new Input('app', ['program' => 'my-solution.php']));
58+
$failure = $this->check->check($context);
5559

5660
$this->assertInstanceOf(Failure::class, $failure);
5761
$this->assertEquals('File: "some-file.txt" does not exist', $failure->getReason());
5862
}
5963

6064
public function testFailureIsReturnedIfStudentFileDosNotMatchReferenceFile(): void
6165
{
62-
$referenceFile = $this->getTemporaryFile('solution/some-file.txt', "name,age\nAydin,33\nMichael,29\n");
63-
$studentFile = $this->getTemporaryFile('student/some-file.txt', "somegibberish");
64-
6566
$exercise = new FileComparisonExercise(['some-file.txt']);
66-
$exercise->setSolution(new SingleFileSolution($this->getTemporaryFile('solution/solution.php')));
67+
$context = new TestContext($exercise);
68+
$context->createStudentSolutionDirectory();
69+
$context->createReferenceSolutionDirectory();
70+
$context->importStudentFileFromString("somegibberish", 'some-file.txt');
71+
$context->importReferenceFileFromString("name,age\nAydin,33\nMichael,29\n", 'some-file.txt');
6772

68-
$failure = $this->check->check($exercise, new Input('app', [
69-
'program' => $this->getTemporaryFile('student/my-solution.php')
70-
]));
73+
$failure = $this->check->check($context);
7174

7275
$this->assertInstanceOf(FileComparisonFailure::class, $failure);
7376
$this->assertEquals($failure->getFileName(), 'some-file.txt');
@@ -77,37 +80,27 @@ public function testFailureIsReturnedIfStudentFileDosNotMatchReferenceFile(): vo
7780

7881
public function testSuccessIsReturnedIfFilesMatch(): void
7982
{
80-
$referenceFile = $this->getTemporaryFile('solution/some-file.txt', "name,age\nAydin,33\nMichael,29\n");
81-
$studentFile = $this->getTemporaryFile('student/some-file.txt', "name,age\nAydin,33\nMichael,29\n");
82-
8383
$exercise = new FileComparisonExercise(['some-file.txt']);
84-
$exercise->setSolution(new SingleFileSolution($this->getTemporaryFile('solution/solution.php')));
85-
86-
$this->assertInstanceOf(
87-
Success::class,
88-
$this->check->check($exercise, new Input('app', [
89-
'program' => $this->getTemporaryFile('student/my-solution.php')
90-
]))
91-
);
84+
85+
$context = new TestContext($exercise);
86+
$context->createStudentSolutionDirectory();
87+
$context->createReferenceSolutionDirectory();
88+
$context->importStudentFileFromString("name,age\nAydin,33\nMichael,29\n", 'some-file.txt');
89+
$context->importReferenceFileFromString("name,age\nAydin,33\nMichael,29\n", 'some-file.txt');
90+
91+
$this->assertInstanceOf(Success::class, $this->check->check($context));
9292
}
9393

9494
public function testFailureIsReturnedIfFileDoNotMatchUsingStrip(): void
9595
{
96-
$referenceFile = $this->getTemporaryFile(
97-
'solution/some-file.txt',
98-
"01:03name,age\n04:05Aydin,33\n17:21Michael,29\n"
99-
);
100-
$studentFile = $this->getTemporaryFile(
101-
'student/some-file.txt',
102-
"01:04name,age\n06:76Aydin,34\n99:00Michael,29\n"
103-
);
104-
10596
$exercise = new FileComparisonExercise(['some-file.txt' => ['strip' => '/\d{2}:\d{2}/']]);
106-
$exercise->setSolution(new SingleFileSolution($this->getTemporaryFile('solution/solution.php')));
97+
$context = new TestContext($exercise);
98+
$context->createStudentSolutionDirectory();
99+
$context->createReferenceSolutionDirectory();
100+
$context->importStudentFileFromString("01:04name,age\n06:76Aydin,34\n99:00Michael,29\n", 'some-file.txt');
101+
$context->importReferenceFileFromString("01:03name,age\n04:05Aydin,33\n17:21Michael,29\n", 'some-file.txt');
107102

108-
$failure = $this->check->check($exercise, new Input('app', [
109-
'program' => $this->getTemporaryFile('student/my-solution.php')
110-
]));
103+
$failure = $this->check->check($context);
111104

112105
$this->assertInstanceOf(FileComparisonFailure::class, $failure);
113106
$this->assertEquals($failure->getFileName(), 'some-file.txt');

‎test/Check/FileExistsCheckTest.php

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
use PhpSchool\PhpWorkshop\Check\SimpleCheckInterface;
66
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
7+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext;
78
use PhpSchool\PhpWorkshop\Input\Input;
9+
use PhpSchool\PhpWorkshop\Utils\Path;
810
use PHPUnit\Framework\TestCase;
911
use PhpSchool\PhpWorkshop\Check\FileExistsCheck;
1012
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
@@ -13,27 +15,15 @@
1315

1416
class FileExistsCheckTest extends TestCase
1517
{
16-
/**
17-
* @var string
18-
*/
19-
private $testDir;
20-
21-
/**
22-
* @var FileExistsCheck
23-
*/
24-
private $check;
25-
26-
/**
27-
* @var ExerciseInterface
28-
*/
29-
private $exercise;
18+
private FileExistsCheck $check;
3019

3120
public function setUp(): void
3221
{
33-
$this->testDir = sprintf('%s/%s', sys_get_temp_dir(), $this->getName());
34-
mkdir($this->testDir, 0777, true);
3522
$this->check = new FileExistsCheck();
36-
$this->exercise = $this->createMock(ExerciseInterface::class);
23+
}
24+
25+
public function testCheckMeta(): void
26+
{
3727
$this->assertEquals('File Exists Check', $this->check->getName());
3828
$this->assertEquals(ExerciseInterface::class, $this->check->getExerciseInterface());
3929
$this->assertEquals(SimpleCheckInterface::CHECK_BEFORE, $this->check->getPosition());
@@ -44,26 +34,28 @@ public function setUp(): void
4434

4535
public function testSuccess(): void
4636
{
47-
$file = sprintf('%s/test.txt', $this->testDir);
48-
touch($file);
37+
$context = new TestContext();
38+
$context->createStudentSolutionDirectory();
39+
$context->importStudentFileFromString('<?php echo "Hello World";');
4940

5041
$this->assertInstanceOf(
5142
Success::class,
52-
$this->check->check($this->exercise, new Input('app', ['program' => $file]))
43+
$this->check->check($context)
5344
);
54-
unlink($file);
5545
}
5646

5747
public function testFailure(): void
5848
{
59-
$file = sprintf('%s/test.txt', $this->testDir);
60-
$failure = $this->check->check($this->exercise, new Input('app', ['program' => $file]));
61-
$this->assertInstanceOf(Failure::class, $failure);
62-
$this->assertEquals(sprintf('File: "%s" does not exist', $file), $failure->getReason());
63-
}
49+
$context = new TestContext();
6450

65-
public function tearDown(): void
66-
{
67-
rmdir($this->testDir);
51+
$failure = $this->check->check($context);
52+
$this->assertInstanceOf(Failure::class, $failure);
53+
$this->assertEquals(
54+
sprintf(
55+
'File: "%s" does not exist',
56+
Path::join($context->getStudentExecutionDirectory(), 'solution.php')
57+
),
58+
$failure->getReason()
59+
);
6860
}
6961
}

‎test/Check/FunctionRequirementsCheckTest.php

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PhpParser\ParserFactory;
88
use PhpSchool\PhpWorkshop\Check\SimpleCheckInterface;
99
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
10+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext;
1011
use PhpSchool\PhpWorkshop\Input\Input;
1112
use PhpSchool\PhpWorkshopTest\Asset\FunctionRequirementsExercise;
1213
use PHPUnit\Framework\TestCase;
@@ -19,27 +20,20 @@
1920

2021
class FunctionRequirementsCheckTest extends TestCase
2122
{
22-
/**
23-
* @var FunctionRequirementsCheck
24-
*/
25-
private $check;
26-
27-
/**
28-
* @var ExerciseInterface
29-
*/
30-
private $exercise;
31-
32-
/**
33-
* @var Parser
34-
*/
35-
private $parser;
23+
private FunctionRequirementsCheck $check;
24+
private FunctionRequirementsExercise $exercise;
25+
private Parser $parser;
3626

3727
public function setUp(): void
3828
{
3929
$parserFactory = new ParserFactory();
4030
$this->parser = $parserFactory->create(ParserFactory::PREFER_PHP7);
4131
$this->check = new FunctionRequirementsCheck($this->parser);
4232
$this->exercise = new FunctionRequirementsExercise();
33+
}
34+
35+
public function testCheckMeta(): void
36+
{
4337
$this->assertEquals('Function Requirements Check', $this->check->getName());
4438
$this->assertEquals(FunctionRequirementsExerciseCheck::class, $this->check->getExerciseInterface());
4539
$this->assertEquals(SimpleCheckInterface::CHECK_AFTER, $this->check->getPosition());
@@ -53,25 +47,35 @@ public function testExceptionIsThrownIfNotValidExercise(): void
5347
$exercise = $this->createMock(ExerciseInterface::class);
5448
$this->expectException(InvalidArgumentException::class);
5549

56-
$this->check->check($exercise, new Input('app'));
50+
$this->check->check(new TestContext($exercise));
5751
}
5852

5953
public function testFailureIsReturnedIfCodeCouldNotBeParsed(): void
6054
{
61-
$file = __DIR__ . '/../res/function-requirements/fail-invalid-code.php';
62-
$failure = $this->check->check($this->exercise, new Input('app', ['program' => $file]));
63-
$this->assertInstanceOf(Failure::class, $failure);
55+
$context = TestContext::fromExerciseAndStudentSolution(
56+
$this->exercise,
57+
__DIR__ . '/../res/function-requirements/fail-invalid-code.php'
58+
);
59+
60+
$failure = $this->check->check($context);
6461

65-
$message = sprintf('File: "%s" could not be parsed. Error: "Syntax error, unexpected T_ECHO on line 4"', $file);
62+
$this->assertInstanceOf(Failure::class, $failure);
63+
$message = sprintf(
64+
'File: "%s/fail-invalid-code.php" could not be parsed. Error: "Syntax error, unexpected T_ECHO on line 4"',
65+
$context->getStudentExecutionDirectory()
66+
);
6667
$this->assertEquals($message, $failure->getReason());
6768
}
6869

6970
public function testFailureIsReturnedIfBannedFunctionsAreUsed(): void
7071
{
71-
$failure = $this->check->check(
72+
$context = TestContext::fromExerciseAndStudentSolution(
7273
$this->exercise,
73-
new Input('app', ['program' => __DIR__ . '/../res/function-requirements/fail-banned-function.php'])
74+
__DIR__ . '/../res/function-requirements/fail-banned-function.php'
7475
);
76+
77+
$failure = $this->check->check($context);
78+
7579
$this->assertInstanceOf(FunctionRequirementsFailure::class, $failure);
7680
$this->assertEquals([['function' => 'file', 'line' => 3]], $failure->getBannedFunctions());
7781
$this->assertEquals([], $failure->getMissingFunctions());
@@ -90,12 +94,14 @@ public function testFailureIsReturnedIfNotAllRequiredFunctionsHaveBeenUsed(): vo
9094
->method('getRequiredFunctions')
9195
->willReturn(['file_get_contents', 'implode']);
9296

93-
$failure = $this->check->check(
97+
$context = TestContext::fromExerciseAndStudentSolution(
9498
$exercise,
95-
new Input('app', ['program' => __DIR__ . '/../res/function-requirements/fail-banned-function.php'])
99+
__DIR__ . '/../res/function-requirements/fail-banned-function.php'
96100
);
97-
$this->assertInstanceOf(FunctionRequirementsFailure::class, $failure);
98101

102+
$failure = $this->check->check($context);
103+
104+
$this->assertInstanceOf(FunctionRequirementsFailure::class, $failure);
99105
$this->assertEquals(['file_get_contents', 'implode'], $failure->getMissingFunctions());
100106
$this->assertEquals([], $failure->getBannedFunctions());
101107
}
@@ -113,10 +119,13 @@ public function testSuccess(): void
113119
->method('getRequiredFunctions')
114120
->willReturn(['file_get_contents']);
115121

116-
$success = $this->check->check(
122+
$context = TestContext::fromExerciseAndStudentSolution(
117123
$exercise,
118-
new Input('app', ['program' => __DIR__ . '/../res/function-requirements/success.php'])
124+
__DIR__ . '/../res/function-requirements/success.php'
119125
);
126+
127+
$success = $this->check->check($context);
128+
120129
$this->assertInstanceOf(Success::class, $success);
121130
}
122131
}

‎test/Check/PhpLintCheckTest.php

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
use PhpSchool\PhpWorkshop\Check\SimpleCheckInterface;
66
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
7+
use PhpSchool\PhpWorkshop\ExerciseCheck\FunctionRequirementsExerciseCheck;
8+
use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext;
79
use PhpSchool\PhpWorkshop\Input\Input;
810
use PHPUnit\Framework\TestCase;
911
use PhpSchool\PhpWorkshop\Check\PhpLintCheck;
@@ -16,20 +18,17 @@ class PhpLintCheckTest extends TestCase
1618
{
1719
use AssertionRenames;
1820

19-
/**
20-
* @var PhpLintCheck
21-
*/
22-
private $check;
23-
24-
/**
25-
* @var ExerciseInterface
26-
*/
27-
private $exercise;
21+
private PhpLintCheck $check;
22+
private ExerciseInterface $exercise;
2823

2924
public function setUp(): void
3025
{
3126
$this->check = new PhpLintCheck();
3227
$this->exercise = $this->createMock(ExerciseInterface::class);
28+
}
29+
30+
public function testCheckMeta(): void
31+
{
3332
$this->assertEquals('PHP Code Check', $this->check->getName());
3433
$this->assertEquals(ExerciseInterface::class, $this->check->getExerciseInterface());
3534
$this->assertEquals(SimpleCheckInterface::CHECK_BEFORE, $this->check->getPosition());
@@ -40,18 +39,28 @@ public function setUp(): void
4039

4140
public function testSuccess(): void
4241
{
42+
$context = TestContext::fromExerciseAndStudentSolution(
43+
$this->exercise,
44+
__DIR__ . '/../res/lint/pass.php'
45+
);
46+
47+
$res = $this->check->check($context);
48+
4349
$this->assertInstanceOf(
4450
Success::class,
45-
$this->check->check($this->exercise, new Input('app', ['program' => __DIR__ . '/../res/lint/pass.php']))
51+
$this->check->check($context)
4652
);
4753
}
4854

4955
public function testFailure(): void
5056
{
51-
$failure = $this->check->check(
57+
$context = TestContext::fromExerciseAndStudentSolution(
5258
$this->exercise,
53-
new Input('app', ['program' => __DIR__ . '/../res/lint/fail.php'])
59+
__DIR__ . '/../res/lint/fail.php'
5460
);
61+
62+
$failure = $this->check->check($context);
63+
5564
$this->assertInstanceOf(Failure::class, $failure);
5665
$this->assertMatchesRegularExpression(
5766
"/(PHP )?Parse error:\W+syntax error, unexpected end of file, expecting ['\"][,;]['\"] or ['\"][;,]['\"]/",

‎test/ExerciseDispatcherTest.php

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,9 @@ public function testVerify(): void
219219
$check->method('canRun')->with($exercise->getType())->willReturn(true);
220220
$check->method('getPosition')->willReturn(SimpleCheckInterface::CHECK_BEFORE);
221221
$check->method('getExerciseInterface')->willReturn(ExerciseInterface::class);
222-
$check->method('check')->with($exercise, $input)->willReturn(new Success('Success!'));
222+
$check->method('check')
223+
->with($this->isInstanceOf(ExecutionContext::class))
224+
->willReturn(new Success('Success!'));
223225

224226
$runner = $this->createMock(ExerciseRunnerInterface::class);
225227
$runner->method('getRequiredChecks')->willReturn([get_class($check)]);
@@ -263,7 +265,7 @@ public function testVerifyOnlyRunsRequiredChecks(): void
263265

264266
$check1
265267
->method('check')
266-
->with($exercise, $input)
268+
->with($this->isInstanceOf(ExecutionContext::class))
267269
->willReturn(new Success('Success!'));
268270

269271
$check2 = $this
@@ -274,7 +276,7 @@ public function testVerifyOnlyRunsRequiredChecks(): void
274276
$check2
275277
->expects($this->never())
276278
->method('check')
277-
->with($exercise, $input);
279+
->with($this->isInstanceOf(ExecutionContext::class));
278280

279281
$runner = $this->createMock(ExerciseRunnerInterface::class);
280282
$runner
@@ -313,13 +315,17 @@ public function testVerifyWithBeforeAndAfterRequiredChecks(): void
313315
$check1->method('canRun')->with($exercise->getType())->willReturn(true);
314316
$check1->method('getPosition')->willReturn(SimpleCheckInterface::CHECK_BEFORE);
315317
$check1->method('getExerciseInterface')->willReturn(ExerciseInterface::class);
316-
$check1->method('check')->with($exercise, $input)->willReturn(new Success('Success!'));
318+
$check1->method('check')
319+
->with($this->isInstanceOf(ExecutionContext::class))
320+
->willReturn(new Success('Success!'));
317321

318322
$check2 = $this->createMock(SimpleCheckInterface::class);
319323
$check2->method('canRun')->with($exercise->getType())->willReturn(true);
320324
$check2->method('getPosition')->willReturn(SimpleCheckInterface::CHECK_AFTER);
321325
$check2->method('getExerciseInterface')->willReturn(ExerciseInterface::class);
322-
$check2->method('check')->with($exercise, $input)->willReturn(new Success('Success!'));
326+
$check2->method('check')
327+
->with($this->isInstanceOf(ExecutionContext::class))
328+
->willReturn(new Success('Success!'));
323329

324330
$runner = $this->createMock(ExerciseRunnerInterface::class);
325331
$runner->method('getRequiredChecks')->willReturn([get_class($check1), get_class($check2)]);
@@ -365,7 +371,7 @@ public function testWhenBeforeChecksFailTheyReturnImmediately(): void
365371

366372
$check1
367373
->method('check')
368-
->with($exercise, $input)
374+
->with($this->isInstanceOf(ExecutionContext::class))
369375
->willReturn(new Failure('Failure', 'nope'));
370376

371377
$check2 = $this
@@ -388,7 +394,7 @@ public function testWhenBeforeChecksFailTheyReturnImmediately(): void
388394
$check2
389395
->expects($this->never())
390396
->method('check')
391-
->with($exercise, $input);
397+
->with($this->isInstanceOf(ExecutionContext::class));
392398

393399
$runner = $this->createMock(ExerciseRunnerInterface::class);
394400
$runner

0 commit comments

Comments
 (0)
Please sign in to comment.