/**
  * @param Event $event
  */
 public function __invoke(Event $event)
 {
     $exercise = $event->getParameter('exercise');
     if ($exercise instanceof SelfCheck) {
         $this->results->add($exercise->check($event->getParameter('fileName')));
     }
 }
Exemplo n.º 2
0
 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);
 }
 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));
 }
 public function testExerciseWithOutSelfCheck()
 {
     $exercise = $this->createMock(ExerciseInterface::class);
     $event = new Event('event', ['exercise' => $exercise, 'fileName' => 'some-file.php']);
     $results = new ResultAggregator();
     $listener = new SelfCheckListener($results);
     $listener->__invoke($event);
     $this->assertTrue($results->isSuccessful());
     $this->assertCount(0, $results);
 }
Exemplo n.º 5
0
 /**
  * @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;
 }
Exemplo n.º 7
0
 /**
  * Render the result set to the output and statistics on the number of exercises completed and
  * remaining.
  *
  * @param ResultAggregator $results The result set.
  * @param ExerciseInterface $exercise The exercise instance that was just attempted.
  * @param UserState $userState The current state of the student's progress.
  * @param OutputInterface $output The output instance.
  */
 public function render(ResultAggregator $results, ExerciseInterface $exercise, UserState $userState, OutputInterface $output)
 {
     $successes = [];
     $failures = [];
     foreach ($results as $result) {
         if ($result instanceof SuccessInterface || $result instanceof ResultGroupInterface && $result->isSuccessful()) {
             $successes[] = sprintf(' ✔ Check: %s', $result->getCheckName());
         } else {
             $failures[] = [$result, sprintf(' ✗ Check: %s', $result->getCheckName())];
         }
     }
     $output->emptyLine();
     $output->writeLine($this->center($this->style('*** RESULTS ***', ['magenta', 'bold'])));
     $output->emptyLine();
     $messages = array_merge($successes, array_column($failures, 1));
     $longest = max(array_map('mb_strlen', $messages)) + 4;
     foreach ($successes as $success) {
         $output->writeLine($this->center($this->style(str_repeat(' ', $longest), ['bg_green'])));
         $output->writeLine($this->center($this->style(mb_str_pad($success, $longest), ['bg_green', 'white', 'bold'])));
         $output->writeLine($this->center($this->style(str_repeat(' ', $longest), ['bg_green'])));
         $output->emptyLine();
     }
     if ($results->isSuccessful()) {
         return $this->renderSuccessInformation($exercise, $userState, $output);
     }
     $this->renderErrorInformation($failures, $longest, $exercise, $output);
 }
Exemplo n.º 8
0
 /**
  * @param ResultAggregator $results
  * @param ExerciseInterface $exercise
  * @param UserState $userState
  * @param OutputInterface $output
  */
 public function render(ResultAggregator $results, ExerciseInterface $exercise, UserState $userState, OutputInterface $output)
 {
     $successes = [];
     $failures = [];
     foreach ($results as $result) {
         if ($result instanceof SuccessInterface || $result instanceof ResultAggregator && $result->isSuccessful()) {
             $successes[] = sprintf(' ✔ Check: %s', $result->getCheckName());
         } else {
             $failures[] = [$result, sprintf(' ✗ Check: %s', $result->getCheckName())];
         }
     }
     $longest = max(array_map('strlen', array_merge($successes, array_column($failures, 1)))) + 2;
     $output->writeLines($this->padArray($this->styleArray($successes, ['green', 'bg_black', 'bold']), $longest));
     if ($results->isSuccessful()) {
         return $this->renderSuccessInformation($exercise, $userState, $output);
     }
     $this->renderErrorInformation($failures, $longest, $exercise, $output);
 }
Exemplo n.º 9
0
 /**
  * @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;
 }
Exemplo n.º 10
0
 /**
  * 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 {
             //??!!
         }
     });
 }
Exemplo n.º 11
0
 public function testFailureIsReturnedIfDatabaseVerificationFails()
 {
     $solution = SingleFileSolution::fromFile(realpath(__DIR__ . '/../res/database/solution.php'));
     $this->exercise->expects($this->once())->method('getSolution')->will($this->returnValue($solution));
     $this->exercise->expects($this->once())->method('getArgs')->will($this->returnValue([1, 2, 3]));
     $this->exercise->expects($this->atLeastOnce())->method('getType')->will($this->returnValue(ExerciseType::CLI()));
     $this->exercise->expects($this->once())->method('configure')->will($this->returnCallback(function (ExerciseDispatcher $dispatcher) {
         $dispatcher->requireCheck(DatabaseCheck::class);
     }));
     $this->exercise->expects($this->once())->method('verify')->with($this->isInstanceOf(PDO::class))->will($this->returnValue(false));
     $results = new ResultAggregator();
     $eventDispatcher = new EventDispatcher($results);
     $checkRepository = new CheckRepository([$this->check]);
     $dispatcher = new ExerciseDispatcher(new RunnerFactory(), $results, $eventDispatcher, $checkRepository);
     $dispatcher->verify($this->exercise, __DIR__ . '/../res/database/user.php');
     $this->assertFalse($results->isSuccessful());
     $results = iterator_to_array($results);
     $this->assertSame('Database verification failed', $results[1]->getReason());
 }
Exemplo n.º 12
0
 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));
 }