diff --git a/app/config.php b/app/config.php index 3eaf630a..7b64b923 100644 --- a/app/config.php +++ b/app/config.php @@ -63,6 +63,7 @@ use PhpSchool\PhpWorkshop\Utils\RequestRenderer; use PhpSchool\PhpWorkshop\WorkshopType; use PhpSchool\PhpWorkshop\Check\FileExistsCheck; +use PhpSchool\PhpWorkshop\Check\CodeExistsCheck; use PhpSchool\PhpWorkshop\Check\FunctionRequirementsCheck; use PhpSchool\PhpWorkshop\Check\PhpLintCheck; use PhpSchool\PhpWorkshop\Command\CreditsCommand; @@ -109,6 +110,7 @@ CheckRepository::class => function (ContainerInterface $c) { return new CheckRepository([ $c->get(FileExistsCheck::class), + $c->get(CodeExistsCheck::class), $c->get(PhpLintCheck::class), $c->get(CodeParseCheck::class), $c->get(ComposerCheck::class), @@ -239,6 +241,9 @@ //checks FileExistsCheck::class => create(), PhpLintCheck::class => create(), + CodeExistsCheck::class => function (ContainerInterface $c) { + return new CodeExistsCheck($c->get(Parser::class)); + }, CodeParseCheck::class => function (ContainerInterface $c) { return new CodeParseCheck($c->get(Parser::class)); }, diff --git a/src/Check/CodeExistsCheck.php b/src/Check/CodeExistsCheck.php new file mode 100644 index 00000000..a7277db8 --- /dev/null +++ b/src/Check/CodeExistsCheck.php @@ -0,0 +1,85 @@ +parser = $parser; + } + + public function getName(): string + { + return 'Code Exists Check'; + } + + /** + * 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 + { + $noopHandler = new class implements ErrorHandler { + public function handleError(Error $error): void + { + } + }; + + $code = (string) file_get_contents($input->getRequiredArgument('program')); + $statements = $this->parser->parse($code, $noopHandler); + + $empty = null === $statements || empty($statements); + + if (!$empty) { + $openingTag = is_array($statements) && count($statements) === 1 ? $statements[0] : null; + $empty = $openingTag instanceof InlineHTML ? in_array($openingTag->value, ['getValue(), [ExerciseType::CGI, ExerciseType::CLI], true); + } + + public function getExerciseInterface(): string + { + return ExerciseInterface::class; + } + + /** + * This check must run before executing the solution because all solutions require code + */ + public function getPosition(): string + { + return SimpleCheckInterface::CHECK_BEFORE; + } +} diff --git a/src/ExerciseRunner/CgiRunner.php b/src/ExerciseRunner/CgiRunner.php index c5fd6305..053e103d 100644 --- a/src/ExerciseRunner/CgiRunner.php +++ b/src/ExerciseRunner/CgiRunner.php @@ -5,6 +5,7 @@ namespace PhpSchool\PhpWorkshop\ExerciseRunner; use GuzzleHttp\Psr7\Message; +use PhpSchool\PhpWorkshop\Check\CodeExistsCheck; use PhpSchool\PhpWorkshop\Check\CodeParseCheck; use PhpSchool\PhpWorkshop\Check\FileExistsCheck; use PhpSchool\PhpWorkshop\Check\PhpLintCheck; @@ -55,6 +56,7 @@ class CgiRunner implements ExerciseRunnerInterface */ private static $requiredChecks = [ FileExistsCheck::class, + CodeExistsCheck::class, PhpLintCheck::class, CodeParseCheck::class, ]; diff --git a/src/ExerciseRunner/CliRunner.php b/src/ExerciseRunner/CliRunner.php index 3aca8dc0..af3fa4c9 100644 --- a/src/ExerciseRunner/CliRunner.php +++ b/src/ExerciseRunner/CliRunner.php @@ -4,6 +4,7 @@ namespace PhpSchool\PhpWorkshop\ExerciseRunner; +use PhpSchool\PhpWorkshop\Check\CodeExistsCheck; use PhpSchool\PhpWorkshop\Check\CodeParseCheck; use PhpSchool\PhpWorkshop\Check\FileExistsCheck; use PhpSchool\PhpWorkshop\Check\PhpLintCheck; @@ -50,6 +51,7 @@ class CliRunner implements ExerciseRunnerInterface */ private static $requiredChecks = [ FileExistsCheck::class, + CodeExistsCheck::class, PhpLintCheck::class, CodeParseCheck::class, ]; diff --git a/test/Check/CodeExistsCheckTest.php b/test/Check/CodeExistsCheckTest.php new file mode 100644 index 00000000..662b2e53 --- /dev/null +++ b/test/Check/CodeExistsCheckTest.php @@ -0,0 +1,81 @@ +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); + $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, 'assertInstanceOf( + Success::class, + $this->check->check($this->exercise, new Input('app', ['program' => $this->file])) + ); + } + + public function testFailure(): void + { + file_put_contents($this->file, 'check->check($this->exercise, new Input('app', ['program' => $this->file])); + + $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/ExerciseRunner/CgiRunnerTest.php b/test/ExerciseRunner/CgiRunnerTest.php index b01152a2..20bcde6e 100644 --- a/test/ExerciseRunner/CgiRunnerTest.php +++ b/test/ExerciseRunner/CgiRunnerTest.php @@ -4,6 +4,7 @@ use Colors\Color; use GuzzleHttp\Psr7\Request; +use PhpSchool\PhpWorkshop\Check\CodeExistsCheck; use PhpSchool\Terminal\Terminal; use PhpSchool\PhpWorkshop\Check\CodeParseCheck; use PhpSchool\PhpWorkshop\Check\FileExistsCheck; @@ -53,6 +54,7 @@ public function testRequiredChecks(): void { $requiredChecks = [ FileExistsCheck::class, + CodeExistsCheck::class, PhpLintCheck::class, CodeParseCheck::class, ]; diff --git a/test/ExerciseRunner/CliRunnerTest.php b/test/ExerciseRunner/CliRunnerTest.php index 3f3b4811..602692e2 100644 --- a/test/ExerciseRunner/CliRunnerTest.php +++ b/test/ExerciseRunner/CliRunnerTest.php @@ -3,6 +3,7 @@ namespace PhpSchool\PhpWorkshopTest\ExerciseRunner; use Colors\Color; +use PhpSchool\PhpWorkshop\Check\CodeExistsCheck; use PhpSchool\Terminal\Terminal; use PhpSchool\PhpWorkshop\Check\CodeParseCheck; use PhpSchool\PhpWorkshop\Check\FileExistsCheck; @@ -54,6 +55,7 @@ public function testRequiredChecks(): void { $requiredChecks = [ FileExistsCheck::class, + CodeExistsCheck::class, PhpLintCheck::class, CodeParseCheck::class, ];