public function testIsSuccessfulWithResultGroups()
 {
     $resultAggregator = new ResultAggregator();
     $this->assertTrue($resultAggregator->isSuccessful());
     $resultGroup = new CliResult();
     $resultGroup->add(new CliSuccess(new ArrayObject()));
     $resultAggregator->add($resultGroup);
     $this->assertTrue($resultAggregator->isSuccessful());
     $resultGroup->add(new CliGenericFailure(new ArrayObject(), 'nop'));
     $this->assertFalse($resultAggregator->isSuccessful());
 }
 public function testIsSuccessfulWithNestedResults()
 {
     $resultAggregator = new ResultAggregator();
     $this->assertTrue($resultAggregator->isSuccessful());
     $resultResultAggregator = new ResultResultAggregator();
     $resultResultAggregator->add(new Success($this->check));
     $resultAggregator->add($resultResultAggregator);
     $this->assertTrue($resultAggregator->isSuccessful());
     $resultResultAggregator->add(new Failure($this->check, 'nope'));
     $this->assertFalse($resultAggregator->isSuccessful());
 }
예제 #3
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;
 }
 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);
 }
예제 #6
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);
 }
예제 #7
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());
 }
예제 #8
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);
 }