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()); }
/** * @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); }
/** * @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); }
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()); }
/** * 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); }