diff --git a/app/config.php b/app/config.php index bcc18d5f..aaad2245 100644 --- a/app/config.php +++ b/app/config.php @@ -23,6 +23,7 @@ use PhpSchool\PhpWorkshop\Factory\MenuFactory; use PhpSchool\PhpWorkshop\Factory\ResultRendererFactory; use PhpSchool\PhpWorkshop\Factory\RunnerFactory; +use PhpSchool\PhpWorkshop\Listener\CheckExerciseAssignedListener; use PhpSchool\PhpWorkshop\Listener\CodePatchListener; use PhpSchool\PhpWorkshop\Listener\PrepareSolutionListener; use PhpSchool\PhpWorkshop\Listener\SelfCheckListener; @@ -148,7 +149,6 @@ $c->get(ExerciseRepository::class), $c->get(ExerciseDispatcher::class), $c->get(UserState::class), - $c->get(UserStateSerializer::class), $c->get(OutputInterface::class) ); }, @@ -178,6 +178,9 @@ SelfCheckListener::class => function (ContainerInterface $c) { return new SelfCheckListener($c->get(ResultAggregator::class)); }, + CheckExerciseAssignedListener::class => function (ContainerInterface $c) { + return new CheckExerciseAssignedListener($c->get(UserState::class)); + }, //checks FileExistsCheck::class => object(), @@ -260,5 +263,10 @@ '@shakeyShane' => 'Shane Osbourne', '@chris3ailey' => 'Chris Bailey' ], - 'appContributors' => [] + 'appContributors' => [], + 'eventListeners' => [ + 'route.pre.resolve.args' => [ + CheckExerciseAssignedListener::class + ], + ] ]; diff --git a/src/Command/PrintCommand.php b/src/Command/PrintCommand.php index 05000a9a..14453bed 100644 --- a/src/Command/PrintCommand.php +++ b/src/Command/PrintCommand.php @@ -64,11 +64,6 @@ public function __construct( */ public function __invoke() { - if (!$this->userState->isAssignedExercise()) { - $this->output->printError("No active exercises. Select one from the menu"); - return 1; - } - $currentExercise = $this->userState->getCurrentExercise(); $exercise = $this->exerciseRepository->findByName($currentExercise); diff --git a/src/Command/RunCommand.php b/src/Command/RunCommand.php index 123332f1..445b263f 100644 --- a/src/Command/RunCommand.php +++ b/src/Command/RunCommand.php @@ -31,11 +31,6 @@ class RunCommand */ private $userState; - /** - * @var UserStateSerializer - */ - private $userStateSerializer; - /** * @var ExerciseDispatcher */ @@ -45,20 +40,17 @@ class RunCommand * @param ExerciseRepository $exerciseRepository * @param ExerciseDispatcher $exerciseDispatcher * @param UserState $userState - * @param UserStateSerializer $userStateSerializer * @param OutputInterface $output */ public function __construct( ExerciseRepository $exerciseRepository, ExerciseDispatcher $exerciseDispatcher, UserState $userState, - UserStateSerializer $userStateSerializer, OutputInterface $output ) { $this->output = $output; $this->exerciseRepository = $exerciseRepository; $this->userState = $userState; - $this->userStateSerializer = $userStateSerializer; $this->exerciseDispatcher = $exerciseDispatcher; } @@ -77,14 +69,7 @@ public function __invoke(Input $input) return 1; } $program = realpath($program); - - if (!$this->userState->isAssignedExercise()) { - $this->output->printError("No active exercises. Select one from the menu"); - return 1; - } - $exercise = $this->exerciseRepository->findByName($this->userState->getCurrentExercise()); - $this->exerciseDispatcher->run($exercise, $program, $this->output); } } diff --git a/src/Command/VerifyCommand.php b/src/Command/VerifyCommand.php index ba6ec324..dc511bf7 100644 --- a/src/Command/VerifyCommand.php +++ b/src/Command/VerifyCommand.php @@ -88,11 +88,6 @@ public function __invoke(Input $input) } $program = realpath($program); - if (!$this->userState->isAssignedExercise()) { - $this->output->printError("No active exercises. Select one from the menu"); - return 1; - } - $exercise = $this->exerciseRepository->findByName($this->userState->getCurrentExercise()); $results = $this->exerciseDispatcher->verify($exercise, $input); diff --git a/src/Listener/CheckExerciseAssignedListener.php b/src/Listener/CheckExerciseAssignedListener.php new file mode 100644 index 00000000..b7d4a8a4 --- /dev/null +++ b/src/Listener/CheckExerciseAssignedListener.php @@ -0,0 +1,43 @@ + + */ +class CheckExerciseAssignedListener +{ + /** + * @var UserState + */ + private $userState; + + /** + * @param UserState $userState + */ + public function __construct(UserState $userState) + { + $this->userState = $userState; + } + + /** + * @param Event $event + */ + public function __invoke(Event $event) + { + /** @var CommandDefinition $command */ + $command = $event->getParameter('command'); + + if (!in_array($command->getName(), ['verify', 'run', 'print'])) { + return; + } + + if (!$this->userState->isAssignedExercise()) { + throw new \RuntimeException('No active exercise. Select one from the menu'); + } + } +} diff --git a/test/Command/PrintCommandTest.php b/test/Command/PrintCommandTest.php index ec1c6f0d..26a988e5 100644 --- a/test/Command/PrintCommandTest.php +++ b/test/Command/PrintCommandTest.php @@ -17,22 +17,6 @@ */ class PrintCommandTest extends PHPUnit_Framework_TestCase { - public function testErrorIsPrintedIfNoExerciseAssigned() - { - $repo = new ExerciseRepository([]); - $state = new UserState; - $output = $this->createMock(OutputInterface::class); - $renderer = $this->createMock(MarkdownRenderer::class); - - $output - ->expects($this->once()) - ->method('printError') - ->with('No active exercises. Select one from the menu'); - - $command = new PrintCommand('phpschool', $repo, $state, $renderer, $output); - $this->assertSame(1, $command->__invoke()); - } - public function testExerciseIsPrintedIfAssigned() { $file = tempnam(sys_get_temp_dir(), 'pws'); diff --git a/test/Command/VerifyCommandTest.php b/test/Command/VerifyCommandTest.php index 84692749..381d7d6d 100644 --- a/test/Command/VerifyCommandTest.php +++ b/test/Command/VerifyCommandTest.php @@ -62,30 +62,6 @@ public function testVerifyPrintsErrorIfProgramDoesNotExist() $this->assertSame(1, $command->__invoke(new Input('appName', ['program' => $programFile]))); } - public function testVerifyPrintsErrorIfNoExerciseAssigned() - { - $file = tempnam(sys_get_temp_dir(), 'pws'); - touch($file); - - $repo = new ExerciseRepository([]); - $state = new UserState; - $output = $this->createMock(OutputInterface::class); - $dispatcher = $this->createMock(ExerciseDispatcher::class); - - $output - ->expects($this->once()) - ->method('printError') - ->with('No active exercises. Select one from the menu'); - - $serializer = $this->createMock(UserStateSerializer::class); - $renderer = $this->createMock(ResultsRenderer::class); - - $command = new VerifyCommand($repo, $dispatcher, $state, $serializer, $output, $renderer); - $this->assertSame(1, $command->__invoke(new Input('appName', ['program' => $file]))); - - unlink($file); - } - public function testVerifyAddsCompletedExerciseAndReturnsCorrectCodeOnSuccess() { $file = tempnam(sys_get_temp_dir(), 'pws'); diff --git a/test/Listener/CheckExerciseAssignedListenerTest.php b/test/Listener/CheckExerciseAssignedListenerTest.php new file mode 100644 index 00000000..2aa65ed9 --- /dev/null +++ b/test/Listener/CheckExerciseAssignedListenerTest.php @@ -0,0 +1,91 @@ + + */ +class CheckExerciseAssignedListenerTest extends PHPUnit_Framework_TestCase +{ + /** + * @dataProvider commandsThatRequireAssignedExercise + * @param CommandDefinition $command + */ + public function testExceptionIsThrownIfNoExerciseAssigned(CommandDefinition $command) + { + $state = new UserState; + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('No active exercise. Select one from the menu'); + + $listener = new CheckExerciseAssignedListener($state); + $listener->__invoke(new Event('some-event', ['command' => $command])); + } + + /** + * @dataProvider commandsThatRequireAssignedExercise + * @param CommandDefinition $command + */ + public function testExceptionIsNotThrownIfExerciseAssigned(CommandDefinition $command) + { + $state = new UserState(['exercise1'], 'exercise1'); + $listener = new CheckExerciseAssignedListener($state); + $listener->__invoke(new Event('some-event', ['command' => $command])); + } + + /** + * @return array + */ + public function commandsThatRequireAssignedExercise() + { + return [ + [$this->command('verify')], + [$this->command('run')], + [$this->command('print')], + ]; + } + + /** + * @dataProvider commandsThatDoNotRequireAssignedExercise + * @param CommandDefinition $command + */ + public function testExceptionIsNotThrownIfCommandDoesNotRequireAssignedExercise(CommandDefinition $command) + { + $state = new UserState(['exercise1'], 'exercise1'); + $listener = new CheckExerciseAssignedListener($state); + $listener->__invoke(new Event('some-event', ['command' => $command])); + } + + /** + * @return array + */ + public function commandsThatDoNotRequireAssignedExercise() + { + return [ + [$this->command('help')], + [$this->command('credits')], + [$this->command('menu')], + ]; + } + + /** + * @param $commandName + * @return \PHPUnit_Framework_MockObject_MockObject|CommandDefinition + */ + private function command($commandName) + { + $command = $this->createMock(CommandDefinition::class); + $command + ->expects($this->any()) + ->method('getName') + ->willReturn($commandName); + + return $command; + } +}