diff --git a/src/Check/CodeExistsCheck.php b/src/Check/CodeExistsCheck.php index 859e3d29..79067833 100644 --- a/src/Check/CodeExistsCheck.php +++ b/src/Check/CodeExistsCheck.php @@ -11,6 +11,7 @@ use PhpParser\Parser; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\Result\Failure; use PhpSchool\PhpWorkshop\Result\ResultInterface; @@ -18,14 +19,8 @@ class CodeExistsCheck implements SimpleCheckInterface { - /** - * @var Parser - */ - private $parser; - - public function __construct(Parser $parser) + public function __construct(private Parser $parser) { - $this->parser = $parser; } public function getName(): string @@ -34,10 +29,12 @@ public function getName(): string } /** + * @param ExecutionContext $context The current execution context, containing the exercise, input and working directories. + * * Check solution provided contains code * Note: We don't care if it's valid code at this point */ - public function check(ExerciseInterface $exercise, Input $input): ResultInterface + public function check(ExecutionContext $context): ResultInterface { $noopHandler = new class implements ErrorHandler { public function handleError(Error $error): void @@ -45,7 +42,7 @@ public function handleError(Error $error): void } }; - $code = (string) file_get_contents($input->getRequiredArgument('program')); + $code = (string) file_get_contents($context->getEntryPoint()); $statements = $this->parser->parse($code, $noopHandler); $empty = null === $statements || empty($statements); diff --git a/src/Check/CodeParseCheck.php b/src/Check/CodeParseCheck.php index 670ec1b1..4be59113 100644 --- a/src/Check/CodeParseCheck.php +++ b/src/Check/CodeParseCheck.php @@ -8,6 +8,7 @@ use PhpParser\Parser; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\Result\Failure; use PhpSchool\PhpWorkshop\Result\ResultInterface; @@ -19,17 +20,8 @@ */ class CodeParseCheck implements SimpleCheckInterface { - /** - * @var Parser - */ - private $parser; - - /** - * @param Parser $parser - */ - public function __construct(Parser $parser) + public function __construct(private Parser $parser) { - $this->parser = $parser; } /** @@ -45,18 +37,17 @@ public function getName(): string * attempts to parse it with `nikic/php-parser`. If any exceptions are thrown * by the parser, it is treated as a failure. * - * @param ExerciseInterface $exercise The exercise to check against. - * @param Input $input The command line arguments passed to the command. + * @param ExecutionContext $context The current execution context, containing the exercise, input and working directories. * @return ResultInterface The result of the check. */ - public function check(ExerciseInterface $exercise, Input $input): ResultInterface + public function check(ExecutionContext $context): ResultInterface { - $code = (string) file_get_contents($input->getRequiredArgument('program')); + $code = (string) file_get_contents($context->getEntryPoint()); try { $this->parser->parse($code); } catch (Error $e) { - return Failure::fromCheckAndCodeParseFailure($this, $e, $input->getRequiredArgument('program')); + return Failure::fromCheckAndCodeParseFailure($this, $e, $context->getEntryPoint()); } return Success::fromCheck($this); diff --git a/src/Check/ComposerCheck.php b/src/Check/ComposerCheck.php index 6711f1b2..9e099082 100644 --- a/src/Check/ComposerCheck.php +++ b/src/Check/ComposerCheck.php @@ -9,6 +9,7 @@ use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; use PhpSchool\PhpWorkshop\ExerciseCheck\ComposerExerciseCheck; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\Result\ComposerFailure; use PhpSchool\PhpWorkshop\Result\Failure; @@ -34,30 +35,29 @@ public function getName(): string * installed a set of required packages. If they did not a failure is returned, otherwise, * a success is returned. * - * @param ExerciseInterface $exercise The exercise to check against. - * @param Input $input The command line arguments passed to the command. + * @param ExecutionContext $context The current execution context, containing the exercise, input and working directories. * @return ResultInterface The result of the check. - * @noinspection SpellCheckingInspection */ - public function check(ExerciseInterface $exercise, Input $input): ResultInterface + public function check(ExecutionContext $context): ResultInterface { + $exercise = $context->getExercise(); if (!$exercise instanceof ComposerExerciseCheck) { throw new InvalidArgumentException(); } - if (!file_exists(sprintf('%s/composer.json', dirname($input->getRequiredArgument('program'))))) { + if (!file_exists(sprintf('%s/composer.json', $context->getStudentExecutionDirectory()))) { return ComposerFailure::fromCheckAndMissingFileOrFolder($this, 'composer.json'); } - if (!file_exists(sprintf('%s/composer.lock', dirname($input->getRequiredArgument('program'))))) { + if (!file_exists(sprintf('%s/composer.lock', $context->getStudentExecutionDirectory()))) { return ComposerFailure::fromCheckAndMissingFileOrFolder($this, 'composer.lock'); } - if (!file_exists(sprintf('%s/vendor', dirname($input->getRequiredArgument('program'))))) { + if (!file_exists(sprintf('%s/vendor', $context->getStudentExecutionDirectory()))) { return ComposerFailure::fromCheckAndMissingFileOrFolder($this, 'vendor'); } - $lockFile = new LockFileParser(sprintf('%s/composer.lock', dirname($input->getRequiredArgument('program')))); + $lockFile = new LockFileParser(sprintf('%s/composer.lock', $context->getStudentExecutionDirectory())); $missingPackages = array_filter($exercise->getRequiredPackages(), function ($package) use ($lockFile) { return !$lockFile->hasInstalledPackage($package); }); diff --git a/src/Check/DatabaseCheck.php b/src/Check/DatabaseCheck.php index 0a55f4ec..658865b0 100644 --- a/src/Check/DatabaseCheck.php +++ b/src/Check/DatabaseCheck.php @@ -25,30 +25,11 @@ class DatabaseCheck implements ListenableCheckInterface { use TemporaryDirectoryTrait; - /** - * @var string - */ - private $databaseDirectory; - - /** - * @var string - */ - private $userDatabasePath; - - /** - * @var string - */ - private $solutionDatabasePath; - - /** - * @var string - */ - private $userDsn; - - /** - * @var string - */ - private $solutionDsn; + private string $databaseDirectory; + private string $userDatabasePath; + private string $solutionDatabasePath; + private string $userDsn; + private string $solutionDsn; /** * Setup paths and DSN's. diff --git a/src/Check/FileComparisonCheck.php b/src/Check/FileComparisonCheck.php index 3acefd68..87bf5ddb 100644 --- a/src/Check/FileComparisonCheck.php +++ b/src/Check/FileComparisonCheck.php @@ -10,6 +10,7 @@ use PhpSchool\PhpWorkshop\Exercise\ExerciseType; use PhpSchool\PhpWorkshop\Exercise\ProvidesSolution; use PhpSchool\PhpWorkshop\ExerciseCheck\FileComparisonExerciseCheck; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\Result\Failure; use PhpSchool\PhpWorkshop\Result\FileComparisonFailure; @@ -34,12 +35,12 @@ public function getName(): string /** * Simply check that the file exists. * - * @param ExerciseInterface&ProvidesSolution $exercise The exercise to check against. - * @param Input $input The command line arguments passed to the command. + * @param ExecutionContext $context The current execution context, containing the exercise, input and working directories. * @return ResultInterface The result of the check. */ - public function check(ExerciseInterface $exercise, Input $input): ResultInterface + public function check(ExecutionContext $context): ResultInterface { + $exercise = $context->getExercise(); if (!$exercise instanceof FileComparisonExerciseCheck) { throw new InvalidArgumentException(); } @@ -47,8 +48,8 @@ public function check(ExerciseInterface $exercise, Input $input): ResultInterfac foreach ($exercise->getFilesToCompare() as $key => $file) { [$options, $file] = $this->getOptionsAndFile($key, $file); - $studentFile = Path::join(dirname($input->getRequiredArgument('program')), $file); - $referenceFile = Path::join($exercise->getSolution()->getBaseDirectory(), $file); + $studentFile = Path::join($context->getStudentExecutionDirectory(), $file); + $referenceFile = Path::join($context->getReferenceExecutionDirectory(), $file); if (!file_exists($referenceFile)) { throw SolutionFileDoesNotExistException::fromExpectedFile($file); diff --git a/src/Check/FileExistsCheck.php b/src/Check/FileExistsCheck.php index 5dba56e8..b8a9ee25 100644 --- a/src/Check/FileExistsCheck.php +++ b/src/Check/FileExistsCheck.php @@ -6,6 +6,7 @@ use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\Result\Failure; use PhpSchool\PhpWorkshop\Result\ResultInterface; @@ -27,19 +28,18 @@ public function getName(): string /** * Simply check that the file exists. * - * @param ExerciseInterface $exercise The exercise to check against. - * @param Input $input The command line arguments passed to the command. + * @param ExecutionContext $context The current execution context, containing the exercise, input and working directories. * @return ResultInterface The result of the check. */ - public function check(ExerciseInterface $exercise, Input $input): ResultInterface + public function check(ExecutionContext $context): ResultInterface { - if (file_exists($input->getRequiredArgument('program'))) { + if (file_exists($context->getEntryPoint())) { return Success::fromCheck($this); } return Failure::fromCheckAndReason( $this, - sprintf('File: "%s" does not exist', $input->getRequiredArgument('program')) + sprintf('File: "%s" does not exist', $context->getEntryPoint()) ); } diff --git a/src/Check/FunctionRequirementsCheck.php b/src/Check/FunctionRequirementsCheck.php index 4c14f851..d644a661 100644 --- a/src/Check/FunctionRequirementsCheck.php +++ b/src/Check/FunctionRequirementsCheck.php @@ -12,6 +12,7 @@ use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; use PhpSchool\PhpWorkshop\ExerciseCheck\FunctionRequirementsExerciseCheck; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\NodeVisitor\FunctionVisitor; use PhpSchool\PhpWorkshop\Result\Failure; @@ -25,17 +26,8 @@ */ class FunctionRequirementsCheck implements SimpleCheckInterface { - /** - * @var Parser - */ - private $parser; - - /** - * @param Parser $parser - */ - public function __construct(Parser $parser) + public function __construct(private Parser $parser) { - $this->parser = $parser; } /** @@ -51,12 +43,12 @@ public function getName(): string * required functions and that banned functions are not used. The requirements * are pulled from the exercise. * - * @param ExerciseInterface $exercise The exercise to check against. - * @param Input $input The command line arguments passed to the command. + * @param ExecutionContext $context The current execution context, containing the exercise, input and working directories. * @return ResultInterface The result of the check. */ - public function check(ExerciseInterface $exercise, Input $input): ResultInterface + public function check(ExecutionContext $context): ResultInterface { + $exercise = $context->getExercise(); if (!$exercise instanceof FunctionRequirementsExerciseCheck) { throw new InvalidArgumentException(); } @@ -64,12 +56,12 @@ public function check(ExerciseInterface $exercise, Input $input): ResultInterfac $requiredFunctions = $exercise->getRequiredFunctions(); $bannedFunctions = $exercise->getBannedFunctions(); - $code = (string) file_get_contents($input->getRequiredArgument('program')); + $code = (string) file_get_contents($context->getEntryPoint()); try { $ast = $this->parser->parse($code) ?? []; } catch (Error $e) { - return Failure::fromCheckAndCodeParseFailure($this, $e, $input->getRequiredArgument('program')); + return Failure::fromCheckAndCodeParseFailure($this, $e, $context->getEntryPoint()); } $visitor = new FunctionVisitor($requiredFunctions, $bannedFunctions); diff --git a/src/Check/PhpLintCheck.php b/src/Check/PhpLintCheck.php index c90c3fbd..f05e427d 100644 --- a/src/Check/PhpLintCheck.php +++ b/src/Check/PhpLintCheck.php @@ -6,6 +6,7 @@ use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\Result\ResultInterface; use PhpSchool\PhpWorkshop\Result\Success; @@ -30,14 +31,13 @@ public function getName(): string /** * Simply check the student's solution can be linted with `php -l`. * - * @param ExerciseInterface $exercise The exercise to check against. - * @param Input $input The command line arguments passed to the command. + * @param ExecutionContext $context The current execution context, containing the exercise, input and working directories. * @return ResultInterface The result of the check. */ - public function check(ExerciseInterface $exercise, Input $input): ResultInterface + public function check(ExecutionContext $context): ResultInterface { $finder = new ExecutableFinder(); - $process = new Process([$finder->find('php'), '-l', $input->getArgument('program')]); + $process = new Process([$finder->find('php'), '-l', $context->getEntryPoint()]); $process->run(); if ($process->isSuccessful()) { diff --git a/src/Check/SimpleCheckInterface.php b/src/Check/SimpleCheckInterface.php index 5b4bf78a..b1fbf63e 100644 --- a/src/Check/SimpleCheckInterface.php +++ b/src/Check/SimpleCheckInterface.php @@ -6,6 +6,7 @@ use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\ExecutionContext; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\Result\ResultInterface; @@ -46,11 +47,10 @@ public function canRun(ExerciseType $exerciseType): bool; * successful then an instance of `PhpSchool\PhpWorkshop\Result\FailureInterface` * should be returned. * - * @param ExerciseInterface $exercise The exercise to check against. - * @param Input $input The command line arguments passed to the command. + * @param ExecutionContext $context The current execution context, containing the exercise, input and working directories. * @return ResultInterface The result of the check. */ - public function check(ExerciseInterface $exercise, Input $input): ResultInterface; + public function check(ExecutionContext $context): ResultInterface; /** * Either `static::CHECK_BEFORE` | `static::CHECK_AFTER`. diff --git a/src/ExerciseDispatcher.php b/src/ExerciseDispatcher.php index 5852921d..ed8e6bc3 100644 --- a/src/ExerciseDispatcher.php +++ b/src/ExerciseDispatcher.php @@ -123,7 +123,7 @@ public function verify(ExerciseInterface $exercise, Input $input): ResultAggrega $this->validateChecks($this->checksToRunAfter, $exercise); foreach ($this->checksToRunBefore as $check) { - $this->results->add($check->check($context->getExercise(), $context->getInput())); + $this->results->add($check->check($context)); if (!$this->results->isSuccessful()) { return $this->results; @@ -139,7 +139,7 @@ public function verify(ExerciseInterface $exercise, Input $input): ResultAggrega } foreach ($this->checksToRunAfter as $check) { - $this->results->add($check->check($context->getExercise(), $context->getInput())); + $this->results->add($check->check($context)); } $this->eventDispatcher->dispatch(new ExerciseRunnerEvent('verify.post.check', $exercise, $input)); @@ -167,10 +167,9 @@ public function run(ExerciseInterface $exercise, Input $input, OutputInterface $ /** @var PhpLintCheck $lint */ $lint = $this->checkRepository->getByClass(PhpLintCheck::class); - $result = $lint->check($context->getExercise(), $context->getInput()); + $result = $lint->check($context); if ($result instanceof FailureInterface) { - var_dump($result); throw CouldNotRunException::fromFailure($result); } diff --git a/test/Check/CodeExistsCheckTest.php b/test/Check/CodeExistsCheckTest.php index aee1e8ef..947763dc 100644 --- a/test/Check/CodeExistsCheckTest.php +++ b/test/Check/CodeExistsCheckTest.php @@ -6,81 +6,53 @@ use PhpSchool\PhpWorkshop\Check\CodeExistsCheck; use PhpSchool\PhpWorkshop\Check\SimpleCheckInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext; use PhpSchool\PhpWorkshop\Input\Input; +use PhpSchool\PhpWorkshopTest\BaseTest; use PHPUnit\Framework\TestCase; use PhpSchool\PhpWorkshop\Check\FileExistsCheck; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\Result\Failure; use PhpSchool\PhpWorkshop\Result\Success; -class CodeExistsCheckTest extends TestCase +class CodeExistsCheckTest extends BaseTest { - /** - * @var string - */ - private $testDir; - - /** - * @var FileExistsCheck - */ - private $check; - - /** - * @var ExerciseInterface - */ - private $exercise; - - /** - * @var string - */ - private $file; + private CodeExistsCheck $check; public function setUp(): void { - $this->testDir = sprintf( - '%s/%s/%s', - str_replace('\\', '/', sys_get_temp_dir()), - basename(str_replace('\\', '/', get_class($this))), - $this->getName() - ); - - mkdir($this->testDir, 0777, true); $this->check = new CodeExistsCheck((new ParserFactory())->create(ParserFactory::PREFER_PHP7)); - $this->exercise = $this->createMock(ExerciseInterface::class); + } + + public function testCheckMeta(): void + { $this->assertEquals('Code Exists Check', $this->check->getName()); $this->assertEquals(ExerciseInterface::class, $this->check->getExerciseInterface()); $this->assertEquals(SimpleCheckInterface::CHECK_BEFORE, $this->check->getPosition()); $this->assertTrue($this->check->canRun(ExerciseType::CGI())); $this->assertTrue($this->check->canRun(ExerciseType::CLI())); - - $this->file = sprintf('%s/submission.php', $this->testDir); - touch($this->file); } public function testSuccess(): void { - file_put_contents($this->file, 'importStudentFileFromString('assertInstanceOf( Success::class, - $this->check->check($this->exercise, new Input('app', ['program' => $this->file])) + $this->check->check($context) ); } public function testFailure(): void { - file_put_contents($this->file, 'importStudentFileFromString('check->check($this->exercise, new Input('app', ['program' => $this->file])); + $failure = $this->check->check($context); $this->assertInstanceOf(Failure::class, $failure); $this->assertEquals('No code was found', $failure->getReason()); } - - public function tearDown(): void - { - unlink($this->file); - rmdir($this->testDir); - } } diff --git a/test/Check/CodeParseCheckTest.php b/test/Check/CodeParseCheckTest.php index 2c313cc8..cd031110 100644 --- a/test/Check/CodeParseCheckTest.php +++ b/test/Check/CodeParseCheckTest.php @@ -7,9 +7,12 @@ use PhpSchool\PhpWorkshop\Check\SimpleCheckInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\Result\Failure; use PhpSchool\PhpWorkshop\Result\Success; +use PhpSchool\PhpWorkshop\Utils\Path; +use PhpSchool\PhpWorkshopTest\BaseTest; use PHPUnit\Framework\TestCase; use Yoast\PHPUnitPolyfills\Polyfills\AssertionRenames; @@ -17,64 +20,51 @@ class CodeParseCheckTest extends TestCase { use AssertionRenames; - /** - * @var SimpleCheckInterface - */ - private $check; - - /** - * @var string - */ - private $file; + private CodeParseCheck $check; public function setUp(): void { $this->check = new CodeParseCheck((new ParserFactory())->create(ParserFactory::PREFER_PHP7)); + } + + public function testCheckMeta(): void + { $this->assertEquals('Code Parse Check', $this->check->getName()); $this->assertEquals(ExerciseInterface::class, $this->check->getExerciseInterface()); $this->assertEquals(SimpleCheckInterface::CHECK_BEFORE, $this->check->getPosition()); $this->assertTrue($this->check->canRun(ExerciseType::CGI())); $this->assertTrue($this->check->canRun(ExerciseType::CLI())); - - $this->file = sprintf('%s/%s/submission.php', str_replace('\\', '/', sys_get_temp_dir()), $this->getName()); - mkdir(dirname($this->file), 0775, true); - touch($this->file); } public function testUnParseableCodeReturnsFailure(): void { - file_put_contents($this->file, 'importStudentFileFromString('check->check( - $this->createMock(ExerciseInterface::class), - new Input('app', ['program' => $this->file]) - ); + $result = $this->check->check($context); $this->assertInstanceOf(Failure::class, $result); $this->assertEquals('Code Parse Check', $result->getCheckName()); $this->assertMatchesRegularExpression( - sprintf('|^File: "%s" could not be parsed\. Error: "|', preg_quote($this->file)), + sprintf( + '|^File: "%s" could not be parsed\. Error: "|', + preg_quote( + Path::join($context->getStudentExecutionDirectory(), 'solution.php') + ) + ), $result->getReason() ); } public function testParseableCodeReturnsSuccess(): void { - file_put_contents($this->file, 'importStudentFileFromString('check->check( - $this->createMock(ExerciseInterface::class), - new Input('app', ['program' => $this->file]) - ); + $result = $this->check->check($context); $this->assertInstanceOf(Success::class, $result); $this->assertEquals('Code Parse Check', $result->getCheckName()); } - - public function tearDown(): void - { - unlink($this->file); - rmdir(dirname($this->file)); - } } diff --git a/test/Check/ComposerCheckTest.php b/test/Check/ComposerCheckTest.php index 45b36931..2b7c4657 100644 --- a/test/Check/ComposerCheckTest.php +++ b/test/Check/ComposerCheckTest.php @@ -8,6 +8,7 @@ use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; use PhpSchool\PhpWorkshop\ExerciseCheck\ComposerExerciseCheck; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\Result\ComposerFailure; use PhpSchool\PhpWorkshop\Result\Failure; @@ -17,20 +18,17 @@ class ComposerCheckTest extends TestCase { - /** - * @var ComposerCheck - */ - private $check; - - /** - * @var ExerciseInterface - */ - private $exercise; + private ComposerCheck $check; + private ComposerExercise $exercise; public function setUp(): void { $this->check = new ComposerCheck(); $this->exercise = new ComposerExercise(); + } + + public function testCheckMeta(): void + { $this->assertEquals('Composer Dependency Check', $this->check->getName()); $this->assertEquals(ComposerExerciseCheck::class, $this->check->getExerciseInterface()); $this->assertEquals(SimpleCheckInterface::CHECK_BEFORE, $this->check->getPosition()); @@ -44,14 +42,13 @@ public function testExceptionIsThrownIfNotValidExercise(): void $exercise = $this->createMock(ExerciseInterface::class); $this->expectException(InvalidArgumentException::class); - $this->check->check($exercise, new Input('app')); + $this->check->check(TestContext::withoutDirectories()); } public function testCheckReturnsFailureIfNoComposerFile(): void { $result = $this->check->check( - $this->exercise, - new Input('app', ['program' => 'invalid/solution']) + TestContext::withoutDirectories(null, $this->exercise) ); $this->assertInstanceOf(ComposerFailure::class, $result); @@ -62,10 +59,10 @@ public function testCheckReturnsFailureIfNoComposerFile(): void public function testCheckReturnsFailureIfNoComposerLockFile(): void { - $result = $this->check->check( - $this->exercise, - new Input('app', ['program' => __DIR__ . '/../res/composer/not-locked/solution.php']) - ); + $context = TestContext::withDirectories(null, $this->exercise); + $context->importStudentSolutionFolder(__DIR__ . '/../res/composer/not-locked/'); + + $result = $this->check->check($context); $this->assertInstanceOf(ComposerFailure::class, $result); $this->assertSame('Composer Dependency Check', $result->getCheckName()); @@ -75,10 +72,10 @@ public function testCheckReturnsFailureIfNoComposerLockFile(): void public function testCheckReturnsFailureIfNoVendorFolder(): void { - $result = $this->check->check( - $this->exercise, - new Input('app', ['program' => __DIR__ . '/../res/composer/no-vendor/solution.php']) - ); + $context = TestContext::withDirectories(null, $this->exercise); + $context->importStudentSolutionFolder(__DIR__ . '/../res/composer/no-vendor/'); + + $result = $this->check->check($context); $this->assertInstanceOf(ComposerFailure::class, $result); $this->assertSame('Composer Dependency Check', $result->getCheckName()); @@ -88,18 +85,18 @@ public function testCheckReturnsFailureIfNoVendorFolder(): void /** * @dataProvider dependencyProvider - * - * @param string $dependency - * @param string $solutionFile */ - public function testCheckReturnsFailureIfDependencyNotRequired(string $dependency, string $solutionFile): void + public function testCheckReturnsFailureIfDependencyNotRequired(string $dependency, string $solutionFolder): void { $exercise = $this->createMock(ComposerExercise::class); $exercise->expects($this->once()) ->method('getRequiredPackages') ->willReturn([$dependency]); - $result = $this->check->check($exercise, new Input('app', ['program' => $solutionFile])); + $context = TestContext::withDirectories(null, $exercise); + $context->importStudentSolutionFolder($solutionFolder); + + $result = $this->check->check($context); $this->assertInstanceOf(ComposerFailure::class, $result); $this->assertSame('Composer Dependency Check', $result->getCheckName()); @@ -113,17 +110,17 @@ public function testCheckReturnsFailureIfDependencyNotRequired(string $dependenc public function dependencyProvider(): array { return [ - ['klein/klein', __DIR__ . '/../res/composer/no-klein/solution.php'], - ['danielstjules/stringy', __DIR__ . '/../res/composer/no-stringy/solution.php'] + ['klein/klein', __DIR__ . '/../res/composer/no-klein'], + ['danielstjules/stringy', __DIR__ . '/../res/composer/no-stringy'] ]; } public function testCheckReturnsSuccessIfCorrectLockFile(): void { - $result = $this->check->check( - $this->exercise, - new Input('app', ['program' => __DIR__ . '/../res/composer/good-solution/solution.php']) - ); + $context = TestContext::withDirectories(null, $this->exercise); + $context->importStudentSolutionFolder(__DIR__ . '/../res/composer/good-solution'); + + $result = $this->check->check($context); $this->assertInstanceOf(Success::class, $result); $this->assertSame('Composer Dependency Check', $result->getCheckName()); diff --git a/test/Check/DatabaseCheckTest.php b/test/Check/DatabaseCheckTest.php index 1a2e3ee4..3c8539a6 100644 --- a/test/Check/DatabaseCheckTest.php +++ b/test/Check/DatabaseCheckTest.php @@ -26,6 +26,7 @@ use PHPUnit\Framework\TestCase; use ReflectionProperty; use RuntimeException; +use Symfony\Component\Filesystem\Filesystem; class DatabaseCheckTest extends TestCase { @@ -50,6 +51,12 @@ public function setUp(): void ); } + public function testCheckMeta(): void + { + $this->assertEquals('Database Verification Check', $this->check->getName()); + $this->assertEquals(DatabaseExerciseCheck::class, $this->check->getExerciseInterface()); + } + private function getRunnerManager(ExerciseInterface $exercise, EventDispatcher $eventDispatcher): MockObject { $runner = $this->getMockBuilder(CliRunner::class) @@ -70,12 +77,6 @@ private function getRunnerManager(ExerciseInterface $exercise, EventDispatcher $ return $runnerManager; } - public function testCheckMeta(): void - { - $this->assertEquals('Database Verification Check', $this->check->getName()); - $this->assertEquals(DatabaseExerciseCheck::class, $this->check->getExerciseInterface()); - } - public function testIfDatabaseFolderExistsExceptionIsThrown(): void { $eventDispatcher = new EventDispatcher(new ResultAggregator()); @@ -85,7 +86,6 @@ public function testIfDatabaseFolderExistsExceptionIsThrown(): void $this->fail('Exception was not thrown'); } catch (RuntimeException $e) { $this->assertEquals(sprintf('Database directory: "%s" already exists', $this->dbDir), $e->getMessage()); - rmdir($this->dbDir); } } @@ -111,6 +111,7 @@ public function testIfPDOThrowsExceptionItCleansUp(): void $this->check = new DatabaseCheck(); $solution = SingleFileSolution::fromFile(realpath(__DIR__ . '/../res/database/solution.php')); $this->exercise->setSolution($solution); + $this->exercise->setArgs([[1, 2, 3]]); $this->exercise->setVerifier(fn () => true); @@ -130,7 +131,7 @@ public function testIfPDOThrowsExceptionItCleansUp(): void new StaticExecutionContextFactory($context) ); - $dispatcher->verify($this->exercise, new Input('app', ['program' => __DIR__ . '/../res/database/user.php'])); + $dispatcher->verify($this->exercise, new Input('app', [])); $this->assertTrue($results->isSuccessful()); } @@ -139,8 +140,8 @@ public function testSuccessIsReturnedIfDatabaseVerificationPassed(): void $solution = SingleFileSolution::fromFile(realpath(__DIR__ . '/../res/database/solution.php')); $this->exercise->setSolution($solution); $this->exercise->setArgs([[1, 2, 3]]); - $this->exercise->setVerifier(fn () => true); + $this->exercise->setVerifier(fn () => true); $this->checkRepository->registerCheck($this->check); $context = TestContext::withDirectories(null, $this->exercise); @@ -157,20 +158,16 @@ public function testSuccessIsReturnedIfDatabaseVerificationPassed(): void new StaticExecutionContextFactory($context) ); - $dispatcher->verify($this->exercise, new Input('app', ['program' => __DIR__ . '/../res/database/user.php'])); + $dispatcher->verify($this->exercise, new Input('app', [])); $this->assertTrue($results->isSuccessful()); } public function testRunExercise(): void { - $this->exercise->setArgs([[]]); - $this->checkRepository->registerCheck($this->check); - $input = new Input('app', ['program' => __DIR__ . '/../res/database/user-solution-alter-db.php']); - - $context = TestContext::withDirectories($input, $this->exercise); + $context = TestContext::withDirectories(null, $this->exercise); $context->importStudentSolution(__DIR__ . '/../res/database/user-solution-alter-db.php'); $results = new ResultAggregator(); @@ -185,7 +182,7 @@ public function testRunExercise(): void $dispatcher->run( $this->exercise, - $input, + new Input('app', []), $this->createMock(OutputInterface::class) ); } @@ -213,7 +210,7 @@ public function testFailureIsReturnedIfDatabaseVerificationFails(): void new StaticExecutionContextFactory($context) ); - $dispatcher->verify($this->exercise, new Input('app', ['program' => __DIR__ . '/../res/database/user.php'])); + $dispatcher->verify($this->exercise, new Input('app', [])); $this->assertFalse($results->isSuccessful()); $results = iterator_to_array($results); @@ -224,7 +221,6 @@ public function testAlteringDatabaseInSolutionDoesNotEffectDatabaseInUserSolutio { $solution = SingleFileSolution::fromFile(realpath(__DIR__ . '/../res/database/solution-alter-db.php')); $this->exercise->setSolution($solution); - $this->exercise->setArgs([[]]); $this->exercise->setVerifier(function (PDO $db) { $users = $db->query('SELECT * FROM users'); @@ -268,7 +264,13 @@ public function testAlteringDatabaseInSolutionDoesNotEffectDatabaseInUserSolutio $dispatcher->verify( $this->exercise, - new Input('app', ['program' => __DIR__ . '/../res/database/user-solution-alter-db.php']) + new Input('app') ); } + + protected function tearDown(): void + { + $fs = new Filesystem(); + $fs->remove($this->dbDir); + } } diff --git a/test/Check/FileComparisonCheckTest.php b/test/Check/FileComparisonCheckTest.php index 78f61a82..5b5ea794 100644 --- a/test/Check/FileComparisonCheckTest.php +++ b/test/Check/FileComparisonCheckTest.php @@ -7,24 +7,28 @@ use PhpSchool\PhpWorkshop\Exception\SolutionFileDoesNotExistException; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; use PhpSchool\PhpWorkshop\ExerciseCheck\FileComparisonExerciseCheck; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\Result\FileComparisonFailure; use PhpSchool\PhpWorkshop\Solution\SingleFileSolution; +use PhpSchool\PhpWorkshop\Solution\SolutionInterface; use PhpSchool\PhpWorkshopTest\Asset\FileComparisonExercise; use PhpSchool\PhpWorkshopTest\BaseTest; use PhpSchool\PhpWorkshop\Result\Failure; use PhpSchool\PhpWorkshop\Result\Success; +use PHPUnit\Framework\TestCase; -class FileComparisonCheckTest extends BaseTest +class FileComparisonCheckTest extends TestCase { - /** - * @var FileComparisonCheck - */ - private $check; + private FileComparisonCheck $check; public function setUp(): void { $this->check = new FileComparisonCheck(); + } + + public function testCheckMeta(): void + { $this->assertEquals('File Comparison Check', $this->check->getName()); $this->assertEquals(FileComparisonExerciseCheck::class, $this->check->getExerciseInterface()); $this->assertEquals(SimpleCheckInterface::CHECK_AFTER, $this->check->getPosition()); @@ -39,19 +43,18 @@ public function testExceptionIsThrownIfReferenceFileDoesNotExist(): void $this->expectExceptionMessage('File: "some-file.txt" does not exist in solution folder'); $exercise = new FileComparisonExercise(['some-file.txt']); - $exercise->setSolution(new SingleFileSolution($this->getTemporaryFile('solution/solution.php'))); + $context = TestContext::withDirectories(null, $exercise); - $this->check->check($exercise, new Input('app', ['program' => 'my-solution.php'])); + $this->check->check($context); } public function testFailureIsReturnedIfStudentsFileDoesNotExist(): void { - $referenceFile = $this->getTemporaryFile('solution/some-file.txt', "name,age\nAydin,33\nMichael,29\n"); - $exercise = new FileComparisonExercise(['some-file.txt']); - $exercise->setSolution(new SingleFileSolution($this->getTemporaryFile('solution/solution.php'))); + $context = TestContext::withDirectories(null, $exercise); + $context->importReferenceFileFromString("name,age\nAydin,33\nMichael,29\n", 'some-file.txt'); - $failure = $this->check->check($exercise, new Input('app', ['program' => 'my-solution.php'])); + $failure = $this->check->check($context); $this->assertInstanceOf(Failure::class, $failure); $this->assertEquals('File: "some-file.txt" does not exist', $failure->getReason()); @@ -59,15 +62,12 @@ public function testFailureIsReturnedIfStudentsFileDoesNotExist(): void public function testFailureIsReturnedIfStudentFileDosNotMatchReferenceFile(): void { - $referenceFile = $this->getTemporaryFile('solution/some-file.txt', "name,age\nAydin,33\nMichael,29\n"); - $studentFile = $this->getTemporaryFile('student/some-file.txt', "somegibberish"); - $exercise = new FileComparisonExercise(['some-file.txt']); - $exercise->setSolution(new SingleFileSolution($this->getTemporaryFile('solution/solution.php'))); + $context = TestContext::withDirectories(null, $exercise); + $context->importStudentFileFromString("somegibberish", 'some-file.txt'); + $context->importReferenceFileFromString("name,age\nAydin,33\nMichael,29\n", 'some-file.txt'); - $failure = $this->check->check($exercise, new Input('app', [ - 'program' => $this->getTemporaryFile('student/my-solution.php') - ])); + $failure = $this->check->check($context); $this->assertInstanceOf(FileComparisonFailure::class, $failure); $this->assertEquals($failure->getFileName(), 'some-file.txt'); @@ -77,37 +77,24 @@ public function testFailureIsReturnedIfStudentFileDosNotMatchReferenceFile(): vo public function testSuccessIsReturnedIfFilesMatch(): void { - $referenceFile = $this->getTemporaryFile('solution/some-file.txt', "name,age\nAydin,33\nMichael,29\n"); - $studentFile = $this->getTemporaryFile('student/some-file.txt', "name,age\nAydin,33\nMichael,29\n"); - $exercise = new FileComparisonExercise(['some-file.txt']); - $exercise->setSolution(new SingleFileSolution($this->getTemporaryFile('solution/solution.php'))); - - $this->assertInstanceOf( - Success::class, - $this->check->check($exercise, new Input('app', [ - 'program' => $this->getTemporaryFile('student/my-solution.php') - ])) - ); + $context = TestContext::withDirectories(null, $exercise); + + $context->importStudentFileFromString("name,age\nAydin,33\nMichael,29\n", 'some-file.txt'); + $context->importReferenceFileFromString("name,age\nAydin,33\nMichael,29\n", 'some-file.txt'); + + $this->assertInstanceOf(Success::class, $this->check->check($context)); } public function testFailureIsReturnedIfFileDoNotMatchUsingStrip(): void { - $referenceFile = $this->getTemporaryFile( - 'solution/some-file.txt', - "01:03name,age\n04:05Aydin,33\n17:21Michael,29\n" - ); - $studentFile = $this->getTemporaryFile( - 'student/some-file.txt', - "01:04name,age\n06:76Aydin,34\n99:00Michael,29\n" - ); - $exercise = new FileComparisonExercise(['some-file.txt' => ['strip' => '/\d{2}:\d{2}/']]); - $exercise->setSolution(new SingleFileSolution($this->getTemporaryFile('solution/solution.php'))); + $context = TestContext::withDirectories(null, $exercise); + + $context->importStudentFileFromString("01:04name,age\n06:76Aydin,34\n99:00Michael,29\n", 'some-file.txt'); + $context->importReferenceFileFromString("01:03name,age\n04:05Aydin,33\n17:21Michael,29\n", 'some-file.txt'); - $failure = $this->check->check($exercise, new Input('app', [ - 'program' => $this->getTemporaryFile('student/my-solution.php') - ])); + $failure = $this->check->check($context); $this->assertInstanceOf(FileComparisonFailure::class, $failure); $this->assertEquals($failure->getFileName(), 'some-file.txt'); diff --git a/test/Check/FileExistsCheckTest.php b/test/Check/FileExistsCheckTest.php index 8afb8c8a..2874b58a 100644 --- a/test/Check/FileExistsCheckTest.php +++ b/test/Check/FileExistsCheckTest.php @@ -4,7 +4,9 @@ use PhpSchool\PhpWorkshop\Check\SimpleCheckInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext; use PhpSchool\PhpWorkshop\Input\Input; +use PhpSchool\PhpWorkshop\Utils\Path; use PHPUnit\Framework\TestCase; use PhpSchool\PhpWorkshop\Check\FileExistsCheck; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; @@ -13,27 +15,15 @@ class FileExistsCheckTest extends TestCase { - /** - * @var string - */ - private $testDir; - - /** - * @var FileExistsCheck - */ - private $check; - - /** - * @var ExerciseInterface - */ - private $exercise; + private FileExistsCheck $check; public function setUp(): void { - $this->testDir = sprintf('%s/%s', sys_get_temp_dir(), $this->getName()); - mkdir($this->testDir, 0777, true); $this->check = new FileExistsCheck(); - $this->exercise = $this->createMock(ExerciseInterface::class); + } + + public function testCheckMeta(): void + { $this->assertEquals('File Exists Check', $this->check->getName()); $this->assertEquals(ExerciseInterface::class, $this->check->getExerciseInterface()); $this->assertEquals(SimpleCheckInterface::CHECK_BEFORE, $this->check->getPosition()); @@ -44,26 +34,27 @@ public function setUp(): void public function testSuccess(): void { - $file = sprintf('%s/test.txt', $this->testDir); - touch($file); + $context = TestContext::withDirectories(); + $context->importStudentFileFromString('assertInstanceOf( Success::class, - $this->check->check($this->exercise, new Input('app', ['program' => $file])) + $this->check->check($context) ); - unlink($file); } public function testFailure(): void { - $file = sprintf('%s/test.txt', $this->testDir); - $failure = $this->check->check($this->exercise, new Input('app', ['program' => $file])); - $this->assertInstanceOf(Failure::class, $failure); - $this->assertEquals(sprintf('File: "%s" does not exist', $file), $failure->getReason()); - } + $context = TestContext::withDirectories(); - public function tearDown(): void - { - rmdir($this->testDir); + $failure = $this->check->check($context); + $this->assertInstanceOf(Failure::class, $failure); + $this->assertEquals( + sprintf( + 'File: "%s" does not exist', + Path::join($context->getStudentExecutionDirectory(), 'solution.php') + ), + $failure->getReason() + ); } } diff --git a/test/Check/FunctionRequirementsCheckTest.php b/test/Check/FunctionRequirementsCheckTest.php index 70a10249..b6bafbcf 100644 --- a/test/Check/FunctionRequirementsCheckTest.php +++ b/test/Check/FunctionRequirementsCheckTest.php @@ -7,6 +7,7 @@ use PhpParser\ParserFactory; use PhpSchool\PhpWorkshop\Check\SimpleCheckInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshopTest\Asset\FunctionRequirementsExercise; use PHPUnit\Framework\TestCase; @@ -19,20 +20,9 @@ class FunctionRequirementsCheckTest extends TestCase { - /** - * @var FunctionRequirementsCheck - */ - private $check; - - /** - * @var ExerciseInterface - */ - private $exercise; - - /** - * @var Parser - */ - private $parser; + private FunctionRequirementsCheck $check; + private FunctionRequirementsExercise $exercise; + private Parser $parser; public function setUp(): void { @@ -40,6 +30,10 @@ public function setUp(): void $this->parser = $parserFactory->create(ParserFactory::PREFER_PHP7); $this->check = new FunctionRequirementsCheck($this->parser); $this->exercise = new FunctionRequirementsExercise(); + } + + public function testCheckMeta(): void + { $this->assertEquals('Function Requirements Check', $this->check->getName()); $this->assertEquals(FunctionRequirementsExerciseCheck::class, $this->check->getExerciseInterface()); $this->assertEquals(SimpleCheckInterface::CHECK_AFTER, $this->check->getPosition()); @@ -53,25 +47,29 @@ public function testExceptionIsThrownIfNotValidExercise(): void $exercise = $this->createMock(ExerciseInterface::class); $this->expectException(InvalidArgumentException::class); - $this->check->check($exercise, new Input('app')); + $this->check->check(TestContext::withoutDirectories(null, $exercise)); } public function testFailureIsReturnedIfCodeCouldNotBeParsed(): void { - $file = __DIR__ . '/../res/function-requirements/fail-invalid-code.php'; - $failure = $this->check->check($this->exercise, new Input('app', ['program' => $file])); - $this->assertInstanceOf(Failure::class, $failure); + $context = TestContext::withDirectories(null, $this->exercise); + $context->importStudentSolution(__DIR__ . '/../res/function-requirements/fail-invalid-code.php'); + $failure = $this->check->check($context); - $message = sprintf('File: "%s" could not be parsed. Error: "Syntax error, unexpected T_ECHO on line 4"', $file); + $this->assertInstanceOf(Failure::class, $failure); + $message = sprintf( + 'File: "%s/solution.php" could not be parsed. Error: "Syntax error, unexpected T_ECHO on line 4"', + $context->getStudentExecutionDirectory() + ); $this->assertEquals($message, $failure->getReason()); } public function testFailureIsReturnedIfBannedFunctionsAreUsed(): void { - $failure = $this->check->check( - $this->exercise, - new Input('app', ['program' => __DIR__ . '/../res/function-requirements/fail-banned-function.php']) - ); + $context = TestContext::withDirectories(null, $this->exercise); + $context->importStudentSolution(__DIR__ . '/../res/function-requirements/fail-banned-function.php'); + $failure = $this->check->check($context); + $this->assertInstanceOf(FunctionRequirementsFailure::class, $failure); $this->assertEquals([['function' => 'file', 'line' => 3]], $failure->getBannedFunctions()); $this->assertEquals([], $failure->getMissingFunctions()); @@ -90,12 +88,11 @@ public function testFailureIsReturnedIfNotAllRequiredFunctionsHaveBeenUsed(): vo ->method('getRequiredFunctions') ->willReturn(['file_get_contents', 'implode']); - $failure = $this->check->check( - $exercise, - new Input('app', ['program' => __DIR__ . '/../res/function-requirements/fail-banned-function.php']) - ); - $this->assertInstanceOf(FunctionRequirementsFailure::class, $failure); + $context = TestContext::withDirectories(null, $exercise); + $context->importStudentSolution(__DIR__ . '/../res/function-requirements/fail-banned-function.php'); + $failure = $this->check->check($context); + $this->assertInstanceOf(FunctionRequirementsFailure::class, $failure); $this->assertEquals(['file_get_contents', 'implode'], $failure->getMissingFunctions()); $this->assertEquals([], $failure->getBannedFunctions()); } @@ -113,10 +110,10 @@ public function testSuccess(): void ->method('getRequiredFunctions') ->willReturn(['file_get_contents']); - $success = $this->check->check( - $exercise, - new Input('app', ['program' => __DIR__ . '/../res/function-requirements/success.php']) - ); + $context = TestContext::withDirectories(null, $exercise); + $context->importStudentSolution(__DIR__ . '/../res/function-requirements/success.php'); + $success = $this->check->check($context); + $this->assertInstanceOf(Success::class, $success); } } diff --git a/test/Check/PhpLintCheckTest.php b/test/Check/PhpLintCheckTest.php index 82c3025d..3bad4857 100644 --- a/test/Check/PhpLintCheckTest.php +++ b/test/Check/PhpLintCheckTest.php @@ -4,6 +4,8 @@ use PhpSchool\PhpWorkshop\Check\SimpleCheckInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; +use PhpSchool\PhpWorkshop\ExerciseCheck\FunctionRequirementsExerciseCheck; +use PhpSchool\PhpWorkshop\ExerciseRunner\Context\TestContext; use PhpSchool\PhpWorkshop\Input\Input; use PHPUnit\Framework\TestCase; use PhpSchool\PhpWorkshop\Check\PhpLintCheck; @@ -16,20 +18,17 @@ class PhpLintCheckTest extends TestCase { use AssertionRenames; - /** - * @var PhpLintCheck - */ - private $check; - - /** - * @var ExerciseInterface - */ - private $exercise; + private PhpLintCheck $check; + private ExerciseInterface $exercise; public function setUp(): void { $this->check = new PhpLintCheck(); $this->exercise = $this->createMock(ExerciseInterface::class); + } + + public function testCheckMeta(): void + { $this->assertEquals('PHP Code Check', $this->check->getName()); $this->assertEquals(ExerciseInterface::class, $this->check->getExerciseInterface()); $this->assertEquals(SimpleCheckInterface::CHECK_BEFORE, $this->check->getPosition()); @@ -40,18 +39,24 @@ public function setUp(): void public function testSuccess(): void { + $context = TestContext::withDirectories(null, $this->exercise); + $context->importStudentSolution(__DIR__ . '/../res/lint/pass.php'); + + $res = $this->check->check($context); + $this->assertInstanceOf( Success::class, - $this->check->check($this->exercise, new Input('app', ['program' => __DIR__ . '/../res/lint/pass.php'])) + $this->check->check($context) ); } public function testFailure(): void { - $failure = $this->check->check( - $this->exercise, - new Input('app', ['program' => __DIR__ . '/../res/lint/fail.php']) - ); + $context = TestContext::withDirectories(null, $this->exercise); + $context->importStudentSolution(__DIR__ . '/../res/lint/fail.php'); + + $failure = $this->check->check($context); + $this->assertInstanceOf(Failure::class, $failure); $this->assertMatchesRegularExpression( "/(PHP )?Parse error:\W+syntax error, unexpected end of file, expecting ['\"][,;]['\"] or ['\"][;,]['\"]/", diff --git a/test/ExerciseDispatcherTest.php b/test/ExerciseDispatcherTest.php index 3b897c5d..a227e28c 100644 --- a/test/ExerciseDispatcherTest.php +++ b/test/ExerciseDispatcherTest.php @@ -228,7 +228,9 @@ public function testVerify(): void $check->method('canRun')->with($exercise->getType())->willReturn(true); $check->method('getPosition')->willReturn(SimpleCheckInterface::CHECK_BEFORE); $check->method('getExerciseInterface')->willReturn(ExerciseInterface::class); - $check->method('check')->with($exercise, $input)->willReturn(new Success('Success!')); + $check->method('check') + ->with($this->isInstanceOf(ExecutionContext::class)) + ->willReturn(new Success('Success!')); $runner = $this->createMock(ExerciseRunnerInterface::class); $runner->method('getRequiredChecks')->willReturn([get_class($check)]); @@ -273,7 +275,7 @@ public function testVerifyOnlyRunsRequiredChecks(): void $check1 ->method('check') - ->with($exercise, $input) + ->with($this->isInstanceOf(ExecutionContext::class)) ->willReturn(new Success('Success!')); $check2 = $this @@ -284,7 +286,7 @@ public function testVerifyOnlyRunsRequiredChecks(): void $check2 ->expects($this->never()) ->method('check') - ->with($exercise, $input); + ->with($this->isInstanceOf(ExecutionContext::class)); $runner = $this->createMock(ExerciseRunnerInterface::class); $runner @@ -324,13 +326,17 @@ public function testVerifyWithBeforeAndAfterRequiredChecks(): void $check1->method('canRun')->with($exercise->getType())->willReturn(true); $check1->method('getPosition')->willReturn(SimpleCheckInterface::CHECK_BEFORE); $check1->method('getExerciseInterface')->willReturn(ExerciseInterface::class); - $check1->method('check')->with($exercise, $input)->willReturn(new Success('Success!')); + $check1->method('check') + ->with($this->isInstanceOf(ExecutionContext::class)) + ->willReturn(new Success('Success!')); $check2 = $this->createMock(SimpleCheckInterface::class); $check2->method('canRun')->with($exercise->getType())->willReturn(true); $check2->method('getPosition')->willReturn(SimpleCheckInterface::CHECK_AFTER); $check2->method('getExerciseInterface')->willReturn(ExerciseInterface::class); - $check2->method('check')->with($exercise, $input)->willReturn(new Success('Success!')); + $check2->method('check') + ->with($this->isInstanceOf(ExecutionContext::class)) + ->willReturn(new Success('Success!')); $runner = $this->createMock(ExerciseRunnerInterface::class); $runner->method('getRequiredChecks')->willReturn([get_class($check1), get_class($check2)]); @@ -377,7 +383,7 @@ public function testWhenBeforeChecksFailTheyReturnImmediately(): void $check1 ->method('check') - ->with($exercise, $input) + ->with($this->isInstanceOf(ExecutionContext::class)) ->willReturn(new Failure('Failure', 'nope')); $check2 = $this @@ -400,7 +406,7 @@ public function testWhenBeforeChecksFailTheyReturnImmediately(): void $check2 ->expects($this->never()) ->method('check') - ->with($exercise, $input); + ->with($this->isInstanceOf(ExecutionContext::class)); $runner = $this->createMock(ExerciseRunnerInterface::class); $runner