/** * @param ExerciseDispatcher $exerciseDispatcher */ public function configure(ExerciseDispatcher $exerciseDispatcher) { $eventDispatcher = $exerciseDispatcher->getEventDispatcher(); $appendArgsListener = function (CliExecuteEvent $event) { $event->appendArg('127.0.0.1'); $event->appendArg($this->getRandomPort()); }; $eventDispatcher->listen('cli.verify.reference-execute.pre', $appendArgsListener); $eventDispatcher->listen('cli.verify.student-execute.pre', $appendArgsListener); $eventDispatcher->listen('cli.run.student-execute.pre', $appendArgsListener); $eventDispatcher->listen('cli.verify.reference.executing', function (CliExecuteEvent $event) { $args = $event->getArgs()->getArrayCopy(); $client = $this->socketFactory->createClient(...$args); //wait for server to boot usleep(100000); $client->connect(); $client->readAll(); //wait for shutdown usleep(100000); }); $eventDispatcher->insertVerifier('cli.verify.student.executing', function (CliExecuteEvent $event) { $args = $event->getArgs()->getArrayCopy(); $client = $this->socketFactory->createClient(...$args); //wait for server to boot usleep(100000); try { $client->connect(); } catch (Exception $e) { return Failure::fromNameAndReason($this->getName(), $e->getMessage()); } $out = $client->readAll(); //wait for shutdown usleep(100000); $date = new \DateTime(); //match the current date but any seconds //since we can't mock time in PHP easily if (!preg_match(sprintf('/^%s:([0-5][0-9]|60)\\n$/', $date->format('Y-m-d H:i')), $out)) { return new StdOutFailure($this->getName(), $date->format("Y-m-d H:i:s\n"), $out); } return new Success($this->getName()); }); $eventDispatcher->listen('cli.run.student.executing', function (CliExecuteEvent $event) { /** @var OutputInterface $output */ $output = $event->getParameter('output'); $args = $event->getArgs()->getArrayCopy(); $client = $this->socketFactory->createClient(...$args); //wait for server to boot usleep(100000); $client->connect(); $out = $client->readAll(); //wait for shutdown usleep(100000); $output->write($out); }); }
/** * @param Input $input The command line arguments passed to the command. * * @return int|void */ public function __invoke(Input $input) { $exercise = $this->exerciseRepository->findByName($this->userState->getCurrentExercise()); $results = $this->exerciseDispatcher->verify($exercise, $input); if ($results->isSuccessful()) { $this->userState->addCompletedExercise($exercise->getName()); $this->userStateSerializer->serialize($this->userState); } $this->resultsRenderer->render($results, $exercise, $this->userState, $this->output); return $results->isSuccessful() ? 0 : 1; }
/** * @param string $appName * @param string $program * * @return int|void */ public function __invoke($appName, $program) { if (!file_exists($program)) { $this->output->printError(sprintf('Could not run. File: "%s" does not exist', $program)); 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); }
public function testRun() { $exercise = $this->getMock(ExerciseInterface::class); $output = $this->getMock(OutputInterface::class); $this->mockRunner($exercise); $this->runner->expects($this->once())->method('run')->with($this->file, $output)->will($this->returnValue(true)); $this->assertTrue($this->exerciseDispatcher->run($exercise, $this->file, $output)); }
/** * @param string $appName * @param string $program * * @return int|void */ public function __invoke($appName, $program) { if (!file_exists($program)) { $this->output->printError(sprintf('Could not verify. File: "%s" does not exist', $program)); 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()); $results = $this->exerciseDispatcher->verify($exercise, $program); if ($results->isSuccessful()) { $this->userState->addCompletedExercise($exercise->getName()); $this->userStateSerializer->serialize($this->userState); } $this->resultsRenderer->render($results, $exercise, $this->userState, $this->output); return $results->isSuccessful() ? 0 : 1; }
public function testRun() { $color = new Color(); $color->setForceStyle(true); $output = new StdOutput($color, $terminal = $this->getMock(TerminalInterface::class)); $outputRegEx = "/\n"; $outputRegEx .= '\\[1m\\[4mArguments\\[0m\\[0m'; $outputRegEx .= "\n"; $outputRegEx .= '127.0.0.1, \\d+'; $outputRegEx .= "\n\n"; $outputRegEx .= '\\[1m\\[4mOutput\\[0m\\[0m'; $outputRegEx .= "\n"; $outputRegEx .= '\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}'; $outputRegEx .= "\n/"; $this->expectOutputRegex($outputRegEx); $this->exerciseDispatcher->run($this->exercise, __DIR__ . '/../res/time-server/solution.php', $output); }
public function testAlteringDatabaseInSolutionDoesNotEffectDatabaseInUserSolution() { $solution = SingleFileSolution::fromFile(realpath(__DIR__ . '/../res/database/solution-alter-db.php')); $this->exercise->expects($this->once())->method('getSolution')->will($this->returnValue($solution)); $this->exercise->expects($this->any())->method('getArgs')->will($this->returnValue([])); $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('seed')->with($this->isInstanceOf(PDO::class))->will($this->returnCallback(function (PDO $db) { $db->exec('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER, gender TEXT)'); $stmt = $db->prepare('INSERT into users (name, age, gender) VALUES (:name, :age, :gender)'); $stmt->execute([':name' => 'Jimi Hendrix', ':age' => 27, ':gender' => 'Male']); })); $this->exercise->expects($this->once())->method('verify')->with($this->isInstanceOf(PDO::class))->will($this->returnCallback(function (PDO $db) { $users = $db->query('SELECT * FROM users'); $users = $users->fetchAll(PDO::FETCH_ASSOC); $this->assertEquals([['id' => 1, 'name' => 'Jimi Hendrix', 'age' => '27', 'gender' => 'Male'], ['id' => 2, 'name' => 'Kurt Cobain', 'age' => '27', 'gender' => 'Male']], $users); })); $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-solution-alter-db.php'); }
public function testRun() { $input = new Input('app', ['program' => $this->file]); $output = $this->prophesize(OutputInterface::class)->reveal(); $exercise = new CliExerciseImpl('Some Exercise'); $runner = $this->prophesize(ExerciseRunnerInterface::class); $runner->getRequiredChecks()->willReturn([]); $runner->run($input, $output)->willReturn(true); $runnerManager = $this->prophesize(RunnerManager::class); $runnerManager->getRunner($exercise)->willReturn($runner->reveal()); $exerciseDispatcher = new ExerciseDispatcher($runnerManager->reveal(), new ResultAggregator(), $this->prophesize(EventDispatcher::class)->reveal(), new CheckRepository()); $this->assertTrue($exerciseDispatcher->run($exercise, $input, $output)); }
/** * @param ExerciseDispatcher $dispatcher */ public function configure(ExerciseDispatcher $dispatcher) { $dispatcher->requireCheck(FunctionRequirementsCheck::class); }
/** * @param ExerciseDispatcher $dispatcher */ public function configure(ExerciseDispatcher $dispatcher) { $dispatcher->requireCheck(ComposerCheck::class); }
/** * @param ExerciseDispatcher $dispatcher */ public function configure(ExerciseDispatcher $dispatcher) { $dispatcher->requireCheck(DatabaseCheck::class); }
/** * @param Input $input The command line arguments passed to the command. * * @return int|void */ public function __invoke(Input $input) { $exercise = $this->exerciseRepository->findByName($this->userState->getCurrentExercise()); $this->exerciseDispatcher->run($exercise, $input, $this->output); }
use PhpSchool\PhpWorkshop\ExerciseRepository; use PhpSchool\PhpWorkshop\ExerciseRunner; use PhpSchool\PhpWorkshop\Factory\MarkdownCliRendererFactory; use PhpSchool\PhpWorkshop\MarkdownRenderer; use PhpSchool\PhpWorkshop\Result\FunctionRequirementsFailure; use PhpSchool\PhpWorkshop\Result\Success; use PhpSchool\PhpWorkshop\Result\Failure; use PhpSchool\PhpWorkshop\ResultRenderer\FailureRenderer; use PhpSchool\PhpWorkshop\ResultRenderer\FunctionRequirementsFailureRenderer; use PhpSchool\PhpWorkshop\ResultRenderer\ResultsRenderer; use PhpSchool\PhpWorkshop\ResultRenderer\SuccessRenderer; use PhpSchool\PhpWorkshop\UserState; use PhpSchool\PhpWorkshop\UserStateSerializer; use Symfony\Component\Filesystem\Filesystem; return ['appName' => basename($_SERVER['argv'][0]), ExerciseDispatcher::class => factory(function (ContainerInterface $c) { $dispatcher = new ExerciseDispatcher($c->get(RunnerFactory::class), $c->get(ResultAggregator::class), $c->get(EventDispatcher::class), $c->get(CheckRepository::class)); //checks which should always run (probably) $dispatcher->requireCheck(FileExistsCheck::class, ExerciseDispatcher::CHECK_BEFORE); $dispatcher->requireCheck(PhpLintCheck::class, ExerciseDispatcher::CHECK_BEFORE); $dispatcher->requireCheck(CodeParseCheck::class, ExerciseDispatcher::CHECK_BEFORE); return $dispatcher; }), ResultAggregator::class => object(ResultAggregator::class), CheckRepository::class => factory(function (ContainerInterface $c) { return new CheckRepository([$c->get(FileExistsCheck::class), $c->get(PhpLintCheck::class), $c->get(CodeParseCheck::class), $c->get(ComposerCheck::class), $c->get(FunctionRequirementsCheck::class), $c->get(DatabaseCheck::class)]); }), CommandRouter::class => factory(function (ContainerInterface $c) { return new CommandRouter([new CommandDefinition('menu', [], MenuCommand::class), new CommandDefinition('help', [], HelpCommand::class), new CommandDefinition('print', [], PrintCommand::class), new CommandDefinition('verify', ['program'], VerifyCommand::class), new CommandDefinition('run', ['program'], RunCommand::class), new CommandDefinition('credits', [], CreditsCommand::class)], 'menu', $c); }), Color::class => factory(function (ContainerInterface $c) { $colors = new Color(); $colors->setForceStyle(true); return $colors; }), OutputInterface::class => factory(function (ContainerInterface $c) { return new StdOutput($c->get(Color::class), $c->get(TerminalInterface::class));
use PhpSchool\PhpWorkshop\Command\VerifyCommand; use PhpSchool\PhpWorkshop\Command\RunCommand; use PhpSchool\PhpWorkshop\CommandDefinition; use PhpSchool\PhpWorkshop\CommandRouter; use PhpSchool\PhpWorkshop\ExerciseRenderer; use PhpSchool\PhpWorkshop\ExerciseRepository; use PhpSchool\PhpWorkshop\Factory\MarkdownCliRendererFactory; use PhpSchool\PhpWorkshop\MarkdownRenderer; use PhpSchool\PhpWorkshop\ResultRenderer\ResultsRenderer; use PhpSchool\PhpWorkshop\UserState; use PhpSchool\PhpWorkshop\UserStateSerializer; use Symfony\Component\Filesystem\Filesystem; use Faker\Factory as FakerFactory; use Faker\Generator as FakerGenerator; return ['appName' => basename($_SERVER['argv'][0]), WorkshopType::class => WorkshopType::STANDARD(), ExerciseDispatcher::class => function (ContainerInterface $c) { $dispatcher = new ExerciseDispatcher($c->get(RunnerFactory::class), $c->get(ResultAggregator::class), $c->get(EventDispatcher::class), $c->get(CheckRepository::class)); //checks which should always run (probably) $dispatcher->requireCheck(FileExistsCheck::class); $dispatcher->requireCheck(PhpLintCheck::class); $dispatcher->requireCheck(CodeParseCheck::class); return $dispatcher; }, ResultAggregator::class => object(ResultAggregator::class), CheckRepository::class => function (ContainerInterface $c) { return new CheckRepository([$c->get(FileExistsCheck::class), $c->get(PhpLintCheck::class), $c->get(CodeParseCheck::class), $c->get(ComposerCheck::class), $c->get(FunctionRequirementsCheck::class), $c->get(DatabaseCheck::class)]); }, CommandRouter::class => function (ContainerInterface $c) { return new CommandRouter([new CommandDefinition('menu', [], MenuCommand::class), new CommandDefinition('help', [], HelpCommand::class), new CommandDefinition('print', [], PrintCommand::class), new CommandDefinition('verify', ['program'], VerifyCommand::class), new CommandDefinition('run', ['program'], RunCommand::class), new CommandDefinition('credits', [], CreditsCommand::class)], 'menu', $c); }, Color::class => function () { $colors = new Color(); $colors->setForceStyle(true); return $colors; }, OutputInterface::class => function (ContainerInterface $c) { return new StdOutput($c->get(Color::class), $c->get(TerminalInterface::class));
/** * @param ExerciseDispatcher $dispatcher */ public function configure(ExerciseDispatcher $dispatcher) { $dispatcher->requireCheck(ComposerCheck::class, $dispatcher::CHECK_BEFORE); }