/** * @param Event $event */ public function __invoke(Event $event) { $exercise = $event->getParameter('exercise'); if ($exercise instanceof SelfCheck) { $this->results->add($exercise->check($event->getParameter('fileName'))); } }
public function testIterator() { $results = [new Success($this->check), new Failure($this->check, 'nope')]; $resultAggregator = new ResultAggregator(); $resultAggregator->add($results[0]); $resultAggregator->add($results[1]); $this->assertEquals($results, iterator_to_array($resultAggregator)); }
/** * @param ExerciseInterface $exercise * @param string $fileName * @return ResultAggregator * @throws CheckNotApplicableException * @throws ExerciseNotConfiguredException */ public function verify(ExerciseInterface $exercise, $fileName) { $exercise->configure($this); $runner = $this->runnerFactory->create($exercise, $this->eventDispatcher); $this->eventDispatcher->dispatch(new Event('verify.start', compact('exercise', 'fileName'))); $this->validateChecks($this->checksToRunBefore, $exercise); $this->validateChecks($this->checksToRunAfter, $exercise); foreach ($this->checksToRunBefore as $check) { $this->results->add($check->check($exercise, $fileName)); if (!$this->results->isSuccessful()) { return $this->results; } } $this->eventDispatcher->dispatch(new Event('verify.pre.execute', compact('exercise', 'fileName'))); try { $this->results->add($runner->verify($fileName)); } finally { $this->eventDispatcher->dispatch(new Event('verify.post.execute', compact('exercise', 'fileName'))); } foreach ($this->checksToRunAfter as $check) { $this->results->add($check->check($exercise, $fileName)); } $this->eventDispatcher->dispatch(new Event('verify.post.check', compact('exercise', 'fileName'))); $exercise->tearDown(); $this->eventDispatcher->dispatch(new Event('verify.finish', compact('exercise', 'fileName'))); return $this->results; }
/** * Verify a students solution against a specific exercise. Runs queued checks based on their position. Invokes the * correct runner for the exercise based on the exercise type. Various events are triggered throughout the process. * * @param ExerciseInterface $exercise The exercise instance. * @param Input $input The command line arguments passed to the command. * @return ResultAggregator Contains all the results injected via the runner, checks and events. * @throws CheckNotApplicableException If the check is not applicable to the exercise type. * @throws ExerciseNotConfiguredException If the exercise does not implement the correct interface based on * the checks required. */ public function verify(ExerciseInterface $exercise, Input $input) { $exercise->configure($this); $runner = $this->runnerManager->getRunner($exercise); foreach ($runner->getRequiredChecks() as $requiredCheck) { $this->requireCheck($requiredCheck); } $this->eventDispatcher->dispatch(new ExerciseRunnerEvent('verify.start', $exercise, $input)); $this->validateChecks($this->checksToRunBefore, $exercise); $this->validateChecks($this->checksToRunAfter, $exercise); foreach ($this->checksToRunBefore as $check) { $this->results->add($check->check($exercise, $input)); if (!$this->results->isSuccessful()) { return $this->results; } } $this->eventDispatcher->dispatch(new ExerciseRunnerEvent('verify.pre.execute', $exercise, $input)); try { $this->results->add($runner->verify($input)); } finally { $this->eventDispatcher->dispatch(new ExerciseRunnerEvent('verify.post.execute', $exercise, $input)); } foreach ($this->checksToRunAfter as $check) { $this->results->add($check->check($exercise, $input)); } $this->eventDispatcher->dispatch(new ExerciseRunnerEvent('verify.post.check', $exercise, $input)); $exercise->tearDown(); $this->eventDispatcher->dispatch(new ExerciseRunnerEvent('verify.finish', $exercise, $input)); return $this->results; }
public function testVerifyDoesNotAddCompletedExerciseAndReturnsCorrectCodeOnFailure() { $file = tempnam(sys_get_temp_dir(), 'pws'); touch($file); $input = new Input('appName', ['program' => $file]); $exercise = new CliExerciseImpl(); $repo = new ExerciseRepository([$exercise]); $state = new UserState(); $state->setCurrentExercise('my-exercise'); $color = new Color(); $color->setForceStyle(true); $output = new StdOutput($color, $this->createMock(TerminalInterface::class)); $serializer = $this->createMock(UserStateSerializer::class); $serializer->expects($this->never())->method('serialize')->with($state); $renderer = $this->createMock(ResultsRenderer::class); $results = new ResultAggregator(); $results->add(new Failure($this->check, 'cba')); $dispatcher = $this->createMock(ExerciseDispatcher::class); $dispatcher->expects($this->once())->method('verify')->with($exercise, $input)->will($this->returnValue($results)); $renderer->expects($this->once())->method('render')->with($results, $exercise, $state, $output); $command = new VerifyCommand($repo, $dispatcher, $state, $serializer, $output, $renderer); $this->assertEquals(1, $command->__invoke($input)); $this->assertEquals([], $state->getCompletedExercises()); unlink($file); }
/** * @param EventInterface $event * @return EventInterface */ public function dispatch(EventInterface $event) { if (array_key_exists($event->getName(), $this->listeners)) { foreach ($this->listeners[$event->getName()] as $listener) { $listener($event); } } if (array_key_exists($event->getName(), $this->verifiers)) { foreach ($this->verifiers[$event->getName()] as $verifier) { $result = $verifier($event); //return type hints pls if ($result instanceof ResultInterface) { $this->resultAggregator->add($result); } else { //??!! } } } return $event; }
/** * Insert a verifier callback which will execute at the given event name much like normal listeners. * A verifier should return an object which implements `PhpSchool\PhpWorkshop\Result\FailureInterface` * or `PhpSchool\PhpWorkshop\Result\SuccessInterface`. This result object will be added to the result aggregator. * * @param string|array $eventName * @param callable $verifier */ public function insertVerifier($eventName, callable $verifier) { $this->attachListener($eventName, function (EventInterface $event) use($verifier) { $result = $verifier($event); //return type hints pls if ($result instanceof ResultInterface) { $this->resultAggregator->add($result); } else { //??!! } }); }
public function testRenderAllFailures() { $color = new Color(); $color->setForceStyle(true); $resultRendererFactory = new ResultRendererFactory(); $resultRendererFactory->registerRenderer(Failure::class, FailureRenderer::class, function (Failure $failure) { $renderer = $this->prophesize(FailureRenderer::class); $renderer->render(Argument::type(ResultsRenderer::class))->willReturn($failure->getReason() . "\n"); return $renderer->reveal(); }); $terminal = $this->prophesize(TerminalInterface::class); $terminal->getWidth()->willReturn(100); $terminal = $terminal->reveal(); $exerciseRepo = $this->prophesize(ExerciseRepository::class); $exerciseRepo->count()->willReturn(2); $renderer = new ResultsRenderer('app', $color, $terminal, $exerciseRepo->reveal(), (new Factory())->__invoke(), $resultRendererFactory); $resultSet = new ResultAggregator(); $resultSet->add(new Failure('Failure 1', 'Failure 1')); $resultSet->add(new Failure('Failure 2', 'Failure 2')); $this->expectOutputString($this->getExpectedOutput()); $renderer->render($resultSet, $this->createMock(ExerciseInterface::class), new UserState(), new StdOutput($color, $terminal)); }