diff --git a/app/config.php b/app/config.php index d82897da..ca78d61a 100644 --- a/app/config.php +++ b/app/config.php @@ -22,6 +22,7 @@ use PhpSchool\PhpWorkshop\ExerciseDispatcher; use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CgiRunnerFactory; use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CliRunnerFactory; +use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CustomVerifyingRunnerFactory; use PhpSchool\PhpWorkshop\ExerciseRunner\RunnerManager; use PhpSchool\PhpWorkshop\Factory\EventDispatcherFactory; use PhpSchool\PhpWorkshop\Factory\MenuFactory; @@ -125,6 +126,7 @@ $manager = new RunnerManager; $manager->addFactory(new CliRunnerFactory($c->get(EventDispatcher::class))); $manager->addFactory(new CgiRunnerFactory($c->get(EventDispatcher::class))); + $manager->addFactory(new CustomVerifyingRunnerFactory); return $manager; }, @@ -326,25 +328,25 @@ containerListener(CodePatchListener::class, 'patch'), ], 'cli.verify.finish' => [ - containerListener(CodePatchListener::class, 'patch'), + containerListener(CodePatchListener::class, 'revert'), ], 'cli.run.start' => [ containerListener(CodePatchListener::class, 'patch'), ], 'cli.run.finish' => [ - containerListener(CodePatchListener::class, 'patch'), + containerListener(CodePatchListener::class, 'revert'), ], 'cgi.verify.start' => [ containerListener(CodePatchListener::class, 'patch'), ], 'cgi.verify.finish' => [ - containerListener(CodePatchListener::class, 'patch'), + containerListener(CodePatchListener::class, 'revert'), ], 'cgi.run.start' => [ containerListener(CodePatchListener::class, 'patch'), ], 'cgi.run.finish' => [ - containerListener(CodePatchListener::class, 'patch'), + containerListener(CodePatchListener::class, 'revert'), ], ], 'self-check' => [ diff --git a/src/Exercise/CustomVerifyingExercise.php b/src/Exercise/CustomVerifyingExercise.php new file mode 100644 index 00000000..a3d4cbfc --- /dev/null +++ b/src/Exercise/CustomVerifyingExercise.php @@ -0,0 +1,16 @@ + + */ +interface CustomVerifyingExercise +{ + /** + * @return ResultInterface + */ + public function verify(); +} diff --git a/src/Exercise/ExerciseType.php b/src/Exercise/ExerciseType.php index 893e27a5..d01575f6 100644 --- a/src/Exercise/ExerciseType.php +++ b/src/Exercise/ExerciseType.php @@ -20,6 +20,8 @@ class ExerciseType extends Enum { const CLI = 'CLI'; const CGI = 'CGI'; + const CUSTOM = 'CUSTOM'; + /** * Map of exercise types to the required interfaces exercises of that particular @@ -30,6 +32,7 @@ class ExerciseType extends Enum private static $exerciseTypeToExerciseInterfaceMap = [ self::CLI => CliExercise::class, self::CGI => CgiExercise::class, + self::CUSTOM => CustomVerifyingExercise::class, ]; /** diff --git a/src/ExerciseRunner/CustomVerifyingRunner.php b/src/ExerciseRunner/CustomVerifyingRunner.php new file mode 100644 index 00000000..836db2e0 --- /dev/null +++ b/src/ExerciseRunner/CustomVerifyingRunner.php @@ -0,0 +1,75 @@ + + */ +class CustomVerifyingRunner implements ExerciseRunnerInterface +{ + /** + * @var CustomVerifyingExercise + */ + private $exercise; + + /** + * @param CustomVerifyingExercise $exercise + */ + public function __construct(CustomVerifyingExercise $exercise) + { + $this->exercise = $exercise; + } + + /** + * Get the name of the exercise runner. + * + * @return string + */ + public function getName() + { + return 'Custom Verifying Runner'; + } + + /** + * Get an array of the class names of the required checks this runner needs. + * + * @return array + */ + public function getRequiredChecks() + { + return []; + } + + /** + * Delegate to the exercise for verifying. Verifying could mean checking that a program was installed or that some + * other arbitrary task was performed. + * + * @param Input $input The command line arguments passed to the command. + * @return ResultInterface The result of the check. + */ + public function verify(Input $input) + { + return $this->exercise->verify(); + } + + /** + * Running a custom verifying exercise does nothing. There is no program required, therefore there is nothing + * to run. + * + * @param Input $input The command line arguments passed to the command. + * @param OutputInterface $output A wrapper around STDOUT. + * @return bool If the solution was successfully executed, eg. exit code was 0. + */ + public function run(Input $input, OutputInterface $output) + { + $message = 'Nothing to run here. This exercise does not require a code solution, '; + $message .= 'so there is nothing to execute.'; + $output->writeLine($message); + return true; + } +} diff --git a/src/ExerciseRunner/Factory/CustomVerifyingRunnerFactory.php b/src/ExerciseRunner/Factory/CustomVerifyingRunnerFactory.php new file mode 100644 index 00000000..3645de7a --- /dev/null +++ b/src/ExerciseRunner/Factory/CustomVerifyingRunnerFactory.php @@ -0,0 +1,51 @@ + + */ +class CustomVerifyingRunnerFactory implements ExerciseRunnerFactoryInterface +{ + /** + * @var string + */ + private static $type = ExerciseType::CUSTOM; + + /** + * Whether the factory supports this exercise type. + * + * @param ExerciseInterface $exercise + * @return bool + */ + public function supports(ExerciseInterface $exercise) + { + return $exercise->getType()->getValue() === self::$type; + } + + /** + * Add any extra required arguments to the command. + * + * @param CommandDefinition $commandDefinition + */ + public function configureInput(CommandDefinition $commandDefinition) + { + } + + /** + * Create and return an instance of the runner. + * + * @param ExerciseInterface $exercise + * @return ExerciseRunnerInterface + */ + public function create(ExerciseInterface $exercise) + { + return new CustomVerifyingRunner($exercise); + } +} diff --git a/test/Asset/CustomVerifyingExerciseImpl.php b/test/Asset/CustomVerifyingExerciseImpl.php new file mode 100644 index 00000000..a715311b --- /dev/null +++ b/test/Asset/CustomVerifyingExerciseImpl.php @@ -0,0 +1,55 @@ + + */ +class CustomVerifyingExerciseImpl extends AbstractExercise implements ExerciseInterface, CustomVerifyingExercise +{ + + /** + * Get the name of the exercise, like `Hello World!`. + * + * @return string + */ + public function getName() + { + return 'Custom Verifying exercise'; + } + + /** + * A short description of the exercise. + * + * @return string + */ + public function getDescription() + { + return 'Custom Verifying exercise'; + } + + /** + * Return the type of exercise. This is an ENUM. See `PhpSchool\PhpWorkshop\Exercise\ExerciseType`. + * + * @return ExerciseType + */ + public function getType() + { + return ExerciseType::CUSTOM(); + } + + /** + * @return ResultInterface + */ + public function verify() + { + return new Success('success'); + } +} diff --git a/test/ExerciseRunner/CustomVerifyingRunnerTest.php b/test/ExerciseRunner/CustomVerifyingRunnerTest.php new file mode 100644 index 00000000..411297c0 --- /dev/null +++ b/test/ExerciseRunner/CustomVerifyingRunnerTest.php @@ -0,0 +1,58 @@ + + */ +class ExtRunnerTest extends PHPUnit_Framework_TestCase +{ + /** + * @var CustomVerifyingRunner + */ + private $runner; + + /** + * @var CustomVerifyingExerciseImpl + */ + private $exercise; + + public function setUp() + { + $this->exercise = new CustomVerifyingExerciseImpl; + $this->runner = new CustomVerifyingRunner($this->exercise); + + $this->assertEquals('Custom Verifying Runner', $this->runner->getName()); + } + + public function testRequiredChecks() + { + $this->assertEquals([], $this->runner->getRequiredChecks()); + } + + public function testRunOutputsErrorMessage() + { + $color = new Color; + $color->setForceStyle(true); + $output = new StdOutput($color, $this->createMock(TerminalInterface::class)); + + $exp = 'Nothing to run here. This exercise does not require a code solution, '; + $exp .= "so there is nothing to execute.\n"; + + $this->expectOutputString($exp); + + $this->runner->run(new Input('app'), $output); + } + + public function testVerifyProxiesToExercise() + { + self::assertEquals($this->exercise->verify(), $this->runner->verify(new Input('app'))); + } +} diff --git a/test/ExerciseRunner/Factory/CliRunnerFactoryTest.php b/test/ExerciseRunner/Factory/CliRunnerFactoryTest.php index f6469cc6..bff2134c 100644 --- a/test/ExerciseRunner/Factory/CliRunnerFactoryTest.php +++ b/test/ExerciseRunner/Factory/CliRunnerFactoryTest.php @@ -4,13 +4,11 @@ use PhpSchool\PhpWorkshop\CommandDefinition; use PhpSchool\PhpWorkshop\Event\EventDispatcher; -use PhpSchool\PhpWorkshop\Exercise\CliExercise; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\Exercise\ExerciseType; use PhpSchool\PhpWorkshop\ExerciseRunner\CliRunner; use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CliRunnerFactory; use PhpSchool\PhpWorkshopTest\Asset\CliExerciseImpl; -use PhpSchool\PhpWorkshopTest\Asset\CliExerciseInterface; use PHPUnit_Framework_TestCase; /** diff --git a/test/ExerciseRunner/Factory/CustomVerifyingRunnerFactoryTest.php b/test/ExerciseRunner/Factory/CustomVerifyingRunnerFactoryTest.php new file mode 100644 index 00000000..ce5d8405 --- /dev/null +++ b/test/ExerciseRunner/Factory/CustomVerifyingRunnerFactoryTest.php @@ -0,0 +1,57 @@ + + */ +class CustomRunnerFactoryTest extends PHPUnit_Framework_TestCase +{ + /** + * @var CustomVerifyingRunnerFactory + */ + private $factory; + + public function setUp() + { + $this->factory = new CustomVerifyingRunnerFactory; + } + + public function testSupports() + { + $exercise1 = $this->prophesize(ExerciseInterface::class); + $exercise2 = $this->prophesize(ExerciseInterface::class); + $exercise3 = $this->prophesize(ExerciseInterface::class); + + $exercise1->getType()->willReturn(ExerciseType::CLI()); + $exercise2->getType()->willReturn(ExerciseType::CGI()); + $exercise3->getType()->willReturn(ExerciseType::CUSTOM()); + + $this->assertFalse($this->factory->supports($exercise1->reveal())); + $this->assertFalse($this->factory->supports($exercise2->reveal())); + $this->assertTrue($this->factory->supports($exercise3->reveal())); + } + + public function testConfigureInputAddsNoArgument() + { + $command = new CommandDefinition('my-command', [], 'var_dump'); + + $this->factory->configureInput($command); + $this->assertCount(0, $command->getRequiredArgs()); + } + + public function testCreateReturnsRunner() + { + $exercise = new CustomVerifyingExerciseImpl; + $this->assertInstanceOf(CustomVerifyingRunner::class, $this->factory->create($exercise)); + } +}