diff --git a/app/config.php b/app/config.php index ace0a1a3..b7bede9d 100644 --- a/app/config.php +++ b/app/config.php @@ -20,12 +20,15 @@ use PhpSchool\PhpWorkshop\CodePatcher; use PhpSchool\PhpWorkshop\Event\EventDispatcher; use PhpSchool\PhpWorkshop\ExerciseDispatcher; +use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CgiRunnerFactory; +use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CliRunnerFactory; +use PhpSchool\PhpWorkshop\ExerciseRunner\RunnerManager; use PhpSchool\PhpWorkshop\Factory\EventDispatcherFactory; use PhpSchool\PhpWorkshop\Factory\MenuFactory; use PhpSchool\PhpWorkshop\Factory\ResultRendererFactory; -use PhpSchool\PhpWorkshop\Factory\RunnerFactory; use PhpSchool\PhpWorkshop\Listener\CheckExerciseAssignedListener; use PhpSchool\PhpWorkshop\Listener\CodePatchListener; +use PhpSchool\PhpWorkshop\Listener\ConfigureCommandListener; use PhpSchool\PhpWorkshop\Listener\PrepareSolutionListener; use PhpSchool\PhpWorkshop\Listener\SelfCheckListener; use PhpSchool\PhpWorkshop\MenuItem\ResetProgress; @@ -63,7 +66,7 @@ WorkshopType::class => WorkshopType::STANDARD(), ExerciseDispatcher::class => function (ContainerInterface $c) { return new ExerciseDispatcher( - $c->get(RunnerFactory::class), + $c->get(RunnerManager::class), $c->get(ResultAggregator::class), $c->get(EventDispatcher::class), $c->get(CheckRepository::class) @@ -86,8 +89,8 @@ 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('verify', [], VerifyCommand::class), + new CommandDefinition('run', [], RunCommand::class), new CommandDefinition('credits', [], CreditsCommand::class) ], 'menu', @@ -117,7 +120,12 @@ EventDispatcherFactory::class => object(), //Exercise Runners - RunnerFactory::class => object(), + RunnerManager::class => function (ContainerInterface $c) { + $manager = new RunnerManager; + $manager->addFactory(new CliRunnerFactory($c->get(EventDispatcher::class))); + $manager->addFactory(new CgiRunnerFactory($c->get(EventDispatcher::class))); + return $manager; + }, //commands MenuCommand::class => function (ContainerInterface $c) { @@ -172,16 +180,23 @@ }, //Listeners - PrepareSolutionListener::class => object(), - CodePatchListener::class => function (ContainerInterface $c) { + PrepareSolutionListener::class => object(), + CodePatchListener::class => function (ContainerInterface $c) { return new CodePatchListener($c->get(CodePatcher::class)); }, - SelfCheckListener::class => function (ContainerInterface $c) { + SelfCheckListener::class => function (ContainerInterface $c) { return new SelfCheckListener($c->get(ResultAggregator::class)); }, CheckExerciseAssignedListener::class => function (ContainerInterface $c) { return new CheckExerciseAssignedListener($c->get(UserState::class)); }, + ConfigureCommandListener::class => function (ContainerInterface $c) { + return new ConfigureCommandListener( + $c->get(UserState::class), + $c->get(ExerciseRepository::class), + $c->get(RunnerManager::class) + ); + }, //checks FileExistsCheck::class => object(), @@ -271,6 +286,11 @@ containerListener(CheckExerciseAssignedListener::class) ], ], + 'configure-command-arguments' => [ + 'route.pre.resolve.args' => [ + containerListener(ConfigureCommandListener::class) + ], + ], 'prepare-solution' => [ 'verify.start' => [ containerListener(PrepareSolutionListener::class), diff --git a/composer.json b/composer.json index 69ef113c..ccd52484 100644 --- a/composer.json +++ b/composer.json @@ -33,8 +33,9 @@ "nikic/php-parser": "^2.1" }, "require-dev": { - "composer/composer": "^1.0-alpha", - "phpunit/phpunit": "^5.4", + "composer/composer": "^1.2", + "phpunit/phpunit": "^5.6", + "phpunit/phpunit-mock-objects": "^3.3", "squizlabs/php_codesniffer": "^2.4" }, "autoload" : { diff --git a/composer.lock b/composer.lock index 7882cc32..f71d5548 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "87289bfee8ab370b8af121daeef32638", + "content-hash": "846264cf45eb6d3d35b0cd9c524ae776", "packages": [ { "name": "aydin-hassan/cli-md-renderer", @@ -51,16 +51,16 @@ }, { "name": "beberlei/assert", - "version": "2.6.5", + "version": "v2.4", "source": { "type": "git", "url": "https://github.com/beberlei/assert.git", - "reference": "fbadde44717ea3eb98fba35425d49731185bf418" + "reference": "7281b1fd8118b31cb9162c2fb5a4cc6f01d62ed6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beberlei/assert/zipball/fbadde44717ea3eb98fba35425d49731185bf418", - "reference": "fbadde44717ea3eb98fba35425d49731185bf418", + "url": "https://api.github.com/repos/beberlei/assert/zipball/7281b1fd8118b31cb9162c2fb5a4cc6f01d62ed6", + "reference": "7281b1fd8118b31cb9162c2fb5a4cc6f01d62ed6", "shasum": "" }, "require": { @@ -68,10 +68,14 @@ "php": ">=5.3" }, "require-dev": { - "friendsofphp/php-cs-fixer": "2.0.0-alpha", "phpunit/phpunit": "@stable" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, "autoload": { "psr-0": { "Assert": "lib/" @@ -87,13 +91,7 @@ "authors": [ { "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de", - "role": "Lead Developer" - }, - { - "name": "Richard Quadling", - "email": "rquadling@gmail.com", - "role": "Collaborator" + "email": "kontakt@beberlei.de" } ], "description": "Thin assertion library for input validation in business models.", @@ -102,7 +100,7 @@ "assertion", "validation" ], - "time": "2016-10-11T17:13:28+00:00" + "time": "2015-08-21T16:50:17+00:00" }, { "name": "container-interop/container-interop", @@ -133,29 +131,33 @@ }, { "name": "fzaninotto/faker", - "version": "v1.6.0", + "version": "v1.5.0", "source": { "type": "git", "url": "https://github.com/fzaninotto/Faker.git", - "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123" + "reference": "d0190b156bcca848d401fb80f31f504f37141c8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/44f9a286a04b80c76a4e5fb7aad8bb539b920123", - "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/d0190b156bcca848d401fb80f31f504f37141c8d", + "reference": "d0190b156bcca848d401fb80f31f504f37141c8d", "shasum": "" }, "require": { - "php": "^5.3.3|^7.0" + "php": ">=5.3.3" }, "require-dev": { - "ext-intl": "*", "phpunit/phpunit": "~4.0", "squizlabs/php_codesniffer": "~1.5" }, + "suggest": { + "ext-intl": "*" + }, "type": "library", "extra": { - "branch-alias": [] + "branch-alias": { + "dev-master": "1.5.x-dev" + } }, "autoload": { "psr-4": { @@ -177,7 +179,7 @@ "faker", "fixtures" ], - "time": "2016-04-29T12:21:54+00:00" + "time": "2015-05-29T06:29:14+00:00" }, { "name": "kevinlebrun/colors.php", @@ -232,16 +234,16 @@ }, { "name": "league/commonmark", - "version": "0.13.4", + "version": "0.13.0", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "83f8210427fb01f671e272bb8d44b4ed3a94d459" + "reference": "a4e93bc4fd1a8ff8f534040c4a07371ea5f4b484" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/83f8210427fb01f671e272bb8d44b4ed3a94d459", - "reference": "83f8210427fb01f671e272bb8d44b4ed3a94d459", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/a4e93bc4fd1a8ff8f534040c4a07371ea5f4b484", + "reference": "a4e93bc4fd1a8ff8f534040c4a07371ea5f4b484", "shasum": "" }, "require": { @@ -252,14 +254,13 @@ "colinodell/commonmark-php": "*" }, "require-dev": { - "cebe/markdown": "~1.0", "erusev/parsedown": "~1.0", - "jgm/commonmark": "0.25", + "jgm/commonmark": "0.24", "michelf/php-markdown": "~1.4", - "mikehaertl/php-shellcommand": "~1.2.0", + "mikehaertl/php-shellcommand": "~1.1.0", "phpunit/phpunit": "~4.3|~5.0", - "scrutinizer/ocular": "~1.1", - "symfony/finder": "~2.3|~3.0" + "scrutinizer/ocular": "^1.1", + "symfony/finder": "~2.3" }, "suggest": { "league/commonmark-extras": "Library of useful extensions including smart punctuation" @@ -286,7 +287,7 @@ { "name": "Colin O'Dell", "email": "colinodell@gmail.com", - "homepage": "https://www.colinodell.com", + "homepage": "http://www.colinodell.com", "role": "Lead Developer" } ], @@ -297,20 +298,20 @@ "markdown", "parser" ], - "time": "2016-06-14T14:49:29+00:00" + "time": "2016-01-14T04:29:54+00:00" }, { "name": "myclabs/php-enum", - "version": "1.5.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/myclabs/php-enum.git", - "reference": "e42fa9d2ae5dd660dbd0fb573d94c61e5a0dbb02" + "reference": "7c4cd65efc984e80c70522b0aa50545ea51dfff4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/php-enum/zipball/e42fa9d2ae5dd660dbd0fb573d94c61e5a0dbb02", - "reference": "e42fa9d2ae5dd660dbd0fb573d94c61e5a0dbb02", + "url": "https://api.github.com/repos/myclabs/php-enum/zipball/7c4cd65efc984e80c70522b0aa50545ea51dfff4", + "reference": "7c4cd65efc984e80c70522b0aa50545ea51dfff4", "shasum": "" }, "require": { @@ -341,20 +342,20 @@ "keywords": [ "enum" ], - "time": "2016-10-09T21:43:05+00:00" + "time": "2015-05-19T05:28:18+00:00" }, { "name": "nikic/php-parser", - "version": "v2.1.1", + "version": "v2.1.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "4dd659edadffdc2143e4753df655d866dbfeedf0" + "reference": "47b254ea51f1d6d5dc04b9b299e88346bf2369e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4dd659edadffdc2143e4753df655d866dbfeedf0", - "reference": "4dd659edadffdc2143e4753df655d866dbfeedf0", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/47b254ea51f1d6d5dc04b9b299e88346bf2369e3", + "reference": "47b254ea51f1d6d5dc04b9b299e88346bf2369e3", "shasum": "" }, "require": { @@ -392,20 +393,20 @@ "parser", "php" ], - "time": "2016-09-16T12:04:44+00:00" + "time": "2016-04-19T13:41:41+00:00" }, { "name": "php-di/invoker", - "version": "1.3.3", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/PHP-DI/Invoker.git", - "reference": "1f4ca63b9abc66109e53b255e465d0ddb5c2e3f7" + "reference": "7ea703c62dbb29d64763fa85258826034ce3c97d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/1f4ca63b9abc66109e53b255e465d0ddb5c2e3f7", - "reference": "1f4ca63b9abc66109e53b255e465d0ddb5c2e3f7", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/7ea703c62dbb29d64763fa85258826034ce3c97d", + "reference": "7ea703c62dbb29d64763fa85258826034ce3c97d", "shasum": "" }, "require": { @@ -435,45 +436,39 @@ "invoke", "invoker" ], - "time": "2016-07-14T13:09:58+00:00" + "time": "2015-04-24T10:18:34+00:00" }, { "name": "php-di/php-di", - "version": "5.4.0", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/PHP-DI/PHP-DI.git", - "reference": "e348393488fa909e4bc0707ba5c9c44cd602a1cb" + "reference": "c3bbc0d334b888ec8baa75f95b4900ee17b18fa7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/e348393488fa909e4bc0707ba5c9c44cd602a1cb", - "reference": "e348393488fa909e4bc0707ba5c9c44cd602a1cb", + "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/c3bbc0d334b888ec8baa75f95b4900ee17b18fa7", + "reference": "c3bbc0d334b888ec8baa75f95b4900ee17b18fa7", "shasum": "" }, "require": { "container-interop/container-interop": "~1.0", - "php": ">=5.5.0", - "php-di/invoker": "^1.3.2", - "php-di/phpdoc-reader": "^2.0.1" - }, - "provide": { - "container-interop/container-interop-implementation": "^1.0" - }, - "replace": { - "mnapoli/php-di": "*" + "php": ">=5.4.0", + "php-di/invoker": "~1.0", + "php-di/phpdoc-reader": "~2.0" }, "require-dev": { "doctrine/annotations": "~1.2", - "doctrine/cache": "~1.4", - "mnapoli/phpunit-easymock": "~0.2.0", - "ocramius/proxy-manager": "~1.0|~2.0", + "doctrine/cache": "~1.0", + "mnapoli/phpunit-easymock": "~0.1.4", + "ocramius/proxy-manager": "~1.0", "phpunit/phpunit": "~4.5" }, "suggest": { "doctrine/annotations": "Install it if you want to use annotations (version ~1.2)", - "doctrine/cache": "Install it if you want to use the cache (version ~1.4)", - "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~1.0 or ~2.0)" + "doctrine/cache": "Install it if you want to use the cache (version ~1.0)", + "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~1.0)" }, "type": "library", "autoload": { @@ -495,20 +490,20 @@ "dependency injection", "di" ], - "time": "2016-08-23T20:18:00+00:00" + "time": "2015-06-10T06:16:52+00:00" }, { "name": "php-di/phpdoc-reader", - "version": "2.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/PHP-DI/PhpDocReader.git", - "reference": "83f5ead159defccfa8e7092e5b6c1c533b326d68" + "reference": "21dce5e29f640d655e7b4583ecfb7d166127a5da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/83f5ead159defccfa8e7092e5b6c1c533b326d68", - "reference": "83f5ead159defccfa8e7092e5b6c1c533b326d68", + "url": "https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/21dce5e29f640d655e7b4583ecfb7d166127a5da", + "reference": "21dce5e29f640d655e7b4583ecfb7d166127a5da", "shasum": "" }, "require": { @@ -532,7 +527,7 @@ "phpdoc", "reflection" ], - "time": "2015-11-29T10:34:25+00:00" + "time": "2015-06-01T14:23:20+00:00" }, { "name": "php-school/cli-menu", @@ -590,16 +585,16 @@ }, { "name": "php-school/psx", - "version": "1.1.2", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/php-school/psx.git", - "reference": "4063d9ac62e057897a41be11ec979424ed93035c" + "reference": "762074f23541b20577bb01862988238a4256f4d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-school/psx/zipball/4063d9ac62e057897a41be11ec979424ed93035c", - "reference": "4063d9ac62e057897a41be11ec979424ed93035c", + "url": "https://api.github.com/repos/php-school/psx/zipball/762074f23541b20577bb01862988238a4256f4d8", + "reference": "762074f23541b20577bb01862988238a4256f4d8", "shasum": "" }, "require": { @@ -628,20 +623,20 @@ } ], "description": "PHP CLI Syntax Highlighter", - "time": "2016-03-30T22:07:50+00:00" + "time": "2015-12-04T17:38:50+00:00" }, { "name": "psr/http-message", - "version": "1.0.1", + "version": "1.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", "shasum": "" }, "require": { @@ -669,7 +664,6 @@ } ], "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", "keywords": [ "http", "http-message", @@ -678,38 +672,36 @@ "request", "response" ], - "time": "2016-08-06T14:39:51+00:00" + "time": "2015-05-04T20:22:00+00:00" }, { "name": "symfony/filesystem", - "version": "v3.1.6", + "version": "v2.5.0", + "target-dir": "Symfony/Component/Filesystem", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "0565b61bf098cb4dc09f4f103f033138ae4f42c6" + "reference": "98e831eac836a0a5911626ce82684155f21d0e4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/0565b61bf098cb4dc09f4f103f033138ae4f42c6", - "reference": "0565b61bf098cb4dc09f4f103f033138ae4f42c6", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/98e831eac836a0a5911626ce82684155f21d0e4d", + "reference": "98e831eac836a0a5911626ce82684155f21d0e4d", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.3.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "2.5-dev" } }, "autoload": { - "psr-4": { + "psr-0": { "Symfony\\Component\\Filesystem\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -717,48 +709,46 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" } ], "description": "Symfony Filesystem Component", - "homepage": "https://symfony.com", - "time": "2016-10-18T04:30:12+00:00" + "homepage": "http://symfony.com", + "time": "2014-04-16T10:36:21+00:00" }, { "name": "symfony/process", - "version": "v3.1.6", + "version": "v2.3.0", + "target-dir": "Symfony/Component/Process", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "66de154ae86b1a07001da9fbffd620206e4faf94" + "reference": "bb721b29e033594512f8b08386e13593b0faaf0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/66de154ae86b1a07001da9fbffd620206e4faf94", - "reference": "66de154ae86b1a07001da9fbffd620206e4faf94", + "url": "https://api.github.com/repos/symfony/process/zipball/bb721b29e033594512f8b08386e13593b0faaf0f", + "reference": "bb721b29e033594512f8b08386e13593b0faaf0f", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.3.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "2.3-dev" } }, "autoload": { - "psr-4": { + "psr-0": { "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -766,48 +756,48 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" } ], "description": "Symfony Process Component", - "homepage": "https://symfony.com", - "time": "2016-09-29T14:13:09+00:00" + "homepage": "http://symfony.com", + "time": "2013-05-06T20:03:44+00:00" }, { "name": "zendframework/zend-diactoros", - "version": "1.3.7", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/zendframework/zend-diactoros.git", - "reference": "969ff423d3f201da3ff718a5831bb999bb0669b0" + "reference": "e2f5c12916c74da384058d0dfbc7fbc0b03d1181" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/969ff423d3f201da3ff718a5831bb999bb0669b0", - "reference": "969ff423d3f201da3ff718a5831bb999bb0669b0", + "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/e2f5c12916c74da384058d0dfbc7fbc0b03d1181", + "reference": "e2f5c12916c74da384058d0dfbc7fbc0b03d1181", "shasum": "" }, "require": { - "php": "^5.4 || ^7.0", + "php": ">=5.4", "psr/http-message": "~1.0" }, "provide": { "psr/http-message-implementation": "~1.0.0" }, "require-dev": { - "phpunit/phpunit": "^4.6 || ^5.5", + "phpunit/phpunit": "~4.6", "squizlabs/php_codesniffer": "^2.3.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3-dev", - "dev-develop": "1.4-dev" + "dev-master": "1.0-dev", + "dev-develop": "1.1-dev" } }, "autoload": { @@ -826,31 +816,28 @@ "psr", "psr-7" ], - "time": "2016-10-11T13:25:21+00:00" + "time": "2015-08-10T20:04:20+00:00" } ], "packages-dev": [ { "name": "composer/ca-bundle", - "version": "1.0.4", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "ec21a59414b99501e723b63fd664aa8ead9c5680" + "reference": "4059c02b474668bde9d115731615eaf073691ee1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/ec21a59414b99501e723b63fd664aa8ead9c5680", - "reference": "ec21a59414b99501e723b63fd664aa8ead9c5680", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/4059c02b474668bde9d115731615eaf073691ee1", + "reference": "4059c02b474668bde9d115731615eaf073691ee1", "shasum": "" }, "require": { - "ext-openssl": "*", - "ext-pcre": "*", "php": "^5.3.2 || ^7.0" }, "require-dev": { - "psr/log": "^1.0", "symfony/process": "^2.5 || ^3.0" }, "suggest": { @@ -886,20 +873,20 @@ "ssl", "tls" ], - "time": "2016-09-04T19:00:06+00:00" + "time": "2016-04-11T15:47:46+00:00" }, { "name": "composer/composer", - "version": "1.2.1", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "16422c4b1ac4286f7caecf5211136dc073191672" + "reference": "b49a006748a460f8dae6500ec80ed021501ce969" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/16422c4b1ac4286f7caecf5211136dc073191672", - "reference": "16422c4b1ac4286f7caecf5211136dc073191672", + "url": "https://api.github.com/repos/composer/composer/zipball/b49a006748a460f8dae6500ec80ed021501ce969", + "reference": "b49a006748a460f8dae6500ec80ed021501ce969", "shasum": "" }, "require": { @@ -963,33 +950,33 @@ "dependency", "package" ], - "time": "2016-09-12T09:27:20+00:00" + "time": "2016-07-18T23:28:52+00:00" }, { "name": "composer/semver", - "version": "1.4.2", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573" + "reference": "d0e1ccc6d44ab318b758d709e19176037da6b1ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573", - "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573", + "url": "https://api.github.com/repos/composer/semver/zipball/d0e1ccc6d44ab318b758d709e19176037da6b1ba", + "reference": "d0e1ccc6d44ab318b758d709e19176037da6b1ba", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0" + "php": ">=5.3.2" }, "require-dev": { - "phpunit/phpunit": "^4.5 || ^5.0.5", - "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "~2.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "0.1-dev" } }, "autoload": { @@ -1002,6 +989,10 @@ "MIT" ], "authors": [ + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com" + }, { "name": "Nils Adermann", "email": "naderman@naderman.de", @@ -1011,11 +1002,6 @@ "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" } ], "description": "Semver library that offers utilities, version constraint parsing and validation.", @@ -1025,33 +1011,34 @@ "validation", "versioning" ], - "time": "2016-08-30T16:08:34+00:00" + "time": "2015-09-21T09:42:36+00:00" }, { "name": "composer/spdx-licenses", - "version": "1.1.5", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "96c6a07b05b716e89a44529d060bc7f5c263cb13" + "reference": "abf7dfc7da7d7dc66c147a91b6e927099512292a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/96c6a07b05b716e89a44529d060bc7f5c263cb13", - "reference": "96c6a07b05b716e89a44529d060bc7f5c263cb13", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/abf7dfc7da7d7dc66c147a91b6e927099512292a", + "reference": "abf7dfc7da7d7dc66c147a91b6e927099512292a", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0" + "justinrainbow/json-schema": "~1.4", + "php": ">=5.3.2" }, "require-dev": { - "phpunit/phpunit": "^4.5 || ^5.0.5", - "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "~2.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "1.0-dev" } }, "autoload": { @@ -1064,6 +1051,10 @@ "MIT" ], "authors": [ + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com" + }, { "name": "Nils Adermann", "email": "naderman@naderman.de", @@ -1073,11 +1064,6 @@ "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" } ], "description": "SPDX licenses list and validation library.", @@ -1086,20 +1072,75 @@ "spdx", "validator" ], - "time": "2016-09-28T07:17:45+00:00" + "time": "2015-07-15T17:38:14+00:00" + }, + { + "name": "dflydev/markdown", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-markdown.git", + "reference": "76501a808522dbe40a5a71d272bd08d54cbae03d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-markdown/zipball/76501a808522dbe40a5a71d272bd08d54cbae03d", + "reference": "76501a808522dbe40a5a71d272bd08d54cbae03d", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "autoload": { + "psr-0": { + "dflydev\\markdown": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "New BSD License" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Michel Fortin", + "homepage": "http://michelf.com" + }, + { + "name": "John Gruber", + "homepage": "http://daringfireball.net" + } + ], + "description": "PHP Markdown & Extra", + "homepage": "http://github.com/dflydev/dflydev-markdown", + "keywords": [ + "markdown" + ], + "abandoned": "michelf/php-markdown", + "time": "2012-01-02T23:11:32+00:00" }, { "name": "doctrine/instantiator", - "version": "1.0.5", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f976e5de371104877ebc89bd8fecb0019ed9c119", + "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119", "shasum": "" }, "require": { @@ -1110,7 +1151,7 @@ "ext-pdo": "*", "ext-phar": "*", "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" + "squizlabs/php_codesniffer": "2.0.*@ALPHA" }, "type": "library", "extra": { @@ -1119,8 +1160,8 @@ } }, "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + "psr-0": { + "Doctrine\\Instantiator\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1140,29 +1181,29 @@ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2014-10-13T12:58:55+00:00" }, { "name": "justinrainbow/json-schema", - "version": "2.0.5", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "6b2a33e6a768f96bdc2ead5600af0822eed17d67" + "reference": "f9e27c3e202faf14fd581ef41355d83bb4b7eb7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/6b2a33e6a768f96bdc2ead5600af0822eed17d67", - "reference": "6b2a33e6a768f96bdc2ead5600af0822eed17d67", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/f9e27c3e202faf14fd581ef41355d83bb4b7eb7d", + "reference": "f9e27c3e202faf14fd581ef41355d83bb4b7eb7d", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.2" }, "require-dev": { - "json-schema/json-schema-test-suite": "1.2.0", + "json-schema/json-schema-test-suite": "1.1.0", "phpdocumentor/phpdocumentor": "~2", - "phpunit/phpunit": "^4.8.22" + "phpunit/phpunit": "~3.7" }, "bin": [ "bin/validate-json" @@ -1170,7 +1211,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.4.x-dev" } }, "autoload": { @@ -1180,7 +1221,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { @@ -1206,20 +1247,20 @@ "json", "schema" ], - "time": "2016-06-02T10:59:52+00:00" + "time": "2016-01-06T14:37:04+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.5.4", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "ea74994a3dc7f8d2f65a06009348f2d63c81e61f" + "reference": "96fbdc07635989c35c5a1912379f4c4b2ab15fd5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/ea74994a3dc7f8d2f65a06009348f2d63c81e61f", - "reference": "ea74994a3dc7f8d2f65a06009348f2d63c81e61f", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/96fbdc07635989c35c5a1912379f4c4b2ab15fd5", + "reference": "96fbdc07635989c35c5a1912379f4c4b2ab15fd5", "shasum": "" }, "require": { @@ -1248,138 +1289,38 @@ "object", "object graph" ], - "time": "2016-09-16T13:37:59+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "1.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "shasum": "" - }, - "require": { - "php": ">=5.5" - }, - "require-dev": { - "phpunit/phpunit": "^4.6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "time": "2015-12-27T11:43:31+00:00" + "time": "2015-03-21T22:40:23+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "3.1.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", - "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", - "shasum": "" - }, - "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0@dev", - "phpdocumentor/type-resolver": "^0.2.0", - "webmozart/assert": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2016-09-30T07:12:33+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "0.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443" + "reference": "66ae84e9d7c8ea85c979cb65977bd8e608baf0c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443", - "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/66ae84e9d7c8ea85c979cb65977bd8e608baf0c5", + "reference": "66ae84e9d7c8ea85c979cb65977bd8e608baf0c5", "shasum": "" }, "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0" + "dflydev/markdown": "1.0.*", + "php": ">=5.3.3" }, "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" + "phpunit/phpunit": "3.7.*@stable" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ + "psr-0": { + "phpDocumentor": [ "src/" ] } @@ -1391,39 +1332,36 @@ "authors": [ { "name": "Mike van Riel", - "email": "me@mikevanriel.com" + "email": "mike.vanriel@naenius.com" } ], - "time": "2016-06-10T07:14:17+00:00" + "time": "2013-08-07T11:04:22+00:00" }, { "name": "phpspec/prophecy", - "version": "v1.6.1", + "version": "v1.3.1", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0" + "reference": "9ca52329bcdd1500de24427542577ebf3fc2f1c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/9ca52329bcdd1500de24427542577ebf3fc2f1c9", + "reference": "9ca52329bcdd1500de24427542577ebf3fc2f1c9", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", - "sebastian/comparator": "^1.1", - "sebastian/recursion-context": "^1.0" + "doctrine/instantiator": "~1.0,>=1.0.2", + "phpdocumentor/reflection-docblock": "~2.0" }, "require-dev": { - "phpspec/phpspec": "^2.0" + "phpspec/phpspec": "~2.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -1447,7 +1385,7 @@ } ], "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", + "homepage": "http://phpspec.org", "keywords": [ "Double", "Dummy", @@ -1456,7 +1394,7 @@ "spy", "stub" ], - "time": "2016-06-07T08:13:47+00:00" + "time": "2014-11-17T16:23:49+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1523,16 +1461,16 @@ }, { "name": "phpunit/php-file-iterator", - "version": "1.4.1", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + "reference": "a923bb15680d0089e2316f7a4af8f437046e96bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a923bb15680d0089e2316f7a4af8f437046e96bb", + "reference": "a923bb15680d0089e2316f7a4af8f437046e96bb", "shasum": "" }, "require": { @@ -1566,20 +1504,20 @@ "filesystem", "iterator" ], - "time": "2015-06-21T13:08:43+00:00" + "time": "2015-04-02T05:19:05+00:00" }, { "name": "phpunit/php-text-template", - "version": "1.2.1", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", "shasum": "" }, "require": { @@ -1588,17 +1526,20 @@ "type": "library", "autoload": { "classmap": [ - "src/" + "Text/" ] }, "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", + "email": "sb@sebastian-bergmann.de", "role": "lead" } ], @@ -1607,28 +1548,25 @@ "keywords": [ "template" ], - "time": "2015-06-21T13:50:34+00:00" + "time": "2014-01-30T17:20:04+00:00" }, { "name": "phpunit/php-timer", - "version": "1.0.8", + "version": "1.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + "reference": "83fe1bdc5d47658b727595c14da140da92b3d66d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/83fe1bdc5d47658b727595c14da140da92b3d66d", + "reference": "83fe1bdc5d47658b727595c14da140da92b3d66d", "shasum": "" }, "require": { "php": ">=5.3.3" }, - "require-dev": { - "phpunit/phpunit": "~4|~5" - }, "type": "library", "autoload": { "classmap": [ @@ -1651,20 +1589,20 @@ "keywords": [ "timer" ], - "time": "2016-05-12T18:03:57+00:00" + "time": "2015-06-13T07:35:30+00:00" }, { "name": "phpunit/php-token-stream", - "version": "1.4.8", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" + "reference": "db63be1159c81df649cd0260e30249a586d4129e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", - "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/db63be1159c81df649cd0260e30249a586d4129e", + "reference": "db63be1159c81df649cd0260e30249a586d4129e", "shasum": "" }, "require": { @@ -1700,20 +1638,20 @@ "keywords": [ "tokenizer" ], - "time": "2015-09-15T10:49:45+00:00" + "time": "2015-06-12T07:34:24+00:00" }, { "name": "phpunit/phpunit", - "version": "5.6.2", + "version": "5.6.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "cd13b23ac5a519a4708e00736c26ee0bb28b2e01" + "reference": "a7f2db56518e50ab92f28f739810dfad2f223b6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/cd13b23ac5a519a4708e00736c26ee0bb28b2e01", - "reference": "cd13b23ac5a519a4708e00736c26ee0bb28b2e01", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a7f2db56518e50ab92f28f739810dfad2f223b6b", + "reference": "a7f2db56518e50ab92f28f739810dfad2f223b6b", "shasum": "" }, "require": { @@ -1782,20 +1720,20 @@ "testing", "xunit" ], - "time": "2016-10-25T07:40:25+00:00" + "time": "2016-10-06T15:20:39+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "3.4.0", + "version": "3.3.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "238d7a2723bce689c79eeac9c7d5e1d623bb9dc2" + "reference": "7462c19bdb9814f6e6bdeb5cad3eb3ce72c6e0da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/238d7a2723bce689c79eeac9c7d5e1d623bb9dc2", - "reference": "238d7a2723bce689c79eeac9c7d5e1d623bb9dc2", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/7462c19bdb9814f6e6bdeb5cad3eb3ce72c6e0da", + "reference": "7462c19bdb9814f6e6bdeb5cad3eb3ce72c6e0da", "shasum": "" }, "require": { @@ -1841,34 +1779,26 @@ "mock", "xunit" ], - "time": "2016-10-09T07:01:45+00:00" + "time": "2016-09-27T03:17:40+00:00" }, { "name": "psr/log", - "version": "1.0.2", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", "shasum": "" }, - "require": { - "php": ">=5.3.0" - }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" + "psr-0": { + "Psr\\Log\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -1882,13 +1812,12 @@ } ], "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", "keywords": [ "log", "psr", "psr-3" ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2012-12-21T11:40:51+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -1937,30 +1866,30 @@ }, { "name": "sebastian/comparator", - "version": "1.2.0", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" + "reference": "c484a80f97573ab934e37826dba0135a3301b26a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/c484a80f97573ab934e37826dba0135a3301b26a", + "reference": "c484a80f97573ab934e37826dba0135a3301b26a", "shasum": "" }, "require": { "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2" + "sebastian/diff": "~1.1", + "sebastian/exporter": "~1.0" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "~4.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -1997,32 +1926,32 @@ "compare", "equality" ], - "time": "2015-07-26T15:48:44+00:00" + "time": "2014-11-16T21:32:38+00:00" }, { "name": "sebastian/diff", - "version": "1.4.1", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + "reference": "5843509fed39dee4b356a306401e9dd1a931fec7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/5843509fed39dee4b356a306401e9dd1a931fec7", + "reference": "5843509fed39dee4b356a306401e9dd1a931fec7", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { - "phpunit/phpunit": "~4.8" + "phpunit/phpunit": "~4.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.2-dev" } }, "autoload": { @@ -2045,31 +1974,31 @@ } ], "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", + "homepage": "http://www.github.com/sebastianbergmann/diff", "keywords": [ "diff" ], - "time": "2015-12-08T07:14:41+00:00" + "time": "2014-08-15T10:29:00+00:00" }, { "name": "sebastian/environment", - "version": "1.3.8", + "version": "1.3.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" + "reference": "6324c907ce7a52478eeeaede764f48733ef5ae44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6324c907ce7a52478eeeaede764f48733ef5ae44", + "reference": "6324c907ce7a52478eeeaede764f48733ef5ae44", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": ">=5.3.3" }, "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.0" + "phpunit/phpunit": "~4.4" }, "type": "library", "extra": { @@ -2099,20 +2028,20 @@ "environment", "hhvm" ], - "time": "2016-08-18T05:49:44+00:00" + "time": "2015-08-03T06:14:51+00:00" }, { "name": "sebastian/exporter", - "version": "1.2.2", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + "reference": "84839970d05254c73cde183a721c7af13aede943" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943", + "reference": "84839970d05254c73cde183a721c7af13aede943", "shasum": "" }, "require": { @@ -2120,13 +2049,12 @@ "sebastian/recursion-context": "~1.0" }, "require-dev": { - "ext-mbstring": "*", "phpunit/phpunit": "~4.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -2166,20 +2094,20 @@ "export", "exporter" ], - "time": "2016-06-17T09:04:28+00:00" + "time": "2015-01-27T07:23:06+00:00" }, { "name": "sebastian/global-state", - "version": "1.1.1", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01", "shasum": "" }, "require": { @@ -2217,7 +2145,7 @@ "keywords": [ "global state" ], - "time": "2015-10-12T03:26:01+00:00" + "time": "2014-10-06T09:23:50+00:00" }, { "name": "sebastian/object-enumerator", @@ -2267,16 +2195,16 @@ }, { "name": "sebastian/recursion-context", - "version": "1.0.2", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791" + "reference": "3989662bbb30a29d20d9faa04a846af79b276252" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252", "shasum": "" }, "require": { @@ -2316,7 +2244,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2015-11-11T19:50:13+00:00" + "time": "2015-01-24T09:48:32+00:00" }, { "name": "sebastian/resource-operations", @@ -2362,27 +2290,19 @@ }, { "name": "sebastian/version", - "version": "2.0.0", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5" + "reference": "16b021aed448b654ae05846e394e057e9a6f04cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5", - "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/16b021aed448b654ae05846e394e057e9a6f04cb", + "reference": "16b021aed448b654ae05846e394e057e9a6f04cb", "shasum": "" }, - "require": { - "php": ">=5.6" - }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, "autoload": { "classmap": [ "src/" @@ -2401,20 +2321,20 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-02-04T12:56:52+00:00" + "time": "2013-01-05T14:27:32+00:00" }, { "name": "seld/cli-prompt", - "version": "1.0.2", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/Seldaek/cli-prompt.git", - "reference": "8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4" + "reference": "fe114c7a6ac5cb0ce76932ae4017024d9842a49c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4", - "reference": "8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4", + "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/fe114c7a6ac5cb0ce76932ae4017024d9842a49c", + "reference": "fe114c7a6ac5cb0ce76932ae4017024d9842a49c", "shasum": "" }, "require": { @@ -2449,20 +2369,20 @@ "input", "prompt" ], - "time": "2016-04-18T09:31:41+00:00" + "time": "2015-04-30T20:24:49+00:00" }, { "name": "seld/jsonlint", - "version": "1.4.1", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "e827b5254d3e58c736ea2c5616710983d80b0b70" + "reference": "66834d3e3566bb5798db7294619388786ae99394" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/e827b5254d3e58c736ea2c5616710983d80b0b70", - "reference": "e827b5254d3e58c736ea2c5616710983d80b0b70", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/66834d3e3566bb5798db7294619388786ae99394", + "reference": "66834d3e3566bb5798db7294619388786ae99394", "shasum": "" }, "require": { @@ -2495,20 +2415,20 @@ "parser", "validator" ], - "time": "2016-09-14T15:17:56+00:00" + "time": "2015-11-21T02:21:41+00:00" }, { "name": "seld/phar-utils", - "version": "1.0.1", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/Seldaek/phar-utils.git", - "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a" + "reference": "336bb5ee20de511f3c1a164222fcfd194afcab3a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/7009b5139491975ef6486545a39f3e6dad5ac30a", - "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/336bb5ee20de511f3c1a164222fcfd194afcab3a", + "reference": "336bb5ee20de511f3c1a164222fcfd194afcab3a", "shasum": "" }, "require": { @@ -2539,31 +2459,27 @@ "keywords": [ "phra" ], - "time": "2015-10-13T18:44:15+00:00" + "time": "2015-05-01T12:45:48+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "2.7.0", + "version": "2.4.0", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "571e27b6348e5b3a637b2abc82ac0d01e6d7bbed" + "reference": "32a879f4f35019d78d568db2885d7779ca084a33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/571e27b6348e5b3a637b2abc82ac0d01e6d7bbed", - "reference": "571e27b6348e5b3a637b2abc82ac0d01e6d7bbed", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/32a879f4f35019d78d568db2885d7779ca084a33", + "reference": "32a879f4f35019d78d568db2885d7779ca084a33", "shasum": "" }, "require": { - "ext-simplexml": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", "php": ">=5.1.2" }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, "bin": [ "scripts/phpcs", "scripts/phpcbf" @@ -2571,7 +2487,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -2617,156 +2533,91 @@ "phpcs", "standards" ], - "time": "2016-09-01T23:53:02+00:00" + "time": "2015-11-23T21:30:59+00:00" }, { "name": "symfony/console", - "version": "v3.1.6", + "version": "v2.5.0", + "target-dir": "Symfony/Component/Console", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c99da1119ae61e15de0e4829196b9fba6f73d065" + "reference": "ef4ca73b0b3a10cbac653d3ca482d0cdd4502b2c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c99da1119ae61e15de0e4829196b9fba6f73d065", - "reference": "c99da1119ae61e15de0e4829196b9fba6f73d065", + "url": "https://api.github.com/repos/symfony/console/zipball/ef4ca73b0b3a10cbac653d3ca482d0cdd4502b2c", + "reference": "ef4ca73b0b3a10cbac653d3ca482d0cdd4502b2c", "shasum": "" }, "require": { - "php": ">=5.5.9", - "symfony/debug": "~2.8|~3.0", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=5.3.3" }, "require-dev": { "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/process": "~2.8|~3.0" + "symfony/event-dispatcher": "~2.1" }, "suggest": { "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/process": "" + "symfony/event-dispatcher": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "2.5-dev" } }, "autoload": { - "psr-4": { + "psr-0": { "Symfony\\Component\\Console\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, { "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Console Component", - "homepage": "https://symfony.com", - "time": "2016-10-06T01:44:51+00:00" - }, - { - "name": "symfony/debug", - "version": "v3.1.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "e2b3f74a67fc928adc3c1b9027f73e1bc01190a8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/e2b3f74a67fc928adc3c1b9027f73e1bc01190a8", - "reference": "e2b3f74a67fc928adc3c1b9027f73e1bc01190a8", - "shasum": "" - }, - "require": { - "php": ">=5.5.9", - "psr/log": "~1.0" - }, - "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" - }, - "require-dev": { - "symfony/class-loader": "~2.8|~3.0", - "symfony/http-kernel": "~2.8|~3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Debug\\": "" + "homepage": "http://symfony.com/contributors" }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Debug Component", - "homepage": "https://symfony.com", - "time": "2016-09-06T11:02:40+00:00" + "description": "Symfony Console Component", + "homepage": "http://symfony.com", + "time": "2014-05-22T08:54:24+00:00" }, { "name": "symfony/finder", - "version": "v3.1.6", + "version": "v2.2.0", + "target-dir": "Symfony/Component/Finder", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "205b5ffbb518a98ba2ae60a52656c4a31ab00c6f" + "reference": "2feb8d33876f64801bd1b14bdce829b314e2c418" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/205b5ffbb518a98ba2ae60a52656c4a31ab00c6f", - "reference": "205b5ffbb518a98ba2ae60a52656c4a31ab00c6f", + "url": "https://api.github.com/repos/symfony/finder/zipball/2feb8d33876f64801bd1b14bdce829b314e2c418", + "reference": "2feb8d33876f64801bd1b14bdce829b314e2c418", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.3.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "2.2-dev" } }, "autoload": { - "psr-4": { + "psr-0": { "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2774,184 +2625,71 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" } ], "description": "Symfony Finder Component", - "homepage": "https://symfony.com", - "time": "2016-09-28T00:11:12+00:00" + "homepage": "http://symfony.com", + "time": "2013-02-28T14:06:36+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.2.0", + "name": "symfony/yaml", + "version": "v2.1.0", + "target-dir": "Symfony/Component/Yaml", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "dff51f72b0706335131b00a7f49606168c582594" + "url": "https://github.com/symfony/yaml.git", + "reference": "f18e004fc975707bb4695df1dbbe9b0d8c8b7715" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", - "reference": "dff51f72b0706335131b00a7f49606168c582594", + "url": "https://api.github.com/repos/symfony/yaml/zipball/f18e004fc975707bb4695df1dbbe9b0d8c8b7715", + "reference": "f18e004fc975707bb4695df1dbbe9b0d8c8b7715", "shasum": "" }, "require": { "php": ">=5.3.3" }, - "suggest": { - "ext-mbstring": "For best performance" - }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "2.1-dev" } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "files": [ - "bootstrap.php" - ] + "psr-0": { + "Symfony\\Component\\Yaml": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, { "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "time": "2016-05-18T14:26:46+00:00" - }, - { - "name": "symfony/yaml", - "version": "v3.1.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "7ff51b06c6c3d5cc6686df69004a42c69df09e27" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/7ff51b06c6c3d5cc6686df69004a42c69df09e27", - "reference": "7ff51b06c6c3d5cc6686df69004a42c69df09e27", - "shasum": "" - }, - "require": { - "php": ">=5.5.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" + "homepage": "http://symfony.com/contributors" }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Yaml Component", - "homepage": "https://symfony.com", - "time": "2016-10-24T18:41:13+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "bb2d123231c095735130cc8f6d31385a44c7b308" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/bb2d123231c095735130cc8f6d31385a44c7b308", - "reference": "bb2d123231c095735130cc8f6d31385a44c7b308", - "shasum": "" - }, - "require": { - "php": "^5.3.3|^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "time": "2016-08-09T15:02:57+00:00" + "homepage": "http://symfony.com", + "time": "2012-08-22T13:48:41+00:00" } ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "composer/composer": 15 - }, + "stability-flags": [], "prefer-stable": false, - "prefer-lowest": false, + "prefer-lowest": true, "platform": { "php": ">=5.6", "ext-pdo_sqlite": "*" diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php index 920368a9..3c74628b 100644 --- a/src/Exception/InvalidArgumentException.php +++ b/src/Exception/InvalidArgumentException.php @@ -48,6 +48,22 @@ public static function notValidParameter($parameterName, array $allowedValues, $ ); } + /** + * @param object $object + * @param string $requiredInterface + * @return static + */ + public static function missingImplements($object, $requiredInterface) + { + return new static( + sprintf( + '"%s" is required to implement "%s", but it does not', + get_class($object), + $requiredInterface + ) + ); + } + /** * @param $value * @return string diff --git a/src/Exercise/ExerciseType.php b/src/Exercise/ExerciseType.php index f29644e6..893e27a5 100644 --- a/src/Exercise/ExerciseType.php +++ b/src/Exercise/ExerciseType.php @@ -3,8 +3,6 @@ namespace PhpSchool\PhpWorkshop\Exercise; use MyCLabs\Enum\Enum; -use PhpSchool\PhpWorkshop\ExerciseRunner\CgiRunner; -use PhpSchool\PhpWorkshop\ExerciseRunner\CliRunner; /** * This class is a ENUM which represents the types that exercises can be. Instantiation looks like: @@ -12,6 +10,7 @@ * ```php * $typeCli = ExerciseType::CLI(); * $typeCgi = ExerciseType::CGI(); + * $typeCustom = ExerciseType::CUSTOM(); * ``` * * @package PhpSchool\PhpWorkshop\Exercise @@ -19,6 +18,28 @@ */ class ExerciseType extends Enum { - const CLI = CliRunner::class; - const CGI = CgiRunner::class; + const CLI = 'CLI'; + const CGI = 'CGI'; + + /** + * Map of exercise types to the required interfaces exercises of that particular + * type should implement. + * + * @var array + */ + private static $exerciseTypeToExerciseInterfaceMap = [ + self::CLI => CliExercise::class, + self::CGI => CgiExercise::class, + ]; + + /** + * Get the FQCN of the interface this exercise should implement for this + * exercise type. + * + * @return string + */ + public function getExerciseInterface() + { + return static::$exerciseTypeToExerciseInterfaceMap[$this->getKey()]; + } } diff --git a/src/Exercise/ProvidesSolution.php b/src/Exercise/ProvidesSolution.php index 2aa12156..9cc40aa8 100644 --- a/src/Exercise/ProvidesSolution.php +++ b/src/Exercise/ProvidesSolution.php @@ -15,4 +15,4 @@ interface ProvidesSolution * @return SolutionInterface */ public function getSolution(); -} \ No newline at end of file +} diff --git a/src/ExerciseDispatcher.php b/src/ExerciseDispatcher.php index 7be264c2..fa4a190b 100644 --- a/src/ExerciseDispatcher.php +++ b/src/ExerciseDispatcher.php @@ -12,7 +12,7 @@ use PhpSchool\PhpWorkshop\Exception\ExerciseNotConfiguredException; use PhpSchool\PhpWorkshop\Exception\InvalidArgumentException; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; -use PhpSchool\PhpWorkshop\Factory\RunnerFactory; +use PhpSchool\PhpWorkshop\ExerciseRunner\RunnerManager; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\Output\OutputInterface; @@ -36,9 +36,9 @@ class ExerciseDispatcher private $checksToRunAfter = []; /** - * @var RunnerFactory + * @var RunnerManager */ - private $runnerFactory; + private $runnerManager; /** * @var ResultAggregator @@ -56,18 +56,18 @@ class ExerciseDispatcher private $checkRepository; /** - * @param RunnerFactory $runnerFactory Factory capable of building an exercise runner based on the exercise type. + * @param RunnerManager $runnerManager Factory capable of building an exercise runner based on the exercise type. * @param ResultAggregator $resultAggregator * @param EventDispatcher $eventDispatcher * @param CheckRepository $checkRepository */ public function __construct( - RunnerFactory $runnerFactory, + RunnerManager $runnerManager, ResultAggregator $resultAggregator, EventDispatcher $eventDispatcher, CheckRepository $checkRepository ) { - $this->runnerFactory = $runnerFactory; + $this->runnerManager = $runnerManager; $this->results = $resultAggregator; $this->eventDispatcher = $eventDispatcher; $this->checkRepository = $checkRepository; @@ -130,7 +130,12 @@ public function verify(ExerciseInterface $exercise, Input $input) { $exercise->configure($this); - $runner = $this->runnerFactory->create($exercise, $this->eventDispatcher, $this); + $runner = $this->runnerManager->getRunner($exercise); + + foreach ($runner->getRequiredChecks() as $requiredCheck) { + $this->requireCheck($requiredCheck); + } + $this->eventDispatcher->dispatch(new Event('verify.start', compact('exercise', 'input'))); $this->validateChecks($this->checksToRunBefore, $exercise); @@ -179,8 +184,8 @@ public function run(ExerciseInterface $exercise, Input $input, OutputInterface $ $this->eventDispatcher->dispatch(new Event('run.start', compact('exercise', 'input'))); try { - $exitStatus = $this->runnerFactory - ->create($exercise, $this->eventDispatcher, $this) + $exitStatus = $this->runnerManager + ->getRunner($exercise) ->run($input, $output); } finally { $this->eventDispatcher->dispatch(new Event('run.finish', compact('exercise', 'input'))); diff --git a/src/ExerciseRepository.php b/src/ExerciseRepository.php index 7a78f7ef..484f4fd4 100644 --- a/src/ExerciseRepository.php +++ b/src/ExerciseRepository.php @@ -4,7 +4,7 @@ use ArrayIterator; use Countable; -use InvalidArgumentException; +use PhpSchool\PhpWorkshop\Exception\InvalidArgumentException; use IteratorAggregate; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; @@ -28,12 +28,28 @@ class ExerciseRepository implements IteratorAggregate, Countable */ public function __construct(array $exercises) { - //type safety - $this->exercises = array_map(function (ExerciseInterface $e) { - return $e; + $this->exercises = array_map(function (ExerciseInterface $exercise) { + return $this->validateExercise($exercise); }, $exercises); } + /** + * @param ExerciseInterface $exercise + * @return ExerciseInterface + */ + private function validateExercise(ExerciseInterface $exercise) + { + $type = $exercise->getType(); + + $requiredInterface = $type->getExerciseInterface(); + + if (!$exercise instanceof $requiredInterface) { + throw InvalidArgumentException::missingImplements($exercise, $requiredInterface); + } + + return $exercise; + } + /** * Retrieve all of the exercises as an array. * diff --git a/src/ExerciseRunner/CgiRunner.php b/src/ExerciseRunner/CgiRunner.php index 08d08965..c709be16 100644 --- a/src/ExerciseRunner/CgiRunner.php +++ b/src/ExerciseRunner/CgiRunner.php @@ -91,19 +91,17 @@ public function getName() } /** - * Configure the exercise dispatcher. For example set the required checks - * for this exercise type. + * Get an array of the class names of the required checks this runner needs. * - * @param ExerciseDispatcher $exerciseDispatcher - * @return self + * @return array */ - public function configure(ExerciseDispatcher $exerciseDispatcher) + public function getRequiredChecks() { - $exerciseDispatcher->requireCheck(FileExistsCheck::class); - $exerciseDispatcher->requireCheck(PhpLintCheck::class); - $exerciseDispatcher->requireCheck(CodeParseCheck::class); - - return $this; + return [ + FileExistsCheck::class, + PhpLintCheck::class, + CodeParseCheck::class, + ]; } /** diff --git a/src/ExerciseRunner/CliRunner.php b/src/ExerciseRunner/CliRunner.php index 4f4947d3..dfac049f 100644 --- a/src/ExerciseRunner/CliRunner.php +++ b/src/ExerciseRunner/CliRunner.php @@ -64,19 +64,17 @@ public function getName() } /** - * Configure the exercise dispatcher. For example set the required checks - * for this exercise type. + * Get an array of the class names of the required checks this runner needs. * - * @param ExerciseDispatcher $exerciseDispatcher - * @return self + * @return array */ - public function configure(ExerciseDispatcher $exerciseDispatcher) + public function getRequiredChecks() { - $exerciseDispatcher->requireCheck(FileExistsCheck::class); - $exerciseDispatcher->requireCheck(PhpLintCheck::class); - $exerciseDispatcher->requireCheck(CodeParseCheck::class); - - return $this; + return [ + FileExistsCheck::class, + PhpLintCheck::class, + CodeParseCheck::class, + ]; } /** diff --git a/src/ExerciseRunner/ExerciseRunnerInterface.php b/src/ExerciseRunner/ExerciseRunnerInterface.php index 4a88b5b7..4e91c396 100644 --- a/src/ExerciseRunner/ExerciseRunnerInterface.php +++ b/src/ExerciseRunner/ExerciseRunnerInterface.php @@ -25,13 +25,11 @@ interface ExerciseRunnerInterface public function getName(); /** - * Configure the exercise dispatcher. For example set the required checks - * for this exercise type. + * Get an array of the class names of the required checks this runner needs. * - * @param ExerciseDispatcher $exerciseDispatcher - * @return self + * @return array */ - public function configure(ExerciseDispatcher $exerciseDispatcher); + public function getRequiredChecks(); /** * Verify a solution to an exercise. Verification involves executing the reference solution diff --git a/src/ExerciseRunner/Factory/CgiRunnerFactory.php b/src/ExerciseRunner/Factory/CgiRunnerFactory.php new file mode 100644 index 00000000..b9f02040 --- /dev/null +++ b/src/ExerciseRunner/Factory/CgiRunnerFactory.php @@ -0,0 +1,67 @@ + + */ +class CgiRunnerFactory implements ExerciseRunnerFactoryInterface +{ + /** + * @var string + */ + private static $type = ExerciseType::CGI; + + /** + * @var EventDispatcher + */ + private $eventDispatcher; + + /** + * @param EventDispatcher $eventDispatcher + */ + public function __construct(EventDispatcher $eventDispatcher) + { + $this->eventDispatcher = $eventDispatcher; + } + + /** + * Whether the factory supports this exercise type. + * + * @param ExerciseInterface $exercise + * @return bool + */ + public function supports(ExerciseInterface $exercise) + { + return $exercise->getType()->getValue() === self::$type; + } + + /** + * Add any extra required arguments to the command. + * + * @param CommandDefinition $commandDefinition + */ + public function configureInput(CommandDefinition $commandDefinition) + { + $commandDefinition->addArgument(CommandArgument::required('program')); + } + + /** + * Create and return an instance of the runner. + * + * @param ExerciseInterface $exercise + * @return ExerciseRunnerInterface + */ + public function create(ExerciseInterface $exercise) + { + return new CgiRunner($exercise, $this->eventDispatcher); + } +} diff --git a/src/ExerciseRunner/Factory/CliRunnerFactory.php b/src/ExerciseRunner/Factory/CliRunnerFactory.php new file mode 100644 index 00000000..862bbc07 --- /dev/null +++ b/src/ExerciseRunner/Factory/CliRunnerFactory.php @@ -0,0 +1,67 @@ + + */ +class CliRunnerFactory implements ExerciseRunnerFactoryInterface +{ + /** + * @var string + */ + private static $type = ExerciseType::CLI; + + /** + * @var EventDispatcher + */ + private $eventDispatcher; + + /** + * @param EventDispatcher $eventDispatcher + */ + public function __construct(EventDispatcher $eventDispatcher) + { + $this->eventDispatcher = $eventDispatcher; + } + + /** + * Whether the factory supports this exercise type. + * + * @param ExerciseInterface $exercise + * @return bool + */ + public function supports(ExerciseInterface $exercise) + { + return $exercise->getType()->getValue() === self::$type; + } + + /** + * Add any extra required arguments to the command. + * + * @param CommandDefinition $commandDefinition + */ + public function configureInput(CommandDefinition $commandDefinition) + { + $commandDefinition->addArgument(CommandArgument::required('program')); + } + + /** + * Create and return an instance of the runner. + * + * @param ExerciseInterface $exercise + * @return ExerciseRunnerInterface + */ + public function create(ExerciseInterface $exercise) + { + return new CliRunner($exercise, $this->eventDispatcher); + } +} diff --git a/src/ExerciseRunner/Factory/ExerciseRunnerFactoryInterface.php b/src/ExerciseRunner/Factory/ExerciseRunnerFactoryInterface.php new file mode 100644 index 00000000..04e8d716 --- /dev/null +++ b/src/ExerciseRunner/Factory/ExerciseRunnerFactoryInterface.php @@ -0,0 +1,36 @@ + + */ +interface ExerciseRunnerFactoryInterface +{ + /** + * Whether the factory supports this exercise type. + * + * @param ExerciseInterface $exercise + * @return bool + */ + public function supports(ExerciseInterface $exercise); + + /** + * Add any extra required arguments to the command. + * + * @param CommandDefinition $commandDefinition + */ + public function configureInput(CommandDefinition $commandDefinition); + + /** + * Create and return an instance of the runner. + * + * @param ExerciseInterface $exercise + * @return ExerciseRunnerInterface + */ + public function create(ExerciseInterface $exercise); +} diff --git a/src/ExerciseRunner/RunnerManager.php b/src/ExerciseRunner/RunnerManager.php new file mode 100644 index 00000000..1e7b7479 --- /dev/null +++ b/src/ExerciseRunner/RunnerManager.php @@ -0,0 +1,64 @@ + + */ +class RunnerManager +{ + /** + * @var ExerciseRunnerFactoryInterface[] + */ + private $factories = []; + + /** + * @param ExerciseRunnerFactoryInterface $factory + */ + public function addFactory(ExerciseRunnerFactoryInterface $factory) + { + $this->factories[] = $factory; + } + + /** + * @param ExerciseInterface $exercise + * @param CommandDefinition $commandDefinition + */ + public function configureInput(ExerciseInterface $exercise, CommandDefinition $commandDefinition) + { + $this->getFactory($exercise)->configureInput($commandDefinition); + } + + /** + * @param ExerciseInterface $exercise + * @return ExerciseRunnerInterface + */ + public function getRunner(ExerciseInterface $exercise) + { + return $this->getFactory($exercise)->create($exercise); + } + + /** + * @param ExerciseInterface $exercise + * @return ExerciseRunnerFactoryInterface + * @throws InvalidArgumentException + */ + private function getFactory(ExerciseInterface $exercise) + { + foreach ($this->factories as $factory) { + if ($factory->supports($exercise)) { + return $factory; + } + } + + throw new InvalidArgumentException( + sprintf('Exercise Type: "%s" not supported', $exercise->getType()->getValue()) + ); + } +} diff --git a/src/Factory/RunnerFactory.php b/src/Factory/RunnerFactory.php deleted file mode 100644 index d2a3a948..00000000 --- a/src/Factory/RunnerFactory.php +++ /dev/null @@ -1,48 +0,0 @@ - - */ -class RunnerFactory -{ - /** - * @param ExerciseInterface $exercise - * @param EventDispatcher $eventDispatcher - * @param ExerciseDispatcher $exerciseDispatcher - * @return ExerciseRunnerInterface - */ - public function create( - ExerciseInterface $exercise, - EventDispatcher $eventDispatcher, - ExerciseDispatcher $exerciseDispatcher - ) { - switch ($exercise->getType()->getValue()) { - case ExerciseType::CLI: - $runner = new CliRunner($exercise, $eventDispatcher); - break; - case ExerciseType::CGI: - $runner = new CgiRunner($exercise, $eventDispatcher); - break; - default: - throw new InvalidArgumentException( - sprintf('Exercise Type: "%s" not supported', $exercise->getType()->getValue()) - ); - } - - return $runner->configure($exerciseDispatcher); - } -} diff --git a/src/Listener/ConfigureCommandListener.php b/src/Listener/ConfigureCommandListener.php new file mode 100644 index 00000000..03dba51a --- /dev/null +++ b/src/Listener/ConfigureCommandListener.php @@ -0,0 +1,59 @@ + + */ +class ConfigureCommandListener +{ + /** + * @var ExerciseRepository + */ + private $exerciseRepository; + + /** + * @var RunnerManager + */ + private $runnerManager; + + /** + * @param UserState $userState + * @param ExerciseRepository $exerciseRepository + * @param RunnerManager $runnerManager + */ + public function __construct( + UserState $userState, + ExerciseRepository $exerciseRepository, + RunnerManager $runnerManager + ) { + $this->userState = $userState; + $this->exerciseRepository = $exerciseRepository; + $this->runnerManager = $runnerManager; + } + + /** + * @param Event $event + */ + public function __invoke(Event $event) + { + /** @var CommandDefinition $command */ + $command = $event->getParameter('command'); + + if (!in_array($command->getName(), ['verify', 'run'])) { + return; + } + + $currentExercise = $this->exerciseRepository->findByName( + $this->userState->getCurrentExercise() + ); + + $this->runnerManager->configureInput($currentExercise, $command); + } +} diff --git a/test/Asset/CgiExerciseImpl.php b/test/Asset/CgiExerciseImpl.php new file mode 100644 index 00000000..4acbade6 --- /dev/null +++ b/test/Asset/CgiExerciseImpl.php @@ -0,0 +1,99 @@ + + */ +class CgiExerciseImpl implements ExerciseInterface, CgiExercise +{ + + /** + * @var string + */ + private $name; + + /** + * @param string $name + */ + public function __construct($name = 'my-exercise') + { + $this->name = $name; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @return string + */ + public function getDescription() + { + return $this->name; + } + + /** + * @return string + */ + public function getSolution() + { + // TODO: Implement getSolution() method. + } + + /** + * @return string + */ + public function getProblem() + { + // TODO: Implement getProblem() method. + } + + /** + * @return void + */ + public function tearDown() + { + // TODO: Implement tearDown() method. + } + + /** + * This method should return an array of PSR-7 requests, which will be forwarded to the student's + * solution. + * + * @return RequestInterface[] An array of PSR-7 requests. + */ + public function getRequests() + { + // TODO: Implement getRequests() method. + } + + /** + * @return ExerciseType + */ + public function getType() + { + return ExerciseType::CGI(); + } + + /** + * @param ExerciseDispatcher $dispatcher + */ + public function configure(ExerciseDispatcher $dispatcher) + { + } +} diff --git a/test/Asset/CliExerciseImpl.php b/test/Asset/CliExerciseImpl.php new file mode 100644 index 00000000..6476fe04 --- /dev/null +++ b/test/Asset/CliExerciseImpl.php @@ -0,0 +1,94 @@ + + */ +class CliExerciseImpl implements ExerciseInterface, CliExercise +{ + + /** + * @var string + */ + private $name; + + /** + * @param string $name + */ + public function __construct($name = 'my-exercise') + { + $this->name = $name; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @return string + */ + public function getDescription() + { + return $this->name; + } + + /** + * @return string + */ + public function getSolution() + { + // TODO: Implement getSolution() method. + } + + /** + * @return string + */ + public function getProblem() + { + // TODO: Implement getProblem() method. + } + + /** + * @return void + */ + public function tearDown() + { + // TODO: Implement tearDown() method. + } + + /** + * @return array + */ + public function getArgs() + { + // TODO: Implement getArgs() method. + } + + /** + * @return ExerciseType + */ + public function getType() + { + return ExerciseType::CLI(); + } + + /** + * @param ExerciseDispatcher $dispatcher + */ + public function configure(ExerciseDispatcher $dispatcher) + { + } +} diff --git a/test/Asset/CliExerciseMissingInterface.php b/test/Asset/CliExerciseMissingInterface.php new file mode 100644 index 00000000..ec0bd565 --- /dev/null +++ b/test/Asset/CliExerciseMissingInterface.php @@ -0,0 +1,44 @@ + + */ +class CliExerciseMissingInterface extends AbstractExercise implements ExerciseInterface +{ + + /** + * Get the name of the exercise, like `Hello World!`. + * + * @return string + */ + public function getName() + { + return 'CLI exercise missing interface'; + } + + /** + * A short description of the exercise. + * + * @return string + */ + public function getDescription() + { + return 'CLI exercise missing interface'; + } + + /** + * Return the type of exercise. This is an ENUM. See `PhpSchool\PhpWorkshop\Exercise\ExerciseType`. + * + * @return ExerciseType + */ + public function getType() + { + return ExerciseType::CLI(); + } +} diff --git a/test/Asset/ComposerExercise.php b/test/Asset/ComposerExercise.php index bd7218b9..3fc4b12d 100644 --- a/test/Asset/ComposerExercise.php +++ b/test/Asset/ComposerExercise.php @@ -21,7 +21,7 @@ class ComposerExercise implements ExerciseInterface, ComposerExerciseCheck */ public function getName() { - // TODO: Implement getName() method. + return 'composer-exercise'; } /** diff --git a/test/Check/DatabaseCheckTest.php b/test/Check/DatabaseCheckTest.php index 770c45fd..4fc28053 100644 --- a/test/Check/DatabaseCheckTest.php +++ b/test/Check/DatabaseCheckTest.php @@ -14,7 +14,7 @@ use PhpSchool\PhpWorkshop\ExerciseCheck\DatabaseExerciseCheck; use PhpSchool\PhpWorkshop\ExerciseDispatcher; use PhpSchool\PhpWorkshop\ExerciseRunner\CliRunner; -use PhpSchool\PhpWorkshop\Factory\RunnerFactory; +use PhpSchool\PhpWorkshop\ExerciseRunner\RunnerManager; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\Output\OutputInterface; use PhpSchool\PhpWorkshop\ResultAggregator; @@ -61,6 +61,7 @@ public function setUp() $this->check = new DatabaseCheck; $this->exercise = $this->createMock(DatabaseExerciseInterface::class); + $this->exercise->expects($this->any())->method('getType')->willReturn(ExerciseType::CLI()); $this->dbDir = sprintf( '%s/PhpSchool_PhpWorkshop_Check_DatabaseCheck', str_replace('\\', '/', realpath(sys_get_temp_dir())) @@ -75,20 +76,25 @@ public function setUp() * @param EventDispatcher $eventDispatcher * @return \PHPUnit_Framework_MockObject_MockObject */ - private function getRunnerFactory(ExerciseInterface $exercise, EventDispatcher $eventDispatcher) + private function getRunnerManager(ExerciseInterface $exercise, EventDispatcher $eventDispatcher) { $runner = $this->getMockBuilder(CliRunner::class) ->setConstructorArgs([$exercise, $eventDispatcher]) - ->setMethods(['configure']) + ->setMethods(['configure', 'getRequiredChecks']) ->getMock(); - $runnerFactory = $this->createMock(RunnerFactory::class); - $runnerFactory + $runner + ->expects($this->any()) + ->method('getRequiredChecks') + ->willReturn([]); + + $runnerManager = $this->createMock(RunnerManager::class); + $runnerManager ->expects($this->once()) - ->method('create') + ->method('getRunner') ->willReturn($runner); - return $runnerFactory; + return $runnerManager; } public function testIfDatabaseFolderExistsExceptionIsThrown() @@ -153,7 +159,7 @@ public function testIfPDOThrowsExceptionItCleansUp() $results = new ResultAggregator; $eventDispatcher = new EventDispatcher($results); $dispatcher = new ExerciseDispatcher( - $this->getRunnerFactory($this->exercise, $eventDispatcher), + $this->getRunnerManager($this->exercise, $eventDispatcher), $results, $eventDispatcher, $this->checkRepository @@ -194,7 +200,7 @@ public function testSuccessIsReturnedIfDatabaseVerificationPassed() $results = new ResultAggregator; $eventDispatcher = new EventDispatcher($results); $dispatcher = new ExerciseDispatcher( - $this->getRunnerFactory($this->exercise, $eventDispatcher), + $this->getRunnerManager($this->exercise, $eventDispatcher), $results, $eventDispatcher, $this->checkRepository @@ -225,7 +231,7 @@ public function testRunExercise() $results = new ResultAggregator; $eventDispatcher = new EventDispatcher($results); $dispatcher = new ExerciseDispatcher( - $this->getRunnerFactory($this->exercise, $eventDispatcher), + $this->getRunnerManager($this->exercise, $eventDispatcher), $results, $eventDispatcher, $this->checkRepository @@ -241,6 +247,8 @@ public function testRunExercise() public function testFailureIsReturnedIfDatabaseVerificationFails() { $solution = SingleFileSolution::fromFile(realpath(__DIR__ . '/../res/database/solution.php')); + + $this->exercise ->expects($this->once()) ->method('getSolution') @@ -269,7 +277,7 @@ public function testFailureIsReturnedIfDatabaseVerificationFails() $results = new ResultAggregator; $eventDispatcher = new EventDispatcher($results); $dispatcher = new ExerciseDispatcher( - $this->getRunnerFactory($this->exercise, $eventDispatcher), + $this->getRunnerManager($this->exercise, $eventDispatcher), $results, $eventDispatcher, $this->checkRepository @@ -337,7 +345,7 @@ public function testAlteringDatabaseInSolutionDoesNotEffectDatabaseInUserSolutio $results = new ResultAggregator; $eventDispatcher = new EventDispatcher($results); $dispatcher = new ExerciseDispatcher( - $this->getRunnerFactory($this->exercise, $eventDispatcher), + $this->getRunnerManager($this->exercise, $eventDispatcher), $results, $eventDispatcher, $this->checkRepository diff --git a/test/Command/PrintCommandTest.php b/test/Command/PrintCommandTest.php index 26a988e5..04074610 100644 --- a/test/Command/PrintCommandTest.php +++ b/test/Command/PrintCommandTest.php @@ -3,6 +3,9 @@ namespace PhpSchool\PhpWorkshop\Command; use Colors\Color; +use PhpSchool\PhpWorkshop\Exercise\ExerciseType; +use PhpSchool\PhpWorkshopTest\Asset\CliExerciseInterface; +use PhpSchool\PhpWorkshopTest\Asset\ComposerExercise; use PHPUnit_Framework_TestCase; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\ExerciseRepository; @@ -22,21 +25,15 @@ public function testExerciseIsPrintedIfAssigned() $file = tempnam(sys_get_temp_dir(), 'pws'); file_put_contents($file, '### Exercise 1'); - $exercise = $this->createMock(ExerciseInterface::class); - $exercise - ->expects($this->once()) - ->method('getProblem') - ->will($this->returnValue($file)); - - $exercise - ->expects($this->once()) - ->method('getName') - ->will($this->returnValue('current-exercise')); + $exercise = $this->prophesize(CliExerciseInterface::class); + $exercise->getProblem()->willReturn($file); + $exercise->getType()->willReturn(ExerciseType::CLI()); + $exercise->getName()->willReturn('some-exercise'); - $repo = new ExerciseRepository([$exercise]); + $repo = new ExerciseRepository([$exercise->reveal()]); $state = new UserState; - $state->setCurrentExercise('current-exercise'); + $state->setCurrentExercise('some-exercise'); $output = $this->createMock(OutputInterface::class); $renderer = $this->createMock(MarkdownRenderer::class); diff --git a/test/Command/VerifyCommandTest.php b/test/Command/VerifyCommandTest.php index 381d7d6d..596b8de7 100644 --- a/test/Command/VerifyCommandTest.php +++ b/test/Command/VerifyCommandTest.php @@ -5,10 +5,13 @@ use Colors\Color; use PhpSchool\CliMenu\Terminal\TerminalInterface; use PhpSchool\PhpWorkshop\Check\CheckInterface; +use PhpSchool\PhpWorkshop\Exercise\ExerciseType; use PhpSchool\PhpWorkshop\ExerciseDispatcher; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\Output\OutputInterface; use PhpSchool\PhpWorkshop\Output\StdOutput; +use PhpSchool\PhpWorkshopTest\Asset\CliExerciseImpl; +use PhpSchool\PhpWorkshopTest\Asset\CliExerciseInterface; use PHPUnit_Framework_TestCase; use PhpSchool\PhpWorkshop\Command\VerifyCommand; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; @@ -69,13 +72,11 @@ public function testVerifyAddsCompletedExerciseAndReturnsCorrectCodeOnSuccess() $input = new Input('appName', ['program' => $file]); - $e = $this->createMock(ExerciseInterface::class); - $e->expects($this->any()) - ->method('getName') - ->will($this->returnValue('exercise1')); - $repo = new ExerciseRepository([$e]); + $exercise = new CliExerciseImpl; + $repo = new ExerciseRepository([$exercise]); + $state = new UserState; - $state->setCurrentExercise('exercise1'); + $state->setCurrentExercise('my-exercise'); $color = new Color; $color->setForceStyle(true); $output = new StdOutput($color, $this->createMock(TerminalInterface::class)); @@ -96,18 +97,18 @@ public function testVerifyAddsCompletedExerciseAndReturnsCorrectCodeOnSuccess() $dispatcher ->expects($this->once()) ->method('verify') - ->with($e, $input) + ->with($exercise, $input) ->will($this->returnValue($results)); $renderer ->expects($this->once()) ->method('render') - ->with($results, $e, $state, $output); + ->with($results, $exercise, $state, $output); $command = new VerifyCommand($repo, $dispatcher, $state, $serializer, $output, $renderer); $this->assertEquals(0, $command->__invoke($input)); - $this->assertEquals(['exercise1'], $state->getCompletedExercises()); + $this->assertEquals(['my-exercise'], $state->getCompletedExercises()); unlink($file); } @@ -118,13 +119,10 @@ public function testVerifyDoesNotAddCompletedExerciseAndReturnsCorrectCodeOnFail $input = new Input('appName', ['program' => $file]); - $e = $this->createMock(ExerciseInterface::class); - $e->expects($this->any()) - ->method('getName') - ->will($this->returnValue('exercise1')); - $repo = new ExerciseRepository([$e]); + $exercise = new CliExerciseImpl; + $repo = new ExerciseRepository([$exercise]); $state = new UserState; - $state->setCurrentExercise('exercise1'); + $state->setCurrentExercise('my-exercise'); $color = new Color; $color->setForceStyle(true); $output = new StdOutput($color, $this->createMock(TerminalInterface::class)); @@ -146,13 +144,13 @@ public function testVerifyDoesNotAddCompletedExerciseAndReturnsCorrectCodeOnFail $dispatcher ->expects($this->once()) ->method('verify') - ->with($e, $input) + ->with($exercise, $input) ->will($this->returnValue($results)); $renderer ->expects($this->once()) ->method('render') - ->with($results, $e, $state, $output); + ->with($results, $exercise, $state, $output); $command = new VerifyCommand($repo, $dispatcher, $state, $serializer, $output, $renderer); $this->assertEquals(1, $command->__invoke($input)); diff --git a/test/Exception/CheckNotApplicableExceptionTest.php b/test/Exception/CheckNotApplicableExceptionTest.php index 0b2b0805..b1f0c050 100644 --- a/test/Exception/CheckNotApplicableExceptionTest.php +++ b/test/Exception/CheckNotApplicableExceptionTest.php @@ -43,8 +43,7 @@ public function testFromCheckAndExerciseConstructor() $e = CheckNotApplicableException::fromCheckAndExercise($check, $exercise); - $msg = 'Check: "Some Check" cannot process exercise: "Some Exercise" with '; - $msg .= 'type: "PhpSchool\PhpWorkshop\ExerciseRunner\CliRunner"'; + $msg = 'Check: "Some Check" cannot process exercise: "Some Exercise" with type: "CLI"'; $this->assertSame($msg, $e->getMessage()); } } diff --git a/test/Exception/InvalidArgumentExceptionTest.php b/test/Exception/InvalidArgumentExceptionTest.php index caaec5cf..ccfc9dc3 100644 --- a/test/Exception/InvalidArgumentExceptionTest.php +++ b/test/Exception/InvalidArgumentExceptionTest.php @@ -2,6 +2,7 @@ namespace PhpSchool\PhpWorkshopTest\Exception; +use Countable; use PhpSchool\PhpWorkshop\Exception\InvalidArgumentException; use PHPUnit_Framework_TestCase; @@ -30,6 +31,12 @@ public function testExceptionFromNotValidParameterConstructor() $this->assertEquals('Parameter: "number" can only be one of: "1", "2" Received: "3"', $e->getMessage()); } + public function testExceptionFromMissingImplements() + { + $e = InvalidArgumentException::missingImplements(new \stdClass, Countable::class); + self::assertEquals('"stdClass" is required to implement "Countable", but it does not', $e->getMessage()); + } + /** * @dataProvider stringifyProvider * @param mixed $value diff --git a/test/ExerciseDispatcherTest.php b/test/ExerciseDispatcherTest.php index aafcd18d..83621364 100644 --- a/test/ExerciseDispatcherTest.php +++ b/test/ExerciseDispatcherTest.php @@ -2,29 +2,27 @@ namespace PhpSchool\PhpWorkshopTest; -use Interop\Container\ContainerInterface; use PhpSchool\PhpWorkshop\Check\CheckInterface; use PhpSchool\PhpWorkshop\Check\CheckRepository; use PhpSchool\PhpWorkshop\Check\ListenableCheckInterface; use PhpSchool\PhpWorkshop\Check\SimpleCheckInterface; -use PhpSchool\PhpWorkshop\Event\Event; use PhpSchool\PhpWorkshop\Event\EventDispatcher; +use PhpSchool\PhpWorkshop\Event\EventInterface; use PhpSchool\PhpWorkshop\Exception\CheckNotApplicableException; use PhpSchool\PhpWorkshop\Exception\ExerciseNotConfiguredException; use PhpSchool\PhpWorkshop\Exception\InvalidArgumentException; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; -use PhpSchool\PhpWorkshop\Exercise\ExerciseType; use PhpSchool\PhpWorkshop\ExerciseDispatcher; use PhpSchool\PhpWorkshop\ExerciseRunner\ExerciseRunnerInterface; -use PhpSchool\PhpWorkshop\Factory\RunnerFactory; +use PhpSchool\PhpWorkshop\ExerciseRunner\RunnerManager; use PhpSchool\PhpWorkshop\Input\Input; use PhpSchool\PhpWorkshop\Output\OutputInterface; use PhpSchool\PhpWorkshop\Result\Failure; use PhpSchool\PhpWorkshop\Result\Success; -use PhpSchool\PhpWorkshop\Result\SuccessInterface; use PhpSchool\PhpWorkshop\ResultAggregator; -use PhpSchool\PhpWorkshop\Solution\SolutionInterface; +use PhpSchool\PhpWorkshopTest\Asset\CliExerciseImpl; use PHPUnit_Framework_TestCase; +use Prophecy\Argument; use RuntimeException; use Symfony\Component\Filesystem\Filesystem; @@ -35,382 +33,305 @@ */ class ExerciseDispatcherTest extends PHPUnit_Framework_TestCase { - - /** - * @var SimpleCheckInterface - */ - private $check; - /** * @var Filesystem */ private $filesystem; - /** - * @var CheckRepository - */ - private $checkRepository; - - /** - * @var ExerciseDispatcher - */ - private $exerciseDispatcher; - - /** - * @var ExerciseRunnerInterface - */ - private $runner; - - /** - * @var RunnerFactory - */ - private $runnerFactory; - /** * @var string */ private $file; - /** - * @var ExerciseInterface - */ - private $exercise; - - /** - * @var ExerciseType - */ - private $exerciseType; - - /** - * @var SolutionInterface - */ - private $solution; - - /** - * @var EventDispatcher - */ - private $eventDispatcher; - - /** - * @var ResultAggregator - */ - private $results; - public function setUp() { $this->filesystem = new Filesystem; - $this->check = $this->createMock(SimpleCheckInterface::class); - $this->check - ->expects($this->any()) - ->method('getName') - ->will($this->returnValue('Some Check')); - - $this->check - ->expects($this->any()) - ->method('getPosition') - ->willReturn(SimpleCheckInterface::CHECK_BEFORE); - - $this->checkRepository = new CheckRepository([$this->check]); - $this->runner = $this->createMock(ExerciseRunnerInterface::class); - $this->runnerFactory = $this->createMock(RunnerFactory::class); - $this->results = new ResultAggregator; - $this->eventDispatcher = $this->createMock(EventDispatcher::class); - - $this->exerciseDispatcher = new ExerciseDispatcher( - $this->runnerFactory, - $this->results, - $this->eventDispatcher, - $this->checkRepository - ); - - $this->assertSame($this->eventDispatcher, $this->exerciseDispatcher->getEventDispatcher()); - $this->file = sprintf('%s/%s/submission.php', str_replace('\\', '/', sys_get_temp_dir()), $this->getName()); - mkdir(dirname($this->file), 0775, true); touch($this->file); } - private function createExercise() - { - $this->exercise = $this->createMock(ExerciseInterface::class); - $this->solution = $this->createMock(SolutionInterface::class); - - $this->exercise - ->expects($this->any()) - ->method('getName') - ->will($this->returnValue('Some Exercise')); - - $this->exerciseType = new ExerciseType(ExerciseType::CLI); - - $this->exercise - ->expects($this->any()) - ->method('getType') - ->will($this->returnValue($this->exerciseType)); - } - - private function mockRunner(ExerciseInterface $exercise = null) - { - $this->runnerFactory - ->expects($this->once()) - ->method('create') - ->with($exercise ? $exercise : $this->exercise, $this->eventDispatcher) - ->will($this->returnValue($this->runner)); - } - public function testRequireCheckThrowsExceptionIfCheckDoesNotExist() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Check: "NotACheck" does not exist'); - $this->exerciseDispatcher->requireCheck('NotACheck'); + + $exerciseDispatcher = new ExerciseDispatcher( + $this->prophesize(RunnerManager::class)->reveal(), + new ResultAggregator, + $this->prophesize(EventDispatcher::class)->reveal(), + new CheckRepository + ); + $exerciseDispatcher->requireCheck('NotACheck'); } public function testRequireCheckThrowsExceptionIfPositionNotValid() { - $check = $this->createMock(SimpleCheckInterface::class); - $check - ->expects($this->any()) - ->method('getName') - ->willReturn('Some Check'); + $checkProphecy = $this->prophesize(SimpleCheckInterface::class); + $checkProphecy->getName()->willReturn('Some Check'); + $checkProphecy->getPosition()->willReturn('middle'); - $check - ->expects($this->any()) - ->method('getPosition') - ->willReturn('middle'); + $check = $checkProphecy->reveal(); + + $exerciseDispatcher = new ExerciseDispatcher( + $this->prophesize(RunnerManager::class)->reveal(), + new ResultAggregator, + $this->prophesize(EventDispatcher::class)->reveal(), + new CheckRepository([$check]) + ); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Parameter: "position" can only be one of: "before", "after" Received: "middle"'); - $this->checkRepository->registerCheck($check); - $this->exerciseDispatcher->requireCheck(get_class($check)); + $exerciseDispatcher->requireCheck(get_class($check)); } - public function testRequireBeforeCheck() + public function testRequireBeforeCheckIsCorrectlyRegistered() { - $this->exerciseDispatcher->requireCheck(get_class($this->check)); - $checksToRunBefore = $this->readAttribute($this->exerciseDispatcher, 'checksToRunBefore'); - $this->assertEquals([$this->check], $checksToRunBefore); + $checkProphecy = $this->prophesize(SimpleCheckInterface::class); + $checkProphecy->getName()->willReturn('Some Check'); + $checkProphecy->getPosition()->willReturn(SimpleCheckInterface::CHECK_BEFORE); + + $check = $checkProphecy->reveal(); + + $exerciseDispatcher = new ExerciseDispatcher( + $this->prophesize(RunnerManager::class)->reveal(), + new ResultAggregator, + $this->prophesize(EventDispatcher::class)->reveal(), + new CheckRepository([$check]) + ); + + $exerciseDispatcher->requireCheck(get_class($check)); + $checksToRunBefore = $this->readAttribute($exerciseDispatcher, 'checksToRunBefore'); + $this->assertEquals([$check], $checksToRunBefore); } - public function testRequireAfterCheck() + public function testRequireAfterCheckIsCorrectlyRegistered() { - $check = $this->createMock(SimpleCheckInterface::class); - $check - ->expects($this->any()) - ->method('getName') - ->willReturn('Some Check'); - - $check - ->expects($this->any()) - ->method('getPosition') - ->willReturn(SimpleCheckInterface::CHECK_AFTER); - - $this->checkRepository->registerCheck($check); - - $this->exerciseDispatcher->requireCheck(get_class($this->check)); - $checksToRunAfter = $this->readAttribute($this->exerciseDispatcher, 'checksToRunAfter'); - $this->assertEquals([$check], $checksToRunAfter); + $checkProphecy = $this->prophesize(SimpleCheckInterface::class); + $checkProphecy->getName()->willReturn('Some Check'); + $checkProphecy->getPosition()->willReturn(SimpleCheckInterface::CHECK_AFTER); + + $check = $checkProphecy->reveal(); + + $exerciseDispatcher = new ExerciseDispatcher( + $this->prophesize(RunnerManager::class)->reveal(), + new ResultAggregator, + $this->prophesize(EventDispatcher::class)->reveal(), + new CheckRepository([$check]) + ); + + $exerciseDispatcher->requireCheck(get_class($check)); + $checksToRunBefore = $this->readAttribute($exerciseDispatcher, 'checksToRunAfter'); + $this->assertEquals([$check], $checksToRunBefore); } public function testRequireCheckThrowsExceptionIfCheckIsNotSimpleOrListenable() { - $check = $this->createMock(CheckInterface::class); - $check - ->expects($this->any()) - ->method('getName') - ->willReturn('Some Check'); + $checkProphecy = $this->prophesize(CheckInterface::class); + $checkProphecy->getName()->willReturn('Some Check'); + + $check = $checkProphecy->reveal(); - $this->checkRepository->registerCheck($check); + $exerciseDispatcher = new ExerciseDispatcher( + $this->prophesize(RunnerManager::class)->reveal(), + new ResultAggregator, + $this->prophesize(EventDispatcher::class)->reveal(), + new CheckRepository([$check]) + ); $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage(sprintf('Check: "%s" is not a listenable check', get_class($check))); - $this->exerciseDispatcher->requireCheck(get_class($check)); + $exerciseDispatcher->requireCheck(get_class($check)); } public function testRequireListenableCheckAttachesToDispatcher() { - $check = $this->createMock(ListenableCheckInterface::class); - $this->checkRepository->registerCheck($check); - - $check - ->expects($this->once()) - ->method('attach') - ->with($this->eventDispatcher); + $eventDispatcher = $this->prophesize(EventDispatcher::class)->reveal(); + $checkProphecy = $this->prophesize(ListenableCheckInterface::class); + $checkProphecy->attach($eventDispatcher)->shouldBeCalled(); + $check = $checkProphecy->reveal(); + + $exerciseDispatcher = new ExerciseDispatcher( + $this->prophesize(RunnerManager::class)->reveal(), + new ResultAggregator, + $eventDispatcher, + new CheckRepository([$check]) + ); - $this->exerciseDispatcher->requireCheck(get_class($check)); + $exerciseDispatcher->requireCheck(get_class($check)); } public function testVerifyThrowsExceptionIfCheckDoesNotSupportExerciseType() { - $this->createExercise(); - $this->exerciseDispatcher->requireCheck(get_class($this->check)); - $this->check - ->expects($this->once()) - ->method('canRun') - ->with($this->exerciseType) - ->will($this->returnValue(false)); - - $msg = 'Check: "Some Check" cannot process exercise: "Some Exercise" with '; - $msg .= 'type: "PhpSchool\PhpWorkshop\ExerciseRunner\CliRunner"'; + $exercise = new CliExerciseImpl('Some Exercise'); + + $checkProphecy = $this->prophesize(SimpleCheckInterface::class); + $checkProphecy->canRun($exercise->getType())->willReturn(false); + $checkProphecy->getPosition()->willReturn(SimpleCheckInterface::CHECK_BEFORE); + $checkProphecy->getName()->willReturn('Some Check'); + + $check = $checkProphecy->reveal(); + + $runner = $this->prophesize(ExerciseRunnerInterface::class); + $runner->getRequiredChecks()->willReturn([]); + $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([$check]) + ); + + $exerciseDispatcher->requireCheck(get_class($check)); + + $msg = 'Check: "Some Check" cannot process exercise: "Some Exercise" with type: "CLI"'; $this->expectException(CheckNotApplicableException::class); $this->expectExceptionMessage($msg); - $this->exerciseDispatcher->verify($this->exercise, new Input('app')); + $exerciseDispatcher->verify($exercise, new Input('app')); } public function testVerifyThrowsExceptionIfExerciseDoesNotImplementCorrectInterface() { - $this->createExercise(); - $this->exerciseDispatcher->requireCheck(get_class($this->check)); - $this->check - ->expects($this->once()) - ->method('canRun') - ->with($this->exerciseType) - ->will($this->returnValue(true)); - - $this->check - ->expects($this->once()) - ->method('getExerciseInterface') - ->will($this->returnValue('LolIDoNotExist')); + $exercise = new CliExerciseImpl('Some Exercise'); + + $checkProphecy = $this->prophesize(SimpleCheckInterface::class); + $checkProphecy->canRun($exercise->getType())->willReturn(true); + $checkProphecy->getPosition()->willReturn(SimpleCheckInterface::CHECK_BEFORE); + $checkProphecy->getExerciseInterface()->willReturn('LolIDoNotExist'); + + $check = $checkProphecy->reveal(); + $runner = $this->prophesize(ExerciseRunnerInterface::class); + $runner->getRequiredChecks()->willReturn([]); + $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([$check]) + ); + + $exerciseDispatcher->requireCheck(get_class($check)); + + $msg = 'Exercise: "Some Exercise" should implement interface: "LolIDoNotExist"'; $this->expectException(ExerciseNotConfiguredException::class); - $this->expectExceptionMessage('Exercise: "Some Exercise" should implement interface: "LolIDoNotExist"'); + $this->expectExceptionMessage($msg); - $this->exerciseDispatcher->verify($this->exercise, new Input('app')); + $exerciseDispatcher->verify($exercise, new Input('app')); } public function testVerify() { - $this->createExercise(); $input = new Input('app', ['program' => $this->file]); - $this->exercise - ->expects($this->once()) - ->method('configure') - ->with($this->exerciseDispatcher); - - $this->check - ->expects($this->once()) - ->method('check') - ->will($this->returnValue(new Success('Success'))); - - $this->check - ->expects($this->once()) - ->method('canRun') - ->with($this->exerciseType) - ->will($this->returnValue(true)); - - $this->check - ->expects($this->once()) - ->method('getExerciseInterface') - ->will($this->returnValue(ExerciseInterface::class)); - - $this->mockRunner(); - $this->runner - ->expects($this->once()) - ->method('verify') - ->with($input) - ->will($this->returnValue($this->createMock(SuccessInterface::class))); - - $this->exerciseDispatcher->requireCheck(get_class($this->check)); - - $result = $this->exerciseDispatcher->verify($this->exercise, $input); + $exercise = new CliExerciseImpl('Some Exercise'); + + $checkProphecy = $this->prophesize(SimpleCheckInterface::class); + $checkProphecy->canRun($exercise->getType())->willReturn(true); + $checkProphecy->getPosition()->willReturn(SimpleCheckInterface::CHECK_BEFORE); + $checkProphecy->getExerciseInterface()->willReturn(ExerciseInterface::class); + $checkProphecy->check($exercise, $input)->willReturn(new Success('Success!')); + + $check = $checkProphecy->reveal(); + + $runner = $this->prophesize(ExerciseRunnerInterface::class); + $runner->getRequiredChecks()->willReturn([]); + $runner->verify($input)->willReturn(new Success('Success!')); + $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([$check]) + ); + + $exerciseDispatcher->requireCheck(get_class($check)); + + $result = $exerciseDispatcher->verify($exercise, $input); $this->assertInstanceOf(ResultAggregator::class, $result); $this->assertTrue($result->isSuccessful()); } public function testVerifyOnlyRunsRequiredChecks() { - $this->createExercise(); $input = new Input('app', ['program' => $this->file]); - $this->check - ->expects($this->exactly(2)) - ->method('check') - ->will($this->returnValue(new Success('Success', 'nope'))); - - $doNotRunMe = $this->getMockBuilder(SimpleCheckInterface::class) - ->setMockClassName('DoNotRunMeCheck') - ->getMock(); - - $doNotRunMe - ->expects($this->never()) - ->method('check'); - - $this->check - ->expects($this->exactly(2)) - ->method('canRun') - ->with($this->exerciseType) - ->will($this->returnValue(true)); - - $this->check - ->expects($this->exactly(2)) - ->method('getExerciseInterface') - ->will($this->returnValue(ExerciseInterface::class)); - - $this->mockRunner(); - $this->runner - ->expects($this->once()) - ->method('verify') - ->with($input) - ->will($this->returnValue($this->createMock(SuccessInterface::class))); - - $this->checkRepository->registerCheck($doNotRunMe); - - $this->exerciseDispatcher->requireCheck(get_class($this->check)); - $this->exerciseDispatcher->requireCheck(get_class($this->check)); - - $result = $this->exerciseDispatcher->verify($this->exercise, $input); + $exercise = new CliExerciseImpl('Some Exercise'); + + $checkProphecy1 = $this->prophesize(SimpleCheckInterface::class); + $checkProphecy1->canRun($exercise->getType())->willReturn(true); + $checkProphecy1->getPosition()->willReturn(SimpleCheckInterface::CHECK_BEFORE); + $checkProphecy1->getExerciseInterface()->willReturn(ExerciseInterface::class); + $checkProphecy1->check($exercise, $input)->willReturn(new Success('Success!')); + + $checkProphecy2 = $this->prophesize(SimpleCheckInterface::class); + $checkProphecy2->check($exercise, $input)->shouldNotBeCalled(); + + $check1 = $checkProphecy1->reveal(); + $check2 = $checkProphecy2->reveal(); + + $runner = $this->prophesize(ExerciseRunnerInterface::class); + $runner->getRequiredChecks()->willReturn([]); + $runner->verify($input)->willReturn(new Success('Success!')); + $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([$check1, $check2]) + ); + + $exerciseDispatcher->requireCheck(get_class($check1)); + + $result = $exerciseDispatcher->verify($exercise, $input); $this->assertInstanceOf(ResultAggregator::class, $result); $this->assertTrue($result->isSuccessful()); } public function testWhenBeforeChecksFailTheyReturnImmediately() { - $this->createExercise(); $input = new Input('app', ['program' => $this->file]); - $this->check - ->expects($this->once()) - ->method('check') - ->will($this->returnValue(new Failure('Failure', 'nope'))); - - $doNotRunMe = $this->getMockBuilder(SimpleCheckInterface::class) - ->setMockClassName('DoNotRunMeCheck') - ->getMock(); - - $doNotRunMe - ->expects($this->once()) - ->method('getPosition') - ->willReturn(SimpleCheckInterface::CHECK_BEFORE); - $doNotRunMe - ->expects($this->never()) - ->method('check'); - - $this->check - ->expects($this->once()) - ->method('canRun') - ->with($this->exerciseType) - ->will($this->returnValue(true)); - - $this->check - ->expects($this->once()) - ->method('getExerciseInterface') - ->will($this->returnValue(ExerciseInterface::class)); - - $doNotRunMe - ->expects($this->once()) - ->method('canRun') - ->with($this->exerciseType) - ->will($this->returnValue(true)); - - $doNotRunMe - ->expects($this->once()) - ->method('getExerciseInterface') - ->will($this->returnValue(ExerciseInterface::class)); - - $this->checkRepository->registerCheck($doNotRunMe); - - $this->exerciseDispatcher->requireCheck(get_class($this->check)); - $this->exerciseDispatcher->requireCheck(get_class($doNotRunMe)); - - $result = $this->exerciseDispatcher->verify($this->exercise, $input); + $exercise = new CliExerciseImpl('Some Exercise'); + + $checkProphecy1 = $this->prophesize(SimpleCheckInterface::class); + $checkProphecy1->canRun($exercise->getType())->willReturn(true); + $checkProphecy1->getPosition()->willReturn(SimpleCheckInterface::CHECK_BEFORE); + $checkProphecy1->getExerciseInterface()->willReturn(ExerciseInterface::class); + $checkProphecy1->check($exercise, $input)->willReturn(new Failure('Failure', 'nope')); + + $checkProphecy2 = $this->prophesize(SimpleCheckInterface::class); + $checkProphecy2->canRun($exercise->getType())->willReturn(true); + $checkProphecy2->getPosition()->willReturn(SimpleCheckInterface::CHECK_BEFORE); + $checkProphecy2->getExerciseInterface()->willReturn(ExerciseInterface::class); + $checkProphecy2->check($exercise, $input)->shouldNotBeCalled(); + + $check1 = $checkProphecy1->reveal(); + $check2 = $checkProphecy2->reveal(); + + $runner = $this->prophesize(ExerciseRunnerInterface::class); + $runner->getRequiredChecks()->willReturn([]); + $runner->verify($input)->shouldNotBeCalled(); + $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([$check1, $check2]) + ); + + $exerciseDispatcher->requireCheck(get_class($check1)); + $exerciseDispatcher->requireCheck(get_class($check2)); + + $result = $exerciseDispatcher->verify($exercise, $input); $this->assertInstanceOf(ResultAggregator::class, $result); $this->assertFalse($result->isSuccessful()); } @@ -418,66 +339,115 @@ public function testWhenBeforeChecksFailTheyReturnImmediately() public function testAllEventsAreDispatched() { $input = new Input('app', ['program' => $this->file]); - $this->eventDispatcher - ->expects($this->exactly(5)) - ->method('dispatch') - ->withConsecutive( - [$this->isInstanceOf(Event::class)], - [$this->isInstanceOf(Event::class)], - [$this->isInstanceOf(Event::class)], - [$this->isInstanceOf(Event::class)], - [$this->isInstanceOf(Event::class)] - ); - - $this->createExercise(); - $this->mockRunner(); - $this->runner - ->expects($this->once()) - ->method('verify') - ->with($input) - ->will($this->returnValue(new Success('test'))); - - $this->exerciseDispatcher->verify($this->exercise, $input); + $exercise = new CliExerciseImpl('Some Exercise'); + + $eventDispatcher = $this->prophesize(EventDispatcher::class); + + $eventDispatcher + ->dispatch(Argument::that(function ($event) { + return $event instanceof EventInterface && $event->getName() === 'verify.start'; + })) + ->shouldBeCalled(); + $eventDispatcher + ->dispatch(Argument::that(function ($event) { + return $event instanceof EventInterface && $event->getName() === 'verify.pre.execute'; + })) + ->shouldBeCalled(); + $eventDispatcher + ->dispatch(Argument::that(function ($event) { + return $event instanceof EventInterface && $event->getName() === 'verify.post.execute'; + })) + ->shouldBeCalled(); + $eventDispatcher + ->dispatch(Argument::that(function ($event) { + return $event instanceof EventInterface && $event->getName() === 'verify.post.check'; + })) + ->shouldBeCalled(); + $eventDispatcher + ->dispatch(Argument::that(function ($event) { + return $event instanceof EventInterface && $event->getName() === 'verify.finish'; + })) + ->shouldBeCalled(); + + + $runner = $this->prophesize(ExerciseRunnerInterface::class); + $runner->getRequiredChecks()->willReturn([]); + $runner->verify($input)->willReturn(new Success('Success!')); + $runnerManager = $this->prophesize(RunnerManager::class); + $runnerManager->getRunner($exercise)->willReturn($runner->reveal()); + + $exerciseDispatcher = new ExerciseDispatcher( + $runnerManager->reveal(), + new ResultAggregator, + $eventDispatcher->reveal(), + new CheckRepository() + ); + + $exerciseDispatcher->verify($exercise, $input); } public function testVerifyPostExecuteIsStillDispatchedEvenIfRunnerThrowsException() { $input = new Input('app', ['program' => $this->file]); - $this->eventDispatcher - ->expects($this->exactly(3)) - ->method('dispatch') - ->withConsecutive( - [$this->isInstanceOf(Event::class)], - [$this->isInstanceOf(Event::class)], - [$this->isInstanceOf(Event::class)] - ); - - $this->createExercise(); - $this->mockRunner(); - $this->runner - ->expects($this->once()) - ->method('verify') - ->with($input) - ->will($this->throwException(new RuntimeException)); + $exercise = new CliExerciseImpl('Some Exercise'); + + $eventDispatcher = $this->prophesize(EventDispatcher::class); + + $eventDispatcher + ->dispatch(Argument::that(function ($event) { + return $event instanceof EventInterface && $event->getName() === 'verify.start'; + })) + ->shouldBeCalled(); + $eventDispatcher + ->dispatch(Argument::that(function ($event) { + return $event instanceof EventInterface && $event->getName() === 'verify.pre.execute'; + })) + ->shouldBeCalled(); + $eventDispatcher + ->dispatch(Argument::that(function ($event) { + return $event instanceof EventInterface && $event->getName() === 'verify.post.execute'; + })) + ->shouldBeCalled(); + + $runner = $this->prophesize(ExerciseRunnerInterface::class); + $runner->getRequiredChecks()->willReturn([]); + $runner->verify($input)->willThrow(new RuntimeException); + $runnerManager = $this->prophesize(RunnerManager::class); + $runnerManager->getRunner($exercise)->willReturn($runner->reveal()); + + $exerciseDispatcher = new ExerciseDispatcher( + $runnerManager->reveal(), + new ResultAggregator, + $eventDispatcher->reveal(), + new CheckRepository() + ); $this->expectException(RuntimeException::class); - $this->exerciseDispatcher->verify($this->exercise, $input); + $exerciseDispatcher->verify($exercise, $input); } public function testRun() { - $input = new Input('app', ['program' => $this->file]); - $exercise = $this->createMock(ExerciseInterface::class); - $output = $this->createMock(OutputInterface::class); - - $this->mockRunner($exercise); - $this->runner - ->expects($this->once()) - ->method('run') - ->with($input, $output) - ->will($this->returnValue(true)); - - $this->assertTrue($this->exerciseDispatcher->run($exercise, $input, $output)); + $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)); } public function tearDown() diff --git a/test/ExerciseRepositoryTest.php b/test/ExerciseRepositoryTest.php index bc32f934..e1d8073f 100644 --- a/test/ExerciseRepositoryTest.php +++ b/test/ExerciseRepositoryTest.php @@ -2,7 +2,11 @@ namespace PhpSchool\PhpWorkshopTest; -use InvalidArgumentException; +use PhpSchool\PhpWorkshop\Exception\InvalidArgumentException; +use PhpSchool\PhpWorkshop\Exercise\ExerciseType; +use PhpSchool\PhpWorkshopTest\Asset\CliExerciseImpl; +use PhpSchool\PhpWorkshopTest\Asset\CliExerciseInterface; +use PhpSchool\PhpWorkshopTest\Asset\CliExerciseMissingInterface; use PHPUnit_Framework_TestCase; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\ExerciseRepository; @@ -17,8 +21,8 @@ class ExerciseRepositoryTest extends PHPUnit_Framework_TestCase public function testFindAll() { $exercises = [ - $this->createMock(ExerciseInterface::class), - $this->createMock(ExerciseInterface::class), + new CliExerciseImpl('Exercise 1'), + new CliExerciseImpl('Exercise 2'), ]; $repo = new ExerciseRepository($exercises); @@ -28,21 +32,13 @@ public function testFindAll() public function testFindByName() { - $exercise1 = $this->createMock(ExerciseInterface::class); - $exercise2 = $this->createMock(ExerciseInterface::class); - - $exercise1 - ->expects($this->any()) - ->method('getName') - ->will($this->returnValue('exercise1')); - - $exercise2 - ->expects($this->any()) - ->method('getName') - ->will($this->returnValue('exercise2')); + $exercises = [ + new CliExerciseImpl('Exercise 1'), + new CliExerciseImpl('Exercise 2'), + ]; - $repo = new ExerciseRepository([$exercise1, $exercise2]); - $this->assertSame($exercise2, $repo->findByName('exercise2')); + $repo = new ExerciseRepository($exercises); + $this->assertSame($exercises[1], $repo->findByName('Exercise 2')); } public function testFindByNameThrowsExceptionIfNotFound() @@ -56,28 +52,20 @@ public function testFindByNameThrowsExceptionIfNotFound() public function testGetAllNames() { - $exercise1 = $this->createMock(ExerciseInterface::class); - $exercise2 = $this->createMock(ExerciseInterface::class); - - $exercise1 - ->expects($this->any()) - ->method('getName') - ->will($this->returnValue('exercise1')); - - $exercise2 - ->expects($this->any()) - ->method('getName') - ->will($this->returnValue('exercise2')); + $exercises = [ + new CliExerciseImpl('Exercise 1'), + new CliExerciseImpl('Exercise 2'), + ]; - $repo = new ExerciseRepository([$exercise1, $exercise2]); - $this->assertSame(['exercise1', 'exercise2'], $repo->getAllNames()); + $repo = new ExerciseRepository($exercises); + $this->assertSame(['Exercise 1', 'Exercise 2'], $repo->getAllNames()); } public function testCount() { $exercises = [ - $this->createMock(ExerciseInterface::class), - $this->createMock(ExerciseInterface::class), + new CliExerciseImpl('Exercise 1'), + new CliExerciseImpl('Exercise 2'), ]; $repo = new ExerciseRepository($exercises); @@ -87,11 +75,22 @@ public function testCount() public function testIterator() { $exercises = [ - $this->createMock(ExerciseInterface::class), - $this->createMock(ExerciseInterface::class), + new CliExerciseImpl('Exercise 1'), + new CliExerciseImpl('Exercise 2'), ]; $repo = new ExerciseRepository($exercises); $this->assertEquals($exercises, iterator_to_array($repo)); } + + public function testExceptionIsThrownWhenTryingToAddExerciseWhichDoesNotImplementCorrectInterface() + { + $this->expectException(InvalidArgumentException::class); + $message = '"PhpSchool\PhpWorkshopTest\Asset\CliExerciseMissingInterface" is required to implement '; + $message .= '"PhpSchool\PhpWorkshop\Exercise\CliExercise", but it does not'; + $this->expectExceptionMessage($message); + + $exercise = new CliExerciseMissingInterface; + new ExerciseRepository([$exercise]); + } } diff --git a/test/ExerciseRunner/CgiRunnerTest.php b/test/ExerciseRunner/CgiRunnerTest.php index 6f8d8b40..882fafbf 100644 --- a/test/ExerciseRunner/CgiRunnerTest.php +++ b/test/ExerciseRunner/CgiRunnerTest.php @@ -1,12 +1,16 @@ */ @@ -47,6 +50,17 @@ public function setUp() $this->assertEquals('CGI Program Runner', $this->runner->getName()); } + public function testRequiredChecks() + { + $requiredChecks = [ + FileExistsCheck::class, + PhpLintCheck::class, + CodeParseCheck::class, + ]; + + $this->assertEquals($requiredChecks, $this->runner->getRequiredChecks()); + } + public function testVerifyThrowsExceptionIfSolutionFailsExecution() { $solution = SingleFileSolution::fromFile(__DIR__ . '/../res/cgi/solution-error.php'); diff --git a/test/ExerciseRunner/CliRunnerTest.php b/test/ExerciseRunner/CliRunnerTest.php index 02b01c69..289c45da 100644 --- a/test/ExerciseRunner/CliRunnerTest.php +++ b/test/ExerciseRunner/CliRunnerTest.php @@ -1,13 +1,17 @@ */ @@ -46,6 +49,17 @@ public function setUp() $this->assertEquals('CLI Program Runner', $this->runner->getName()); } + public function testRequiredChecks() + { + $requiredChecks = [ + FileExistsCheck::class, + PhpLintCheck::class, + CodeParseCheck::class, + ]; + + $this->assertEquals($requiredChecks, $this->runner->getRequiredChecks()); + } + public function testVerifyThrowsExceptionIfSolutionFailsExecution() { $solution = SingleFileSolution::fromFile(realpath(__DIR__ . '/../res/cli/solution-error.php')); diff --git a/test/ExerciseRunner/Factory/CgiRunnerFactoryTest.php b/test/ExerciseRunner/Factory/CgiRunnerFactoryTest.php new file mode 100644 index 00000000..69b59c3b --- /dev/null +++ b/test/ExerciseRunner/Factory/CgiRunnerFactoryTest.php @@ -0,0 +1,63 @@ + + */ +class CgiRunnerFactoryTest extends PHPUnit_Framework_TestCase +{ + /** + * @var EventDispatcher + */ + private $eventDispatcher; + + /** + * @var CgiRunnerFactory + */ + private $factory; + + public function setUp() + { + $this->eventDispatcher = $this->createMock(EventDispatcher::class); + $this->factory = new CgiRunnerFactory($this->eventDispatcher); + } + + public function testSupports() + { + $exercise1 = $this->prophesize(ExerciseInterface::class); + $exercise2 = $this->prophesize(ExerciseInterface::class); + + $exercise1->getType()->willReturn(ExerciseType::CGI()); + $exercise2->getType()->willReturn(ExerciseType::CLI()); + + $this->assertTrue($this->factory->supports($exercise1->reveal())); + $this->assertFalse($this->factory->supports($exercise2->reveal())); + } + + public function testConfigureInputAddsProgramArgument() + { + $command = new CommandDefinition('my-command', [], 'var_dump'); + + $this->factory->configureInput($command); + + $this->assertCount(1, $command->getRequiredArgs()); + $this->assertSame('program', $command->getRequiredArgs()[0]->getName()); + $this->assertTrue($command->getRequiredArgs()[0]->isRequired()); + } + + public function testCreateReturnsRunner() + { + $exercise = new CgiExerciseImpl; + $this->assertInstanceOf(CgiRunner::class, $this->factory->create($exercise)); + } +} diff --git a/test/ExerciseRunner/Factory/CliRunnerFactoryTest.php b/test/ExerciseRunner/Factory/CliRunnerFactoryTest.php new file mode 100644 index 00000000..f6469cc6 --- /dev/null +++ b/test/ExerciseRunner/Factory/CliRunnerFactoryTest.php @@ -0,0 +1,65 @@ + + */ +class CliRunnerFactoryTest extends PHPUnit_Framework_TestCase +{ + /** + * @var EventDispatcher + */ + private $eventDispatcher; + + /** + * @var CliRunnerFactory + */ + private $factory; + + public function setUp() + { + $this->eventDispatcher = $this->createMock(EventDispatcher::class); + $this->factory = new CliRunnerFactory($this->eventDispatcher); + } + + public function testSupports() + { + $exercise1 = $this->prophesize(ExerciseInterface::class); + $exercise2 = $this->prophesize(ExerciseInterface::class); + + $exercise1->getType()->willReturn(ExerciseType::CLI()); + $exercise2->getType()->willReturn(ExerciseType::CGI()); + + $this->assertTrue($this->factory->supports($exercise1->reveal())); + $this->assertFalse($this->factory->supports($exercise2->reveal())); + } + + public function testConfigureInputAddsProgramArgument() + { + $command = new CommandDefinition('my-command', [], 'var_dump'); + + $this->factory->configureInput($command); + + $this->assertCount(1, $command->getRequiredArgs()); + $this->assertSame('program', $command->getRequiredArgs()[0]->getName()); + $this->assertTrue($command->getRequiredArgs()[0]->isRequired()); + } + + public function testCreateReturnsRunner() + { + $exercise = new CliExerciseImpl; + $this->assertInstanceOf(CliRunner::class, $this->factory->create($exercise)); + } +} diff --git a/test/ExerciseRunner/RunnerManagerTest.php b/test/ExerciseRunner/RunnerManagerTest.php new file mode 100644 index 00000000..cccb1034 --- /dev/null +++ b/test/ExerciseRunner/RunnerManagerTest.php @@ -0,0 +1,75 @@ + + */ +class RunnerManagerTest extends PHPUnit_Framework_TestCase +{ + public function testConfigureInputCallsCorrectFactory() + { + $exercise = new CliExerciseImpl; + $manager = new RunnerManager; + $command = new CommandDefinition('my-command', [], 'var_dump'); + + $factory1 = $this->prophesize(ExerciseRunnerFactoryInterface::class); + $factory1->supports($exercise)->willReturn(false); + $factory1->configureInput($command)->shouldNotBeCalled(); + + $factory2 = $this->prophesize(ExerciseRunnerFactoryInterface::class); + $factory2->supports($exercise)->willReturn(true); + $factory2->configureInput($command)->shouldBeCalled(); + + $manager->addFactory($factory1->reveal()); + $manager->addFactory($factory2->reveal()); + $manager->configureInput($exercise, $command); + } + + public function testGetRunnerCallsCorrectFactory() + { + $exercise = new CliExerciseImpl; + $manager = new RunnerManager; + + $factory1 = $this->prophesize(ExerciseRunnerFactoryInterface::class); + $factory1->supports($exercise)->willReturn(false); + $factory1->create($exercise)->shouldNotBeCalled(); + + $factory2 = $this->prophesize(ExerciseRunnerFactoryInterface::class); + $factory2->supports($exercise)->willReturn(true); + $factory2->create($exercise)->shouldBeCalled(); + + $manager->addFactory($factory1->reveal()); + $manager->addFactory($factory2->reveal()); + $manager->getRunner($exercise); + } + + public function testExceptionIsThrownWhenConfiguringInputIfNoFactorySupportsExercise() + { + $exercise = new CliExerciseImpl; + $manager = new RunnerManager; + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Exercise Type: "CLI" not supported'); + + $manager->configureInput($exercise, new CommandDefinition('my-command', [], 'var_dump')); + } + + public function testExceptionIsThrownWhenGettingRunnerIfNoFactorySupportsExercise() + { + $exercise = new CliExerciseImpl; + $manager = new RunnerManager; + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Exercise Type: "CLI" not supported'); + + $manager->getRunner($exercise); + } +} diff --git a/test/Factory/RunnerFactoryTest.php b/test/Factory/RunnerFactoryTest.php deleted file mode 100644 index 1ccace23..00000000 --- a/test/Factory/RunnerFactoryTest.php +++ /dev/null @@ -1,80 +0,0 @@ - - */ -class RunnerFactoryTest extends PHPUnit_Framework_TestCase -{ - public function testExceptionIsThrownIfTypeNotSupported() - { - $type = $this->createMock(ExerciseType::class); - $type - ->expects($this->exactly(2)) - ->method('getValue') - ->will($this->returnValue('invalid')); - - $exercise = $this->createMock(ExerciseInterface::class); - $exercise - ->expects($this->exactly(2)) - ->method('getType') - ->will($this->returnValue($type)); - - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Exercise Type: "invalid" not supported'); - - (new RunnerFactory) - ->create( - $exercise, - new EventDispatcher(new ResultAggregator), - $this->createMock(ExerciseDispatcher::class) - ); - } - - public function testCliAndCgiRunnerCanBeCreated() - { - $cliType = new ExerciseType(ExerciseType::CLI); - $cgiType = new ExerciseType(ExerciseType::CGI); - - $cliExercise = $this->createMock(CliExerciseInterface::class); - $cliExercise - ->expects($this->once()) - ->method('getType') - ->will($this->returnValue($cliType)); - - $cgiExercise = $this->createMock(CgiExerciseInterface::class); - $cgiExercise - ->expects($this->once()) - ->method('getType') - ->will($this->returnValue($cgiType)); - - - $runnerFactory = new RunnerFactory; - $eventDispatcher = new EventDispatcher(new ResultAggregator); - $this->assertInstanceOf( - CliRunner::class, - $runnerFactory->create($cliExercise, $eventDispatcher, $this->createMock(ExerciseDispatcher::class)) - ); - $this->assertInstanceOf( - CgiRunner::class, - $runnerFactory->create($cgiExercise, $eventDispatcher, $this->createMock(ExerciseDispatcher::class)) - ); - } -} diff --git a/test/Listener/ConfigureCommandListenerTest.php b/test/Listener/ConfigureCommandListenerTest.php new file mode 100644 index 00000000..418af96d --- /dev/null +++ b/test/Listener/ConfigureCommandListenerTest.php @@ -0,0 +1,83 @@ + + */ +class ConfigureCommandListenerTest extends PHPUnit_Framework_TestCase +{ + /** + * @dataProvider configurableCommands + * @param string $commandName + */ + public function testInputIsConfiguredForCorrectCommands($commandName) + { + $command = new CommandDefinition($commandName, [], function () { + }); + + $state = new UserState([], 'Exercise 1'); + $exercise = new CliExerciseImpl('Exercise 1'); + $repo = new ExerciseRepository([$exercise]); + + $runnerManager = $this->prophesize(RunnerManager::class); + $runnerManager->configureInput($exercise, $command)->shouldBeCalled(); + + $event = new Event('some-event', ['command' => $command]); + (new ConfigureCommandListener($state, $repo, $runnerManager->reveal()))->__invoke($event); + } + + /** + * @return array + */ + public function configurableCommands() + { + return [ + ['verify'], + ['run'], + ]; + } + + /** + * @dataProvider nonConfigurableCommands + * @param string $commandName + */ + public function testInputIsNotConfiguredForCorrectCommands($commandName) + { + $command = new CommandDefinition($commandName, [], function () { + }); + + $state = new UserState([], 'Exercise 1'); + $exercise = new CliExerciseImpl('Exercise 1'); + $repo = new ExerciseRepository([$exercise]); + + $runnerManager = $this->prophesize(RunnerManager::class); + + $event = new Event('some-event', ['command' => $command]); + (new ConfigureCommandListener($state, $repo, $runnerManager->reveal()))->__invoke($event); + + $runnerManager->configureInput($exercise, $command)->shouldNotHaveBeenCalled(); + } + + /** + * @return array + */ + public function nonConfigurableCommands() + { + return [ + ['print'], + ['help'], + ['credits'], + ['menu'], + ]; + } +} diff --git a/test/UserStateSerializerTest.php b/test/UserStateSerializerTest.php index 0d907f67..70afc683 100644 --- a/test/UserStateSerializerTest.php +++ b/test/UserStateSerializerTest.php @@ -3,9 +3,11 @@ namespace PhpSchool\PhpWorkshopTest; use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; +use PhpSchool\PhpWorkshop\Exercise\ExerciseType; use PhpSchool\PhpWorkshop\ExerciseRepository; use PhpSchool\PhpWorkshop\UserState; use PhpSchool\PhpWorkshop\UserStateSerializer; +use PhpSchool\PhpWorkshopTest\Asset\CliExerciseInterface; /** * Class UserStateSerializerTest @@ -191,13 +193,19 @@ public function testOldDataWillBeMigratedWhenInCorrectWorkshop() $oldSave = sprintf('%s/.phpschool.json', $this->tmpDir); $newSave = sprintf('%s/.phpschool-save.json', $this->tmpDir); - $e1 = $this->createMock(ExerciseInterface::class); - $e2 = $this->createMock(ExerciseInterface::class); + $exercise1 = $this->prophesize(CliExerciseInterface::class); + $exercise2 = $this->prophesize(CliExerciseInterface::class); + $exercise1->getType()->willReturn(ExerciseType::CLI()); + $exercise2->getType()->willReturn(ExerciseType::CLI()); + $exercise1->getName()->willReturn('Exercise 1'); + $exercise2->getName()->willReturn('Exercise 2'); - $e1->expects($this->once())->method('getName')->willReturn('Exercise 1'); - $e2->expects($this->once())->method('getName')->willReturn('Exercise 2'); + $exercises = [ + $exercise1->reveal(), + $exercise2->reveal() + ]; - $repo = new ExerciseRepository([$e1, $e2]); + $repo = new ExerciseRepository($exercises); $oldData = [ 'current_exercise' => 'Exercise 3', @@ -230,14 +238,19 @@ public function testOldDataWillNotBeMigratedWhenNotInCorrectWorkshop() $oldSave = sprintf('%s/.phpschool.json', $this->tmpDir); $newSave = sprintf('%s/.phpschool-save.json', $this->tmpDir); - $e1 = $this->createMock(ExerciseInterface::class); - $e2 = $this->createMock(ExerciseInterface::class); - - $e1->expects($this->once())->method('getName')->willReturn('Exercise 1'); - $e2->expects($this->once())->method('getName')->willReturn('Exercise 2'); + $exercise1 = $this->prophesize(CliExerciseInterface::class); + $exercise2 = $this->prophesize(CliExerciseInterface::class); + $exercise1->getType()->willReturn(ExerciseType::CLI()); + $exercise2->getType()->willReturn(ExerciseType::CLI()); + $exercise1->getName()->willReturn('Exercise 1'); + $exercise2->getName()->willReturn('Exercise 2'); - $repo = new ExerciseRepository([$e1, $e2]); + $exercises = [ + $exercise1->reveal(), + $exercise2->reveal() + ]; + $repo = new ExerciseRepository($exercises); $oldData = [ 'current_exercise' => 'Exercise 3', 'completed_exercises' => ['Exercise 1 from a diff workshop', 'Exercise 2 from a diff workshop'], @@ -264,13 +277,19 @@ public function testOldDataWillNotBeMigratedWhenNotInCorrectWorkshopWithOtherWor $oldSave = sprintf('%s/.phpschool.json', $this->tmpDir); $newSave = sprintf('%s/.phpschool-save.json', $this->tmpDir); - $e1 = $this->createMock(ExerciseInterface::class); - $e2 = $this->createMock(ExerciseInterface::class); + $exercise1 = $this->prophesize(CliExerciseInterface::class); + $exercise2 = $this->prophesize(CliExerciseInterface::class); + $exercise1->getType()->willReturn(ExerciseType::CLI()); + $exercise2->getType()->willReturn(ExerciseType::CLI()); + $exercise1->getName()->willReturn('Exercise 1'); + $exercise2->getName()->willReturn('Exercise 2'); - $e1->expects($this->once())->method('getName')->willReturn('Exercise 1'); - $e2->expects($this->once())->method('getName')->willReturn('Exercise 2'); + $exercises = [ + $exercise1->reveal(), + $exercise2->reveal() + ]; - $repo = new ExerciseRepository([$e1, $e2]); + $repo = new ExerciseRepository($exercises); $oldData = [ 'current_exercise' => 'Exercise 3',