diff --git a/.gitignore b/.gitignore index 374b9f4..cc9af80 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,6 @@ /vendor/ /tests/_data/node_modules/ -/tests/_data/reports/ +/tests/_data/actual/ /tests/_output/ /tests/_support/_generated/ diff --git a/.travis.yml b/.travis.yml index 654a38c..169c5ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ php: - '7.0' env: - - COMPOSER_NO_INTERACTION=1 COMPOSER_DISABLE_XDEBUG_WARN=1 + - 'COMPOSER_NO_INTERACTION=1 COMPOSER_DISABLE_XDEBUG_WARN=1' cache: directories: diff --git a/RoboFile.php b/RoboFile.php index 89ce63b..a219191 100644 --- a/RoboFile.php +++ b/RoboFile.php @@ -2,6 +2,7 @@ // @codingStandardsIgnoreStart use Symfony\Component\Process\Process; +use Symfony\Component\Yaml\Yaml; /** * Class RoboFile. @@ -16,6 +17,11 @@ class RoboFile extends \Robo\Tasks */ protected $composerInfo = []; + /** + * @var array + */ + protected $codeceptionInfo = []; + /** * @var string */ @@ -71,7 +77,12 @@ public function githookPreCommit() */ public function test() { - return $this->getTaskCodecept(); + /** @var \Robo\Collection\CollectionBuilder $cb */ + $cb = $this->collectionBuilder(); + + return $cb->addTaskList([ + 'codecept' => $this->getTaskCodecept(), + ]); } /** @@ -83,11 +94,12 @@ public function lint() { /** @var \Robo\Collection\CollectionBuilder $cb */ $cb = $this->collectionBuilder(); - - return $cb->addTaskList([ + $cb->addTaskList([ 'lint.composer.lock' => $this->taskComposerValidate(), 'lint.phpcs.psr2' => $this->getTaskPhpcsLint(), ]); + + return $cb; } /** @@ -109,6 +121,28 @@ protected function initComposerInfo() return $this; } + /** + * @return $this + */ + protected function initCodeceptionInfo() + { + if ($this->codeceptionInfo) { + return $this; + } + + if (is_readable('codeception.yml')) { + $this->codeceptionInfo = Yaml::parse(file_get_contents('codeception.yml')); + } else { + $this->codeceptionInfo = [ + 'paths' => [ + 'log' => 'tests/_output', + ], + ]; + } + + return $this; + } + /** * @return \Cheppers\Robo\Phpcs\Task\TaskPhpcsLint */ @@ -119,7 +153,6 @@ protected function getTaskPhpcsLint() 'standard' => 'PSR2', 'reports' => [ 'full' => null, - 'checkstyle' => 'tests/_output/checkstyle/phpcs-psr2.xml', ], 'files' => [ 'src/', @@ -133,10 +166,12 @@ protected function getTaskPhpcsLint() } /** - * @return \Robo\Task\Base\Exec + * @return \Robo\Collection\CollectionBuilder */ protected function getTaskCodecept() { + $this->initCodeceptionInfo(); + $cmd_args = []; if ($this->isPhpExtensionAvailable('xdebug')) { $cmd_pattern = '%s'; @@ -147,13 +182,30 @@ protected function getTaskCodecept() $cmd_args[] = escapeshellarg("{$this->binDir}/codecept"); } - $cmd_pattern .= ' --ansi --verbose --coverage --coverage-xml=%s --coverage-html=%s run'; - $cmd_args[] = escapeshellarg('coverage.xml'); - $cmd_args[] = escapeshellarg('html'); + $cmd_pattern .= ' --ansi'; + $cmd_pattern .= ' --verbose'; + + $cmd_pattern .= ' --coverage=%s'; + $cmd_args[] = escapeshellarg('coverage/coverage.serialized'); + + $cmd_pattern .= ' --coverage-xml=%s'; + $cmd_args[] = escapeshellarg('coverage/coverage.xml'); + + $cmd_pattern .= ' --coverage-html=%s'; + $cmd_args[] = escapeshellarg('coverage/html'); + + $cmd_pattern .= ' run'; + + $reportsDir = $this->codeceptionInfo['paths']['log']; + + /** @var \Robo\Collection\CollectionBuilder $cb */ + $cb = $this->collectionBuilder(); + $cb->addTaskList([ + 'prepareCoverageDir' => $this->taskFilesystemStack()->mkdir("$reportsDir/coverage"), + 'runCodeception' => $this->taskExec(vsprintf($cmd_pattern, $cmd_args)), + ]); - return $this - ->taskExec(vsprintf($cmd_pattern, $cmd_args)) - ->printed(false); + return $cb; } /** diff --git a/composer.json b/composer.json index 8c7107a..7570426 100644 --- a/composer.json +++ b/composer.json @@ -10,13 +10,16 @@ "prefer-stable": true, "require": { "cheppers/asset-jar": "^0.0", - "consolidation/robo": "1.0.0-RC2" + "consolidation/robo": "1.0.0-RC2", + "samsonasik/package-versions": "^1.1" }, "require-dev": { "cheppers/git-hooks": "^0.0.8", - "cheppers/robo-phpcs": "^0.0.4", + "cheppers/lint-report": "^0.0.4", + "cheppers/robo-phpcs": "^0.0.7", "codeception/codeception": "^2.2", - "symfony/process": "^2.8|^3.1" + "symfony/process": "^2.8 || ^3.1", + "symfony/yaml": "^2.8 || ^3.1" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index b38df3e..eb7ebcc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "f3bede9cae0b2f6eb8930ff55257d091", - "content-hash": "9918e697a3bbc75a52d4702f8a3a6e41", + "hash": "a6f3bafeed32e4451fce48f3fbc77d20", + "content-hash": "e7ac6f86384143adbcf383ae5393721f", "packages": [ { "name": "cheppers/asset-jar", @@ -41,16 +41,16 @@ }, { "name": "consolidation/annotated-command", - "version": "1.2.2", + "version": "1.4.1", "source": { "type": "git", - "url": "https://github.com/consolidation-org/annotated-command.git", - "reference": "6d6bacf27893d265d6b71e7c2fa2da661ce891c4" + "url": "https://github.com/consolidation/annotated-command.git", + "reference": "c2dc2464e1edf0498bf97a99f34cac5805d00946" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/consolidation-org/annotated-command/zipball/6d6bacf27893d265d6b71e7c2fa2da661ce891c4", - "reference": "6d6bacf27893d265d6b71e7c2fa2da661ce891c4", + "url": "https://github.com/gitapi/repos/consolidation/annotated-command/zipball/c2dc2464e1edf0498bf97a99f34cac5805d00946", + "reference": "c2dc2464e1edf0498bf97a99f34cac5805d00946", "shasum": "" }, "require": { @@ -89,19 +89,19 @@ } ], "description": "Initialize Symfony Console commands from annotated command class methods.", - "time": "2016-08-19 22:56:42" + "time": "2016-09-13 21:37:50" }, { "name": "consolidation/log", "version": "1.0.3", "source": { "type": "git", - "url": "https://github.com/consolidation-org/log.git", + "url": "https://github.com/consolidation/log.git", "reference": "74ba81b4edc585616747cc5c5309ce56fec41254" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/consolidation-org/log/zipball/74ba81b4edc585616747cc5c5309ce56fec41254", + "url": "https://github.com/gitapi/repos/consolidation/log/zipball/74ba81b4edc585616747cc5c5309ce56fec41254", "reference": "74ba81b4edc585616747cc5c5309ce56fec41254", "shasum": "" }, @@ -140,16 +140,16 @@ }, { "name": "consolidation/output-formatters", - "version": "1.0.0", + "version": "1.1.0", "source": { "type": "git", - "url": "https://github.com/consolidation-org/output-formatters.git", - "reference": "6428d8fb30c9ed3b96314580808b3e4415b46dd9" + "url": "https://github.com/consolidation/output-formatters.git", + "reference": "aadb1ed2deb72bc1351bb6f3b3ddd328222e9261" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/consolidation-org/output-formatters/zipball/6428d8fb30c9ed3b96314580808b3e4415b46dd9", - "reference": "6428d8fb30c9ed3b96314580808b3e4415b46dd9", + "url": "https://github.com/gitapi/repos/consolidation/output-formatters/zipball/aadb1ed2deb72bc1351bb6f3b3ddd328222e9261", + "reference": "aadb1ed2deb72bc1351bb6f3b3ddd328222e9261", "shasum": "" }, "require": { @@ -183,19 +183,19 @@ } ], "description": "Format text by applying transformations provided by plug-in formatters.", - "time": "2016-05-20 04:17:55" + "time": "2016-09-14 23:51:08" }, { "name": "consolidation/robo", "version": "1.0.0-RC2", "source": { "type": "git", - "url": "https://github.com/consolidation-org/Robo.git", + "url": "https://github.com/consolidation/Robo.git", "reference": "abdae8e8e6d0872df9b02031c6d2f1b7364f3113" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/consolidation-org/Robo/zipball/abdae8e8e6d0872df9b02031c6d2f1b7364f3113", + "url": "https://github.com/gitapi/repos/consolidation/Robo/zipball/abdae8e8e6d0872df9b02031c6d2f1b7364f3113", "reference": "abdae8e8e6d0872df9b02031c6d2f1b7364f3113", "shasum": "" }, @@ -406,16 +406,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "3.1.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "9270140b940ff02e58ec577c237274e92cd40cdd" + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd", - "reference": "9270140b940ff02e58ec577c237274e92cd40cdd", + "url": "https://github.com/gitapi/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", "shasum": "" }, "require": { @@ -447,7 +447,7 @@ } ], "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-06-10 09:48:41" + "time": "2016-09-30 07:12:33" }, { "name": "phpdocumentor/type-resolver", @@ -498,22 +498,30 @@ }, { "name": "psr/log", - "version": "1.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + "reference": "5277094ed527a1c4477177d102fe4c53551953e0" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "url": "https://github.com/gitapi/repos/php-fig/log/zipball/5277094ed527a1c4477177d102fe4c53551953e0", + "reference": "5277094ed527a1c4477177d102fe4c53551953e0", "shasum": "" }, + "require": { + "php": ">=5.3.0" + }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { - "psr-0": { - "Psr\\Log\\": "" + "psr-4": { + "Psr\\Log\\": "Psr/Log/" } }, "notification-url": "https://packagist.org/downloads/", @@ -527,35 +535,86 @@ } ], "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", "keywords": [ "log", "psr", "psr-3" ], - "time": "2012-12-21 11:40:51" + "time": "2016-09-19 16:02:08" + }, + { + "name": "samsonasik/package-versions", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/samsonasik/PackageVersions.git", + "reference": "1dab884977464613383afe0e4be571cdef2317fc" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/samsonasik/PackageVersions/zipball/1dab884977464613383afe0e4be571cdef2317fc", + "reference": "1dab884977464613383afe0e4be571cdef2317fc", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0", + "php": "^5.6 || ^7.0" + }, + "replace": { + "ocramius/package-versions": ">=1.0.0" + }, + "require-dev": { + "composer/composer": "^1.0.0-ALPHA11@ALPHA", + "phpunit/phpunit": "^5.2.8" + }, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "A backport of ocramius/package-versions that supports php ^5.6. Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "time": "2016-07-21 12:03:58" }, { "name": "symfony/console", - "version": "v3.1.4", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "8ea494c34f0f772c3954b5fbe00bffc5a435e563" + "reference": "3d3e4fa5f0614c8e45220e5de80332322e33bd90" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/symfony/console/zipball/8ea494c34f0f772c3954b5fbe00bffc5a435e563", - "reference": "8ea494c34f0f772c3954b5fbe00bffc5a435e563", + "url": "https://github.com/gitapi/repos/symfony/console/zipball/3d3e4fa5f0614c8e45220e5de80332322e33bd90", + "reference": "3d3e4fa5f0614c8e45220e5de80332322e33bd90", "shasum": "" }, "require": { - "php": ">=5.5.9", + "php": ">=5.3.9", "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/process": "~2.8|~3.0" + "symfony/event-dispatcher": "~2.1|~3.0.0", + "symfony/process": "~2.1|~3.0.0" }, "suggest": { "psr/log": "For using the console logger", @@ -565,7 +624,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -592,7 +651,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-08-19 06:48:39" + "time": "2016-09-06 10:55:00" }, { "name": "symfony/event-dispatcher", @@ -656,25 +715,25 @@ }, { "name": "symfony/filesystem", - "version": "v3.1.4", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "bb29adceb552d202b6416ede373529338136e84f" + "reference": "44b499521defddf2eae17a18c811bbdae4f98bdf" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/symfony/filesystem/zipball/bb29adceb552d202b6416ede373529338136e84f", - "reference": "bb29adceb552d202b6416ede373529338136e84f", + "url": "https://github.com/gitapi/repos/symfony/filesystem/zipball/44b499521defddf2eae17a18c811bbdae4f98bdf", + "reference": "44b499521defddf2eae17a18c811bbdae4f98bdf", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.3.9" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -701,7 +760,7 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2016-07-20 05:44:26" + "time": "2016-09-06 10:55:00" }, { "name": "symfony/finder", @@ -914,16 +973,16 @@ "packages-dev": [ { "name": "behat/gherkin", - "version": "v4.4.2", + "version": "v4.4.4", "source": { "type": "git", "url": "https://github.com/Behat/Gherkin.git", - "reference": "d26757dc970e67b50ed0ee47b95273daeb84fea6" + "reference": "cf8cc94647101e02a33d690245896d83d880aea1" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/Behat/Gherkin/zipball/d26757dc970e67b50ed0ee47b95273daeb84fea6", - "reference": "d26757dc970e67b50ed0ee47b95273daeb84fea6", + "url": "https://github.com/gitapi/repos/Behat/Gherkin/zipball/cf8cc94647101e02a33d690245896d83d880aea1", + "reference": "cf8cc94647101e02a33d690245896d83d880aea1", "shasum": "" }, "require": { @@ -969,7 +1028,7 @@ "gherkin", "parser" ], - "time": "2016-09-03 07:28:57" + "time": "2016-09-18 12:16:14" }, { "name": "cheppers/git-hooks", @@ -1013,26 +1072,67 @@ "time": "2016-07-10 07:41:08" }, { - "name": "cheppers/robo-phpcs", + "name": "cheppers/lint-report", "version": "v0.0.4", + "source": { + "type": "git", + "url": "https://github.com/Cheppers/lint-report.git", + "reference": "5bbd4429f06b50c893ee30f74ce4ba02ea5a64aa" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/Cheppers/lint-report/zipball/5bbd4429f06b50c893ee30f74ce4ba02ea5a64aa", + "reference": "5bbd4429f06b50c893ee30f74ce4ba02ea5a64aa", + "shasum": "" + }, + "require": { + "league/container": "^2.2", + "symfony/console": "^2.8", + "symfony/filesystem": "^2.8", + "symfony/yaml": "^2.8 || ^3.1" + }, + "require-dev": { + "cheppers/git-hooks": "^0.0.8", + "codeception/codeception": "^2.2", + "squizlabs/php_codesniffer": "2.6.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Cheppers\\LintReport\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0+" + ], + "description": "Generate reports from lint results", + "time": "2016-10-02 12:00:15" + }, + { + "name": "cheppers/robo-phpcs", + "version": "v0.0.7", "source": { "type": "git", "url": "https://github.com/Cheppers/robo-phpcs.git", - "reference": "5b6ee2c22eb41247968cb82d05cb44fa73bcc901" + "reference": "04737eb2d3dadcbc7c4d0e9d91bdee8e1b69307b" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/Cheppers/robo-phpcs/zipball/5b6ee2c22eb41247968cb82d05cb44fa73bcc901", - "reference": "5b6ee2c22eb41247968cb82d05cb44fa73bcc901", + "url": "https://github.com/gitapi/repos/Cheppers/robo-phpcs/zipball/04737eb2d3dadcbc7c4d0e9d91bdee8e1b69307b", + "reference": "04737eb2d3dadcbc7c4d0e9d91bdee8e1b69307b", "shasum": "" }, "require": { + "cheppers/asset-jar": "^0.0.1", + "cheppers/lint-report": "^0.0.4", "consolidation/robo": "1.0.0-RC2", "squizlabs/php_codesniffer": "^2.6" }, "require-dev": { "cheppers/git-hooks": "^0.0.8", - "codeception/codeception": "^2.2" + "codeception/codeception": "^2.2", + "symfony/yaml": "^2.8 || ^3.1" }, "type": "library", "autoload": { @@ -1045,20 +1145,20 @@ "GPL-2.0+" ], "description": "Robo task wrapper for PHPCS", - "time": "2016-09-03 21:22:10" + "time": "2016-10-02 12:13:44" }, { "name": "codeception/codeception", - "version": "2.2.4", + "version": "2.2.5", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "ea617b8b55e6e33cdd47edeafde5d3f6466049e2" + "reference": "b4729341e469d0f174f3cade85718ff5bf8dd751" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/Codeception/Codeception/zipball/ea617b8b55e6e33cdd47edeafde5d3f6466049e2", - "reference": "ea617b8b55e6e33cdd47edeafde5d3f6466049e2", + "url": "https://github.com/gitapi/repos/Codeception/Codeception/zipball/b4729341e469d0f174f3cade85718ff5bf8dd751", + "reference": "b4729341e469d0f174f3cade85718ff5bf8dd751", "shasum": "" }, "require": { @@ -1069,8 +1169,8 @@ "guzzlehttp/guzzle": ">=4.1.4 <7.0", "guzzlehttp/psr7": "~1.0", "php": ">=5.4.0 <8.0", - "phpunit/php-code-coverage": ">=2.1.3", - "phpunit/phpunit": ">4.8.20 <5.5", + "phpunit/php-code-coverage": ">=2.1.3 <5.0", + "phpunit/phpunit": ">4.8.20 <6.0", "sebastian/comparator": "~1.1", "sebastian/diff": "^1.4", "symfony/browser-kit": ">=2.7 <4.0", @@ -1083,7 +1183,7 @@ }, "require-dev": { "codeception/specify": "~0.3", - "facebook/php-sdk-v4": "~5.0", + "facebook/graph-sdk": "~5.3", "flow/jsonpath": "~0.2", "league/factory-muffin": "^3.0", "league/factory-muffin-faker": "^1.0", @@ -1136,7 +1236,7 @@ "functional testing", "unit testing" ], - "time": "2016-08-14 12:28:58" + "time": "2016-09-29 01:29:59" }, { "name": "doctrine/instantiator", @@ -1411,16 +1511,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.5.1", + "version": "1.5.4", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "a8773992b362b58498eed24bf85005f363c34771" + "reference": "ea74994a3dc7f8d2f65a06009348f2d63c81e61f" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/myclabs/DeepCopy/zipball/a8773992b362b58498eed24bf85005f363c34771", - "reference": "a8773992b362b58498eed24bf85005f363c34771", + "url": "https://github.com/gitapi/repos/myclabs/DeepCopy/zipball/ea74994a3dc7f8d2f65a06009348f2d63c81e61f", + "reference": "ea74994a3dc7f8d2f65a06009348f2d63c81e61f", "shasum": "" }, "require": { @@ -1449,7 +1549,7 @@ "object", "object graph" ], - "time": "2015-11-20 12:04:31" + "time": "2016-09-16 13:37:59" }, { "name": "phpspec/prophecy", @@ -1759,24 +1859,24 @@ }, { "name": "phpunit/phpunit", - "version": "5.4.8", + "version": "5.5.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "3132365e1430c091f208e120b8845d39c25f20e6" + "reference": "a57126dc681b08289fef6ac96a48e30656f84350" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/sebastianbergmann/phpunit/zipball/3132365e1430c091f208e120b8845d39c25f20e6", - "reference": "3132365e1430c091f208e120b8845d39c25f20e6", + "url": "https://github.com/gitapi/repos/sebastianbergmann/phpunit/zipball/a57126dc681b08289fef6ac96a48e30656f84350", + "reference": "a57126dc681b08289fef6ac96a48e30656f84350", "shasum": "" }, "require": { "ext-dom": "*", "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", "myclabs/deep-copy": "~1.3", "php": "^5.6 || ^7.0", "phpspec/prophecy": "^1.3.1", @@ -1798,7 +1898,12 @@ "conflict": { "phpdocumentor/reflection-docblock": "3.0.2" }, + "require-dev": { + "ext-pdo": "*" + }, "suggest": { + "ext-tidy": "*", + "ext-xdebug": "*", "phpunit/php-invoker": "~1.1" }, "bin": [ @@ -1807,7 +1912,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.4.x-dev" + "dev-master": "5.5.x-dev" } }, "autoload": { @@ -1833,20 +1938,20 @@ "testing", "xunit" ], - "time": "2016-07-26 14:48:00" + "time": "2016-09-21 14:40:13" }, { "name": "phpunit/phpunit-mock-objects", - "version": "3.2.6", + "version": "3.2.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "46b249b43fd2ed8e127aa0fdb3cbcf56e9bc0e49" + "reference": "546898a2c0c356ef2891b39dd7d07f5d82c8ed0a" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/sebastianbergmann/phpunit-mock-objects/zipball/46b249b43fd2ed8e127aa0fdb3cbcf56e9bc0e49", - "reference": "46b249b43fd2ed8e127aa0fdb3cbcf56e9bc0e49", + "url": "https://github.com/gitapi/repos/sebastianbergmann/phpunit-mock-objects/zipball/546898a2c0c356ef2891b39dd7d07f5d82c8ed0a", + "reference": "546898a2c0c356ef2891b39dd7d07f5d82c8ed0a", "shasum": "" }, "require": { @@ -1892,7 +1997,7 @@ "mock", "xunit" ], - "time": "2016-08-26 05:51:59" + "time": "2016-09-06 16:07:45" }, { "name": "psr/http-message", diff --git a/src/LintReportWrapper/Json/FailureWrapper.php b/src/LintReportWrapper/Json/FailureWrapper.php new file mode 100644 index 0000000..068fc91 --- /dev/null +++ b/src/LintReportWrapper/Json/FailureWrapper.php @@ -0,0 +1,73 @@ +failure = $failure + [ + 'severity' => '', + 'source' => '', + 'message' => '', + 'line' => 0, + 'column' => 0, + ]; + } + + /** + * @return string + */ + public function severity() + { + return $this->failure['severity']; + } + + /** + * @return string + */ + public function source() + { + return $this->failure['source']; + } + + /** + * @return int + */ + public function line() + { + return $this->failure['line']; + } + + /** + * @return int + */ + public function column() + { + return $this->failure['column']; + } + + /** + * @return string + */ + public function message() + { + return $this->failure['message']; + } +} diff --git a/src/LintReportWrapper/Json/FileWrapper.php b/src/LintReportWrapper/Json/FileWrapper.php new file mode 100644 index 0000000..55c0d84 --- /dev/null +++ b/src/LintReportWrapper/Json/FileWrapper.php @@ -0,0 +1,151 @@ +file = $file + [ + 'filePath' => '', + 'errors' => 0, + 'warnings' => 0, + 'stats' => [], + 'failures' => [], + ]; + } + + /** + * {@inheritdoc} + */ + public function filePath() + { + return $this->file['filePath']; + } + + /** + * {@inheritdoc} + */ + public function numOfErrors() + { + return $this->file['errors']; + } + + /** + * {@inheritdoc} + */ + public function numOfWarnings() + { + return $this->file['warnings']; + } + + /** + * {@inheritdoc} + */ + public function yieldFailures() + { + foreach ($this->file['failures'] as $failure) { + yield new FailureWrapper($failure); + } + } + + /** + * {@inheritdoc} + */ + public function stats() + { + if (!$this->file['stats']) { + $this->file['stats'] = [ + 'severity' => 'ok', + 'has' => [ + ReportWrapperInterface::SEVERITY_OK => false, + ReportWrapperInterface::SEVERITY_WARNING => false, + ReportWrapperInterface::SEVERITY_ERROR => false, + ], + 'source' => [], + ]; + foreach ($this->file['failures'] as $failure) { + if ($this->severityComparer($this->file['stats']['severity'], $failure['severity']) === 1) { + $this->file['stats']['severity'] = $failure['severity']; + } + + $this->file['stats']['has'][$failure['severity']] = true; + + $this->file['stats']['source'] += [ + $failure['source'] => [ + 'severity' => $failure['severity'], + 'count' => 0, + ], + ]; + $this->file['stats']['source'][$failure['source']]['count']++; + } + } + + return $this->file['stats']; + } + + + /** + * @return string + */ + public function highestSeverity() + { + if ($this->numOfErrors()) { + return ReportWrapperInterface::SEVERITY_ERROR; + } + + if ($this->numOfWarnings()) { + return ReportWrapperInterface::SEVERITY_WARNING; + } + + return ReportWrapperInterface::SEVERITY_OK; + } + + /** + * @param string $a + * @param string $b + * + * @return int + */ + protected function severityComparer($a, $b) + { + $weights = [ + 'ok', + 'warning', + 'error', + ]; + + if ($a === $b) { + return 0; + } + + $aWeight = array_search($a, $weights); + $bWeight = array_search($b, $weights); + + if ($aWeight === false) { + return -1; + } + + if ($bWeight === false) { + return 1; + } + + return $aWeight > $bWeight ? -1 : 1; + } +} diff --git a/src/LintReportWrapper/Json/ReportWrapper.php b/src/LintReportWrapper/Json/ReportWrapper.php new file mode 100644 index 0000000..2a028be --- /dev/null +++ b/src/LintReportWrapper/Json/ReportWrapper.php @@ -0,0 +1,136 @@ +setReport($report); + } + } + + /** + * @return array + */ + public function getReport() + { + return $this->report; + } + + /** + * @param array $report + * + * @return $this + */ + public function setReport($report) + { + $this->report = $report; + $this->reportInternal = []; + $this->numOfErrors = 0; + $this->numOfWarnings = 0; + + foreach ($report as $filePath => $failures) { + $this->reportInternal[$filePath] = [ + 'filePath' => $filePath, + 'errors' => 0, + 'warnings' => 0, + 'stats' => [], + 'failures' => $failures, + ]; + + foreach ($failures as $failure) { + if ($failure['severity'] === 'error') { + $this->reportInternal[$filePath]['errors']++; + $this->numOfErrors++; + } elseif ($failure['severity'] === 'warning') { + $this->reportInternal[$filePath]['warnings']++; + $this->numOfWarnings++; + } + } + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function countFiles() + { + return count($this->reportInternal); + } + + /** + * {@inheritdoc} + */ + public function yieldFiles() + { + foreach ($this->reportInternal as $filePath => $file) { + yield $filePath => new FileWrapper($file); + } + } + + /** + * @return string + */ + public function highestSeverity() + { + if ($this->numOfErrors()) { + return ReportWrapperInterface::SEVERITY_ERROR; + } + + if ($this->numOfWarnings()) { + return ReportWrapperInterface::SEVERITY_WARNING; + } + + return ReportWrapperInterface::SEVERITY_OK; + } + + /** + * {@inheritdoc} + */ + public function numOfErrors() + { + return $this->numOfErrors; + } + + /** + * {@inheritdoc} + */ + public function numOfWarnings() + { + return $this->numOfWarnings; + } +} diff --git a/src/LintReportWrapper/Yaml/FailureWrapper.php b/src/LintReportWrapper/Yaml/FailureWrapper.php new file mode 100644 index 0000000..4c17163 --- /dev/null +++ b/src/LintReportWrapper/Yaml/FailureWrapper.php @@ -0,0 +1,82 @@ +failure = $failure + [ + 'failure' => '', + 'severity' => 'error', + 'name' => '', + 'ruleName' => '', + 'startPosition' => [ + 'line' => 0, + 'character' => 0, + 'position' => 0, + ], + 'endPosition' => [ + 'line' => 0, + 'character' => 0, + 'position' => 0, + ], + ]; + } + + /** + * @return string + */ + public function severity() + { + return $this->failure['severity']; + } + + /** + * @return string + */ + public function source() + { + return $this->failure['ruleName']; + } + + /** + * @return int + */ + public function line() + { + return $this->failure['startPosition']['line']; + } + + /** + * @return int + */ + public function column() + { + return $this->failure['startPosition']['character']; + } + + /** + * @return string + */ + public function message() + { + return $this->failure['failure']; + } +} diff --git a/src/LintReportWrapper/Yaml/FileWrapper.php b/src/LintReportWrapper/Yaml/FileWrapper.php new file mode 100644 index 0000000..96c5412 --- /dev/null +++ b/src/LintReportWrapper/Yaml/FileWrapper.php @@ -0,0 +1,151 @@ +file = $file + [ + 'filePath' => '', + 'errors' => 0, + 'warnings' => 0, + 'stats' => [], + 'failures' => [], + ]; + } + + /** + * {@inheritdoc} + */ + public function filePath() + { + return $this->file['filePath']; + } + + /** + * {@inheritdoc} + */ + public function numOfErrors() + { + return $this->file['errors']; + } + + /** + * {@inheritdoc} + */ + public function numOfWarnings() + { + return $this->file['warnings']; + } + + /** + * {@inheritdoc} + */ + public function yieldFailures() + { + foreach ($this->file['failures'] as $failure) { + yield new FailureWrapper($failure); + } + } + + /** + * {@inheritdoc} + */ + public function stats() + { + if (!$this->file['stats']) { + $this->file['stats'] = [ + 'severity' => 'ok', + 'has' => [ + ReportWrapperInterface::SEVERITY_OK => false, + ReportWrapperInterface::SEVERITY_WARNING => false, + ReportWrapperInterface::SEVERITY_ERROR => false, + ], + 'source' => [], + ]; + foreach ($this->file['failures'] as $failure) { + if ($this->severityComparer($this->file['stats']['severity'], $failure['severity']) === 1) { + $this->file['stats']['severity'] = $failure['severity']; + } + + $this->file['stats']['has'][$failure['severity']] = true; + + $this->file['stats']['source'] += [ + $failure['ruleName'] => [ + 'severity' => $failure['severity'], + 'count' => 0, + ], + ]; + $this->file['stats']['source'][$failure['ruleName']]['count']++; + } + } + + return $this->file['stats']; + } + + + /** + * @return string + */ + public function highestSeverity() + { + if ($this->numOfErrors()) { + return ReportWrapperInterface::SEVERITY_ERROR; + } + + if ($this->numOfWarnings()) { + return ReportWrapperInterface::SEVERITY_WARNING; + } + + return ReportWrapperInterface::SEVERITY_OK; + } + + /** + * @param string $a + * @param string $b + * + * @return int + */ + protected function severityComparer($a, $b) + { + $weights = [ + 'ok', + 'warning', + 'error', + ]; + + if ($a === $b) { + return 0; + } + + $aWeight = array_search($a, $weights); + $bWeight = array_search($b, $weights); + + if ($aWeight === false) { + return -1; + } + + if ($bWeight === false) { + return 1; + } + + return $aWeight > $bWeight ? -1 : 1; + } +} diff --git a/src/LintReportWrapper/Yaml/ReportWrapper.php b/src/LintReportWrapper/Yaml/ReportWrapper.php new file mode 100644 index 0000000..ec7cfb4 --- /dev/null +++ b/src/LintReportWrapper/Yaml/ReportWrapper.php @@ -0,0 +1,140 @@ +setReport($report); + } + } + + /** + * @return array + */ + public function getReport() + { + return $this->report; + } + + /** + * @param array $report + * + * @return $this + */ + public function setReport($report) + { + $this->report = $report; + $this->numOfErrors = null; + $this->numOfWarnings = null; + + foreach ($report as $document) { + foreach ($document['failures'] as $failure) { + $failure += ['severity' => 'error']; + $filePath = $failure['name']; + if (!isset($this->reportInternal[$filePath])) { + $this->reportInternal[$filePath] = [ + 'filePath' => $filePath, + 'errors' => 0, + 'warnings' => 0, + 'stats' => [], + 'failures' => [], + ]; + } + + $this->reportInternal[$filePath]['failures'][] = $failure; + if ($failure['severity'] === 'error') { + $this->reportInternal[$filePath]['errors']++; + $this->numOfErrors++; + } elseif ($failure['severity'] === 'warning') { + $this->reportInternal[$filePath]['warnings']++; + $this->numOfWarnings++; + } + } + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function countFiles() + { + return count($this->reportInternal); + } + + /** + * {@inheritdoc} + */ + public function yieldFiles() + { + foreach ($this->reportInternal as $file) { + yield $file['filePath'] => new FileWrapper($file); + } + } + + /** + * {@inheritdoc} + */ + public function numOfErrors() + { + return $this->numOfErrors; + } + + /** + * {@inheritdoc} + */ + public function numOfWarnings() + { + return $this->numOfWarnings; + } + + /** + * @return string + */ + public function highestSeverity() + { + if ($this->numOfErrors()) { + return ReportWrapperInterface::SEVERITY_ERROR; + } + + if ($this->numOfWarnings()) { + return ReportWrapperInterface::SEVERITY_WARNING; + } + + return ReportWrapperInterface::SEVERITY_OK; + } +} diff --git a/src/Task/LoadTasks.php b/src/Task/LoadTasks.php index d36cdce..288e8d1 100644 --- a/src/Task/LoadTasks.php +++ b/src/Task/LoadTasks.php @@ -2,6 +2,9 @@ namespace Cheppers\Robo\TsLint\Task; +use League\Container\ContainerAwareInterface; +use Robo\Contract\OutputAwareInterface; + /** * Class LoadTasks. * @@ -22,6 +25,16 @@ trait LoadTasks */ protected function taskTsLintRun(array $options = [], array $paths = []) { - return $this->task(Run::class, $options, $paths); + /** @var \Cheppers\Robo\TSLint\Task\Run $task */ + $task = $this->task(Run::class, $options, $paths); + if ($this instanceof ContainerAwareInterface) { + $task->setContainer($this->getContainer()); + } + + if ($this instanceof OutputAwareInterface) { + $task->setOutput($this->output()); + } + + return $task; } } diff --git a/src/Task/Run.php b/src/Task/Run.php index e04b76d..c07049e 100644 --- a/src/Task/Run.php +++ b/src/Task/Run.php @@ -4,10 +4,24 @@ use Cheppers\AssetJar\AssetJarAware; use Cheppers\AssetJar\AssetJarAwareInterface; +use Cheppers\LintReport\ReporterInterface; +use Cheppers\LintReport\ReportWrapperInterface; +use Cheppers\Robo\TsLint\LintReportWrapper\Json\ReportWrapper as JsonReportWrapper; +use Cheppers\Robo\TsLint\LintReportWrapper\Yaml\ReportWrapper as YamlReportWrapper; +use League\Container\ContainerAwareInterface; +use League\Container\ContainerAwareTrait; +use PackageVersions\Versions; +use Robo\Common\BuilderAwareTrait; use Robo\Common\IO; +use Robo\Contract\BuilderAwareInterface; +use Robo\Contract\OutputAwareInterface; use Robo\Result; use Robo\Task\BaseTask; +use Robo\Task\Filesystem\loadTasks as FsLoadTasks; +use Robo\Task\Filesystem\loadShortcuts as FsShortCuts; +use Robo\TaskAccessor; use Symfony\Component\Process\Process; +use Symfony\Component\Yaml\Yaml; /** * Class TaskTsLintRun. @@ -17,21 +31,40 @@ * * @package Cheppers\Robo\TsLint\Task */ -class Run extends BaseTask implements AssetJarAwareInterface +class Run extends BaseTask implements + AssetJarAwareInterface, + ContainerAwareInterface, + BuilderAwareInterface, + OutputAwareInterface { use AssetJarAware; + use ContainerAwareTrait; + use BuilderAwareTrait; use IO; + use FsLoadTasks; + use FsShortCuts; + use TaskAccessor; /** * Exit code: No lints were found. */ const EXIT_CODE_OK = 0; + /** + * Lints with a severity of warning were reported (no errors). + */ + const EXIT_CODE_WARNING = 1; + /** * One or more errors were reported (and any number of warnings). */ - const EXIT_CODE_ERROR = 1; + const EXIT_CODE_ERROR = 2; + + /** + * Something is invalid. + */ + const EXIT_CODE_INVALID = 3; /** * @todo Some kind of dependency injection would be awesome. @@ -111,6 +144,11 @@ class Run extends BaseTask implements AssetJarAwareInterface */ protected $format = ''; + /** + * @var \Cheppers\LintReport\ReporterInterface[] + */ + protected $lintReporters = []; + /** * The location of a tsconfig.json file that will be used to determine which files will be linted. * @@ -153,7 +191,9 @@ class Run extends BaseTask implements AssetJarAwareInterface */ protected $exitMessages = [ 0 => 'No lints were found', - 1 => 'One or more errors were reported (and any number of warnings)', + 1 => 'Lints with a severity of warning were reported (no errors)', + 2 => 'One or more errors were reported (and any number of warnings)', + 3 => 'Extra lint reporters can be used only if the output format is "json".', ]; /** @@ -222,6 +262,10 @@ public function options(array $options) $this->format($value); break; + case 'lintReporters': + $this->setLintReporters($value); + break; + case 'project': $this->project($value); break; @@ -370,6 +414,51 @@ public function format($value) return $this; } + /** + * @return \Cheppers\LintReport\ReporterInterface[] + */ + public function getLintReporters() + { + return $this->lintReporters; + } + + /** + * @param array $lintReporters + * + * @return $this + */ + public function setLintReporters(array $lintReporters) + { + $this->lintReporters = $lintReporters; + + return $this; + } + + /** + * @param string $id + * @param string|\Cheppers\LintReport\ReporterInterface $lintReporter + * + * @return $this + */ + public function addLintReporter($id, $lintReporter = null) + { + $this->lintReporters[$id] = $lintReporter; + + return $this; + } + + /** + * @param string $id + * + * @return $this + */ + public function removeLintReporter($id) + { + unset($this->lintReporters[$id]); + + return $this; + } + /** * @param string $value * @@ -454,54 +543,62 @@ protected function createIncludeList($items, $include) public function run() { $command = $this->buildCommand(); - $this->printTaskInfo(sprintf('TsLint task runs: %s', $command)); + $lintReporters = $this->initLintReporters(); + if ($lintReporters && !$this->isOutputFormatMachineReadable()) { + $this->exitCode = static::EXIT_CODE_INVALID; + + return new Result($this, $this->exitCode, $this->getExitMessage($this->exitCode)); + } + /** @var Process $process */ $process = new $this->processClass($command); if ($this->workingDirectory) { $process->setWorkingDirectory($this->workingDirectory); } + $result = $this->prepareOutputDirectory(); + if (!$result->wasSuccessful()) { + return $result; + } + $this->startTimer(); - $process->run(); + $this->exitCode = $process->run(); $this->stopTimer(); - $this->exitCode = $process->getExitCode(); - - $write_output = true; - - $report_parents = $this->getAssetJarMap('report'); - if ($this->hasAssetJar() - && $report_parents - && !$this->out - && $this->format === 'yaml' - && $this->convertFormatTo === 'yaml2jsonGroupByFiles' - && in_array($this->exitCode, $this->lintSuccessExitCodes()) - ) { - $report = json_decode($process->getOutput(), true); - if ($report) { - $this->exitCode = static::EXIT_CODE_ERROR; + $numOfErrors = $this->exitCode; + $numOfWarnings = 0; + if ($this->isLintSuccess()) { + $originalOutput = $process->getOutput(); + if ($this->isOutputFormatMachineReadable()) { + $machineOutput = ($this->out ? file_get_contents($this->out) : $originalOutput); + $reportWrapper = $this->decodeOutput($machineOutput); + $numOfErrors = $reportWrapper->numOfErrors(); + $numOfWarnings = $reportWrapper->numOfWarnings(); + + if ($this->isReportHasToBePutBackIntoJar()) { + $this->setAssetJarValue('report', $reportWrapper); + } + + foreach ($lintReporters as $lintReporter) { + $lintReporter + ->setReportWrapper($reportWrapper) + ->generate(); + } } - $write_output = false; - $this - ->getAssetJar() - ->setValue($report_parents, $report); - } - - if ($write_output) { - $this->getOutput()->writeln($process->getOutput()); + if (!$lintReporters) { + $this->output()->write($originalOutput); + } } - $message = isset($this->exitMessages[$this->exitCode]) ? - $this->exitMessages[$this->exitCode] - : $process->getErrorOutput(); + $exitCode = $this->getTaskExitCode($numOfErrors, $numOfWarnings); return new Result( $this, - $this->getTaskExitCode(), - $message, + $exitCode, + $this->getExitMessage($exitCode) ?: $process->getErrorOutput(), [ 'time' => $this->getExecutionTime(), ] @@ -592,25 +689,144 @@ public function buildCommand() return vsprintf($cmd_pattern, $cmd_args); } + /** + * @return bool + */ + protected function isReportHasToBePutBackIntoJar() + { + return ( + $this->hasAssetJar() + && $this->getAssetJarMap('report') + && $this->isLintSuccess() + ); + } + + /** + * @return bool + */ + protected function isOutputFormatMachineReadable() + { + return ($this->format === 'yaml'); + } + + /** + * @param string $output + * + * @return ReportWrapperInterface + */ + protected function decodeOutput($output) + { + $format = ($this->convertFormatTo === 'yaml2jsonGroupByFiles' ? 'json' : 'yaml'); + + switch ($format) { + case 'json': + return new JsonReportWrapper(json_decode($output, true)); + + case 'yaml': + if (function_exists('yaml_parse')) { + $decoded = yaml_parse($output); + } else { + $yamlVersion = ltrim(Versions::getShortVersion('symfony/yaml'), 'v'); + if (version_compare($yamlVersion, '3.1.0', '>=')) { + $decoded = Yaml::parse($output, Yaml::PARSE_OBJECT_FOR_MAP); + } else { + $decoded = Yaml::parse($output); + } + } + + return new YamlReportWrapper($decoded); + } + + return null; + } + + /** + * @return \Cheppers\LintReport\ReporterInterface[] + */ + protected function initLintReporters() + { + $lintReporters = []; + $c = $this->getContainer(); + foreach ($this->getLintReporters() as $id => $lintReporter) { + if ($lintReporter === false) { + continue; + } + + if (!$lintReporter) { + $lintReporter = $c->get($id); + } elseif (is_string($lintReporter)) { + $lintReporter = $c->get($lintReporter); + } + + if ($lintReporter instanceof ReporterInterface) { + $lintReporters[$id] = $lintReporter; + if (!$lintReporter->getDestination()) { + $lintReporter + ->setFilePathStyle('relative') + ->setDestination($this->output()); + } + } + } + + return $lintReporters; + } + /** * Get the exit code regarding the failOn settings. * + * @param int $numOfErrors + * @param int $numOfWarnings + * * @return int - * Exit code. */ - public function getTaskExitCode() + protected function getTaskExitCode($numOfErrors, $numOfWarnings) { - $tolerance = [ - 'never' => [static::EXIT_CODE_ERROR,], - ]; + if ($this->isLintSuccess()) { + switch ($this->failOn) { + case 'never': + return static::EXIT_CODE_OK; + + case 'warning': + if ($numOfErrors) { + return static::EXIT_CODE_ERROR; + } - if (isset($tolerance[$this->failOn]) && in_array($this->exitCode, $tolerance[$this->failOn])) { - return static::EXIT_CODE_OK; + return $numOfWarnings ? static::EXIT_CODE_WARNING : static::EXIT_CODE_OK; + + case 'error': + return $numOfErrors ? static::EXIT_CODE_ERROR : static::EXIT_CODE_OK; + } } return $this->exitCode; } + /** + * @param int $exitCode + * + * @return string + */ + protected function getExitMessage($exitCode) + { + if (isset($this->exitMessages[$exitCode])) { + return $this->exitMessages[$exitCode]; + } + + return false; + } + + /** + * Returns true if the lint ran successfully. + * + * Returns true even if there was any code style error or warning. + * + * @return bool + */ + protected function isLintSuccess() + { + return in_array($this->exitCode, $this->lintSuccessExitCodes()); + } + /** * @return int[] */ @@ -618,7 +834,37 @@ protected function lintSuccessExitCodes() { return [ static::EXIT_CODE_OK, + static::EXIT_CODE_WARNING, static::EXIT_CODE_ERROR, ]; } + + /** + * Prepare directory for report outputs. + * + * @return null|\Robo\Result + * Returns NULL on success or an error \Robo\Result. + */ + protected function prepareOutputDirectory() + { + if (empty($this->out)) { + return Result::success($this, 'There is no directory to create.'); + } + + $currentDir = getcwd(); + if ($this->workingDirectory) { + chdir($this->workingDirectory); + } + + $dir = pathinfo($this->out, PATHINFO_DIRNAME); + if (!file_exists($dir)) { + $result = $this->_mkdir($dir); + } else { + $result = Result::success($this, 'All directory was created successfully.'); + } + + chdir($currentDir); + + return $result; + } } diff --git a/tests/_data/RoboFile.php b/tests/_data/RoboFile.php index 0eb2d90..f231018 100644 --- a/tests/_data/RoboFile.php +++ b/tests/_data/RoboFile.php @@ -1,44 +1,88 @@ container = $container; + + BaseReporter::lintReportConfigureContainer($this->container); + + return $this; + } /** * @return \Cheppers\Robo\TsLint\Task\Run */ - public function lintVerbose() + public function lintStylishStdOutput() { return $this ->taskTsLintRun() - ->setOutput($this->getOutput()) - ->format('verbose') - ->paths(['samples/*']); + ->paths(['samples/*']) + ->format('stylish'); } /** * @return \Cheppers\Robo\TsLint\Task\Run */ - public function lintWithJar() + public function lintStylishFile() { - $assetJar = new \Cheppers\AssetJar\AssetJar([]); - return $this ->taskTsLintRun() - ->setOutput($this->getOutput()) - ->setAssetJar($assetJar) - ->setAssetJarMap('report', ['taskTsLint', 'report']) - ->configFile('tslint.json') - ->formattersDir('node_modules/tslint-formatters/lib/tslint/formatters') + ->paths(['samples/*']) + ->format('stylish') + ->out("{$this->reportsDir}/native.stylish.txt"); + } + + /** + * @return \Cheppers\Robo\TsLint\Task\Run + */ + public function lintAllInOne() + { + $verboseFile = new VerboseReporter(); + $verboseFile + ->setFilePathStyle('relative') + ->setDestination("{$this->reportsDir}/extra.verbose.txt"); + + $summaryFile = new SummaryReporter(); + $summaryFile + ->setFilePathStyle('relative') + ->setDestination("{$this->reportsDir}/extra.summary.txt"); + + return $this->taskTsLintRun() + ->paths(['samples/*']) ->format('yaml') ->convertFormatTo('yaml2jsonGroupByFiles') - ->paths(['samples/*']); + ->failOn('warning') + ->addLintReporter('verbose:StdOutput', 'lintVerboseReporter') + ->addLintReporter('verbose:file', $verboseFile) + ->addLintReporter('summary:StdOutput', 'lintSummaryReporter') + ->addLintReporter('summary:file', $summaryFile); } } diff --git a/tests/_data/expected/extra.summary.txt b/tests/_data/expected/extra.summary.txt new file mode 100644 index 0000000..d764668 --- /dev/null +++ b/tests/_data/expected/extra.summary.txt @@ -0,0 +1,14 @@ +samples/invalid-01.d.ts ++------------+-------------+ +| Source | Occurrences | ++------------+-------------+ +| whitespace | 1 | ++------------+-------------+ + +samples/invalid-02.d.ts ++------------+-------------+ +| Source | Occurrences | ++------------+-------------+ +| one-line | 1 | +| whitespace | 1 | ++------------+-------------+ diff --git a/tests/_data/expected/extra.verbose.txt b/tests/_data/expected/extra.verbose.txt new file mode 100644 index 0000000..5b361db --- /dev/null +++ b/tests/_data/expected/extra.verbose.txt @@ -0,0 +1,14 @@ +samples/invalid-01.d.ts ++----------+------+--------------------+ +| Severity | Line | Message | ++----------+------+--------------------+ +| error | 4 | missing whitespace | ++----------+------+--------------------+ + +samples/invalid-02.d.ts ++----------+------+-------------------------+ +| Severity | Line | Message | ++----------+------+-------------------------+ +| error | 3 | misplaced opening brace | +| error | 5 | missing whitespace | ++----------+------+-------------------------+ diff --git a/tests/_data/expected/native.stylish.txt b/tests/_data/expected/native.stylish.txt new file mode 100644 index 0000000..bc5d392 --- /dev/null +++ b/tests/_data/expected/native.stylish.txt @@ -0,0 +1,6 @@ +samples/invalid-01.d.ts +5:16 whitespace missing whitespace + +samples/invalid-02.d.ts +4:5 one-line misplaced opening brace +6:16 whitespace missing whitespace diff --git a/tests/_data/samples/invalid-02.d.ts b/tests/_data/samples/invalid-02.d.ts index b66788d..2b32223 100644 --- a/tests/_data/samples/invalid-02.d.ts +++ b/tests/_data/samples/invalid-02.d.ts @@ -1,6 +1,7 @@ declare namespace Foo2 { - export interface IMyInterface01 { + export interface IMyInterface01 + { myProp:number; diff --git a/tests/_support/AcceptanceTester.php b/tests/_support/AcceptanceTester.php index 8ce6e7a..d57e77b 100644 --- a/tests/_support/AcceptanceTester.php +++ b/tests/_support/AcceptanceTester.php @@ -13,10 +13,10 @@ * @method void am($role) * @method void lookForwardTo($achieveValue) * @method void comment($description) - * @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL) + * @method \Codeception\Lib\Friend haveFriend($name, $actorClass = null) * * @SuppressWarnings(PHPMD) -*/ + */ class AcceptanceTester extends \Codeception\Actor { use _generated\AcceptanceTesterActions; @@ -26,7 +26,7 @@ class AcceptanceTester extends \Codeception\Actor */ public function clearTheReportsDir() { - $reportsDir = 'tests/_data/reports'; + $reportsDir = codecept_data_dir('actual'); if (is_dir($reportsDir)) { $finder = new \Symfony\Component\Finder\Finder(); $finder->in($reportsDir); @@ -40,17 +40,67 @@ public function clearTheReportsDir() /** * @param string $taskName + * @param array $args + * @param array $options * * @return $this */ - public function runRoboTask($taskName) + public function runRoboTask($taskName, array $args = [], array $options = []) { - $cmd = sprintf( - 'cd tests/_data && ../../bin/robo %s', - escapeshellarg($taskName) + $cmdPattern = 'cd %s && ../../bin/robo %s'; + $cmdArgs = [ + escapeshellarg(codecept_data_dir()), + escapeshellarg($taskName), + ]; + + foreach ($options as $option => $value) { + $cmdPattern .= " --$option"; + if ($value !== null) { + $cmdPattern .= '=%s'; + $cmdArgs[] = escapeshellarg($value); + } + } + + $cmdPattern .= str_repeat(' %s', count($args)); + foreach ($args as $arg) { + $cmdArgs[] = escapeshellarg($arg); + } + + $this->runShellCommand(vsprintf($cmdPattern, $cmdArgs)); + + return $this; + } + + /** + * @param string $fileName + * + * @return $this + */ + public function haveAFileLikeThis($fileName) { + $expectedDir = codecept_data_dir('expected'); + $actualDir = codecept_data_dir('actual'); + + Assert::assertContains( + file_get_contents("$expectedDir/$fileName"), + file_get_contents("$actualDir/$fileName") ); - $this->runShellCommand($cmd); + return $this; + } + + /** + * @param string $fileName + * + * @return $this + */ + public function haveAValidCheckstyleReport($fileName) + { + $fileName = codecept_data_dir($fileName); + $doc = new \DOMDocument(); + $doc->loadXML(file_get_contents($fileName)); + $xpath = new DOMXPath($doc); + $rootElement = $xpath->query('/checkstyle'); + Assert::assertEquals(1, $rootElement->length, 'Root element of the Checkstyle XML is exists.'); return $this; } @@ -84,7 +134,7 @@ public function seeThisTextInTheStdError($expected) * * @return $this */ - public function theExitCodeShouldBe($expected) + public function expectTheExitCodeToBe($expected) { Assert::assertEquals($expected, $this->getExitCode()); diff --git a/tests/acceptance/LintAllInOneCept.php b/tests/acceptance/LintAllInOneCept.php new file mode 100644 index 0000000..7c9b49c --- /dev/null +++ b/tests/acceptance/LintAllInOneCept.php @@ -0,0 +1,20 @@ +wantTo("Run Robo task '$roboTaskName'."); +$i + ->clearTheReportsDir() + ->runRoboTask($roboTaskName) + ->expectTheExitCodeToBe(2) + ->seeThisTextInTheStdOutput(file_get_contents("$expectedDir/extra.verbose.txt")) + ->seeThisTextInTheStdOutput(file_get_contents("$expectedDir/extra.summary.txt")) + ->haveAFileLikeThis('extra.verbose.txt') + ->haveAFileLikeThis('extra.summary.txt') + ->seeThisTextInTheStdError('One or more errors were reported (and any number of warnings)'); diff --git a/tests/acceptance/LintStylishFileCept.php b/tests/acceptance/LintStylishFileCept.php new file mode 100644 index 0000000..d405a3e --- /dev/null +++ b/tests/acceptance/LintStylishFileCept.php @@ -0,0 +1,16 @@ +wantTo("Run Robo task '$roboTaskName'."); +$i + ->clearTheReportsDir() + ->runRoboTask($roboTaskName) + ->expectTheExitCodeToBe(2) + ->haveAFileLikeThis('native.stylish.txt') + ->seeThisTextInTheStdError('One or more errors were reported (and any number of warnings)'); diff --git a/tests/acceptance/LintStylishStdOutputCept.php b/tests/acceptance/LintStylishStdOutputCept.php new file mode 100644 index 0000000..b7288ce --- /dev/null +++ b/tests/acceptance/LintStylishStdOutputCept.php @@ -0,0 +1,17 @@ +wantTo("Run Robo task '$roboTaskName'."); +$i + ->clearTheReportsDir() + ->runRoboTask($roboTaskName) + ->expectTheExitCodeToBe(2) + ->seeThisTextInTheStdOutput(file_get_contents("$expectedDir/native.stylish.txt")) + ->seeThisTextInTheStdError('One or more errors were reported (and any number of warnings)'); diff --git a/tests/acceptance/LintVerboseCept.php b/tests/acceptance/LintVerboseCept.php deleted file mode 100644 index a1fcaa6..0000000 --- a/tests/acceptance/LintVerboseCept.php +++ /dev/null @@ -1,13 +0,0 @@ -wantTo('tslint --format verbose'); - -$i->runRoboTask('lint:verbose'); -$i->theExitCodeShouldBe(2); -$i->seeThisTextInTheStdOutput('(whitespace) samples/invalid-01.d.ts[5, 16]: missing whitespace'); -$i->seeThisTextInTheStdOutput('(whitespace) samples/invalid-02.d.ts[5, 16]: missing whitespace'); diff --git a/tests/acceptance/LintWithJarCept.php b/tests/acceptance/LintWithJarCept.php deleted file mode 100644 index 37c2e81..0000000 --- a/tests/acceptance/LintWithJarCept.php +++ /dev/null @@ -1,11 +0,0 @@ -wantTo('tslint --format yaml | tslint-formatters yaml2jsonGroupByFiles'); -$i->runRoboTask('lint:with-jar'); -$i->theExitCodeShouldBe(1); -$i->seeThisTextInTheStdError('One or more errors were reported (and any number of warnings)'); diff --git a/tests/unit/LintReportWrapper/JsonReportWrapperTest.php b/tests/unit/LintReportWrapper/JsonReportWrapperTest.php new file mode 100644 index 0000000..18ba356 --- /dev/null +++ b/tests/unit/LintReportWrapper/JsonReportWrapperTest.php @@ -0,0 +1,186 @@ + [ + 'expected' => [ + 'countFiles' => 0, + 'numOfErrors' => 0, + 'numOfWarnings' => 0, + 'highestSeverity' => 'ok', + ], + 'report' => [], + 'filesStats' => [], + ], + 'ok:one-file' => [ + 'expected' => [ + 'countFiles' => 1, + 'numOfErrors' => 0, + 'numOfWarnings' => 0, + 'highestSeverity' => 'ok', + ], + 'report' => [ + 'a.ts' => [], + ], + 'filesStats' => [ + 'a.ts' => [ + 'numOfErrors' => 0, + 'numOfWarnings' => 0, + 'highestSeverity' => 'ok', + 'stats' => [ + 'severity' => 'ok', + 'has' => [ + 'ok' => false, + 'warning' => false, + 'error' => false, + ], + 'source' => [], + ], + ], + ], + ], + 'warning:one-file' => [ + 'expected' => [ + 'countFiles' => 1, + 'numOfErrors' => 0, + 'numOfWarnings' => 1, + 'highestSeverity' => 'warning', + ], + 'report' => [ + 'a.ts' => [ + [ + 'severity' => 'warning', + 'source' => 's1', + 'line' => 1, + 'column' => 2, + 'message' => 'm1', + ] + ], + ], + 'filesStats' => [ + 'a.ts' => [ + 'numOfErrors' => 0, + 'numOfWarnings' => 1, + 'highestSeverity' => 'warning', + 'stats' => [ + 'severity' => 'warning', + 'has' => [ + 'ok' => false, + 'warning' => true, + 'error' => false, + ], + 'source' => [ + 's1' => [ + 'severity' => 'warning', + 'count' => 1, + ], + ], + ], + ], + ], + ], + 'error:one-file' => [ + 'expected' => [ + 'countFiles' => 1, + 'numOfErrors' => 1, + 'numOfWarnings' => 0, + 'highestSeverity' => 'error', + ], + 'report' => [ + 'a.ts' => [ + [ + 'severity' => 'error', + 'source' => 's1', + 'line' => 1, + 'column' => 2, + 'message' => 'm1', + ] + ], + ], + 'filesStats' => [ + 'a.ts' => [ + 'numOfErrors' => 1, + 'numOfWarnings' => 0, + 'highestSeverity' => 'error', + 'stats' => [ + 'severity' => 'error', + 'has' => [ + 'ok' => false, + 'warning' => false, + 'error' => true, + ], + 'source' => [ + 's1' => [ + 'severity' => 'error', + 'count' => 1, + ], + ], + ], + ], + ], + ], + ]; + } + + /** + * @dataProvider casesReports + * + * @param array $expected + * @param array $report + * @param array $filesStats + */ + public function testAll(array $expected, array $report, array $filesStats) + { + $rw = new ReportWrapper($report); + + $this->assertEquals($expected['countFiles'], $rw->countFiles()); + $this->assertEquals($expected['numOfErrors'], $rw->numOfErrors()); + $this->assertEquals($expected['numOfWarnings'], $rw->numOfWarnings()); + $this->assertEquals($expected['highestSeverity'], $rw->highestSeverity()); + + /** + * @var string $filePath + * @var \Cheppers\Robo\TsLint\LintReportWrapper\Json\FileWrapper $fw + */ + foreach ($rw->yieldFiles() as $filePath => $fw) { + $fileStats = $filesStats[$filePath]; + $this->assertEquals($filePath, $fw->filePath()); + $this->assertEquals($fileStats['numOfErrors'], $fw->numOfErrors()); + $this->assertEquals($fileStats['numOfWarnings'], $fw->numOfWarnings()); + $this->assertEquals($fileStats['highestSeverity'], $fw->highestSeverity()); + $this->assertEquals($fileStats['stats'], $fw->stats()); + + /** + * @var int $i + * @var \Cheppers\LintReport\FailureWrapperInterface $failureWrapper + */ + foreach ($fw->yieldFailures() as $i => $failureWrapper) { + $failure = $report[$filePath][$i]; + $this->assertEquals($failure['severity'], $failureWrapper->severity()); + $this->assertEquals($failure['source'], $failureWrapper->source()); + $this->assertEquals($failure['line'], $failureWrapper->line()); + $this->assertEquals($failure['column'], $failureWrapper->column()); + $this->assertEquals($failure['message'], $failureWrapper->message()); + } + } + } +} diff --git a/tests/unit/LintReportWrapper/YamlReportWrapperTest.php b/tests/unit/LintReportWrapper/YamlReportWrapperTest.php new file mode 100644 index 0000000..38a982f --- /dev/null +++ b/tests/unit/LintReportWrapper/YamlReportWrapperTest.php @@ -0,0 +1,184 @@ + [ + 'expected' => [ + 'countFiles' => 0, + 'numOfErrors' => 0, + 'numOfWarnings' => 0, + 'highestSeverity' => 'ok', + ], + 'report' => [], + 'filesStats' => [], + ], + 'warning:one-file' => [ + 'expected' => [ + 'countFiles' => 1, + 'numOfErrors' => 0, + 'numOfWarnings' => 1, + 'highestSeverity' => 'warning', + ], + 'report' => [ + [ + 'failures' => [ + [ + 'name' => 'a.ts', + 'severity' => 'warning', + 'ruleName' => 'r1', + 'failure' => 'f1', + 'startPosition' => [ + 'line' => 1, + 'character' => 2, + 'position' => 3, + ], + 'endPosition' => [ + 'line' => 4, + 'character' => 5, + 'position' => 6, + ], + ] + ], + ], + ], + 'filesStats' => [ + 'a.ts' => [ + 'numOfErrors' => 0, + 'numOfWarnings' => 1, + 'highestSeverity' => 'warning', + 'stats' => [ + 'severity' => 'warning', + 'has' => [ + 'ok' => false, + 'warning' => true, + 'error' => false, + ], + 'source' => [ + 'r1' => [ + 'severity' => 'warning', + 'count' => 1, + ], + ], + ], + ], + ], + ], + 'error:one-file' => [ + 'expected' => [ + 'countFiles' => 1, + 'numOfErrors' => 1, + 'numOfWarnings' => 0, + 'highestSeverity' => 'error', + ], + 'report' => [ + [ + 'failures' => [ + [ + 'name' => 'a.ts', + 'severity' => 'error', + 'ruleName' => 'r1', + 'failure' => 'f1', + 'startPosition' => [ + 'line' => 1, + 'character' => 2, + 'position' => 3, + ], + 'endPosition' => [ + 'line' => 4, + 'character' => 5, + 'position' => 6, + ], + ] + ], + ], + ], + 'filesStats' => [ + 'a.ts' => [ + 'numOfErrors' => 1, + 'numOfWarnings' => 0, + 'highestSeverity' => 'error', + 'stats' => [ + 'severity' => 'error', + 'has' => [ + 'ok' => false, + 'warning' => false, + 'error' => true, + ], + 'source' => [ + 'r1' => [ + 'severity' => 'error', + 'count' => 1, + ], + ], + ], + ], + ], + ], + ]; + } + + /** + * @dataProvider casesReports + * + * @param array $expected + * @param array $report + * @param array $filesStats + */ + public function testAll(array $expected, array $report, array $filesStats) + { + $rw = new ReportWrapper($report); + + $this->assertEquals($expected['countFiles'], $rw->countFiles()); + $this->assertEquals($expected['numOfErrors'], $rw->numOfErrors()); + $this->assertEquals($expected['numOfWarnings'], $rw->numOfWarnings()); + $this->assertEquals($expected['highestSeverity'], $rw->highestSeverity()); + + $docIndex = -1; + /** + * @var string $filePath + * @var \Cheppers\Robo\TsLint\LintReportWrapper\Json\FileWrapper $fw + */ + foreach ($rw->yieldFiles() as $fw) { + $docIndex++; + $filePath = $fw->filePath(); + $fileStats = $filesStats[$filePath]; + $this->assertEquals($filePath, $fw->filePath()); + $this->assertEquals($fileStats['numOfErrors'], $fw->numOfErrors()); + $this->assertEquals($fileStats['numOfWarnings'], $fw->numOfWarnings()); + $this->assertEquals($fileStats['highestSeverity'], $fw->highestSeverity()); + $this->assertEquals($fileStats['stats'], $fw->stats()); + + /** + * @var int $i + * @var \Cheppers\LintReport\FailureWrapperInterface $failureWrapper + */ + foreach ($fw->yieldFailures() as $i => $failureWrapper) { + $failure = $report[$docIndex]['failures'][$i]; + $this->assertEquals($failure['severity'], $failureWrapper->severity()); + $this->assertEquals($failure['ruleName'], $failureWrapper->source()); + $this->assertEquals($failure['startPosition']['line'], $failureWrapper->line()); + $this->assertEquals($failure['startPosition']['character'], $failureWrapper->column()); + $this->assertEquals($failure['failure'], $failureWrapper->message()); + } + } + } +} diff --git a/tests/unit/Task/RunTest.php b/tests/unit/Task/RunTest.php index f5b970d..d1b1812 100644 --- a/tests/unit/Task/RunTest.php +++ b/tests/unit/Task/RunTest.php @@ -1,7 +1,9 @@ getMethod($name); + $method->setAccessible(true); + + return $method; + } + /** * @var \League\Container\Container */ @@ -38,6 +54,28 @@ public function getContainer() return $this->container; } + public function testGetSetLintReporters() + { + $task = new RunTask([ + 'lintReporters' => [ + 'aKey' => 'aValue', + ], + ]); + + $task + ->addLintReporter('bKey', 'bValue') + ->addLintReporter('cKey', 'cValue') + ->removeLintReporter('bKey'); + + $this->assertEquals( + [ + 'aKey' => 'aValue', + 'cKey' => 'cValue', + ], + $task->getLintReporters() + ); + } + /** * @return array */ @@ -219,14 +257,16 @@ public function casesBuildCommand() */ public function testBuildCommand($expected, array $options, array $paths) { - $tslint = new Run($options, $paths); + $tslint = new RunTask($options, $paths); static::assertEquals($expected, $tslint->buildCommand()); } public function testExitCodeConstants() { - static::assertEquals(0, Run::EXIT_CODE_OK); - static::assertEquals(1, Run::EXIT_CODE_ERROR); + static::assertEquals(0, RunTask::EXIT_CODE_OK); + static::assertEquals(1, RunTask::EXIT_CODE_WARNING); + static::assertEquals(2, RunTask::EXIT_CODE_ERROR); + static::assertEquals(3, RunTask::EXIT_CODE_INVALID); } /** @@ -234,49 +274,71 @@ public function testExitCodeConstants() */ public function casesGetTaskExitCode() { + $o = RunTask::EXIT_CODE_OK; + $w = RunTask::EXIT_CODE_WARNING; + $e = RunTask::EXIT_CODE_ERROR; + $u = 5; + return [ - 'never-ok' => [ - Run::EXIT_CODE_OK, - [ - 'failOn' => 'never', - ], - Run::EXIT_CODE_OK, - ], - 'never-error' => [ - Run::EXIT_CODE_OK, - [ - 'failOn' => 'never', - ], - Run::EXIT_CODE_ERROR, - ], - 'warning-ok' => [ - Run::EXIT_CODE_OK, - [ - 'failOn' => 'warning', - ], - Run::EXIT_CODE_OK, - ], - 'warning-error' => [ - Run::EXIT_CODE_ERROR, - [ - 'failOn' => 'warning', - ], - Run::EXIT_CODE_ERROR, - ], - 'error-ok' => [ - Run::EXIT_CODE_OK, - [ - 'failOn' => 'error', - ], - Run::EXIT_CODE_OK, - ], - 'error-error' => [ - Run::EXIT_CODE_ERROR, - [ - 'failOn' => 'error', - ], - Run::EXIT_CODE_ERROR, - ], + 'never-000' => [$o, 'never', 0, 0, 0], + 'never-001' => [$o, 'never', 0, 0, 1], + 'never-002' => [$o, 'never', 0, 0, 2], + 'never-005' => [$u, 'never', 0, 0, 5], + + 'never-010' => [$o, 'never', 0, 1, 0], + 'never-011' => [$o, 'never', 0, 1, 1], + 'never-012' => [$o, 'never', 0, 1, 2], + 'never-015' => [$u, 'never', 0, 1, 5], + + 'never-100' => [$o, 'never', 1, 0, 0], + 'never-101' => [$o, 'never', 1, 0, 1], + 'never-102' => [$o, 'never', 1, 0, 2], + 'never-105' => [$u, 'never', 1, 0, 5], + + 'never-110' => [$o, 'never', 1, 1, 0], + 'never-111' => [$o, 'never', 1, 1, 1], + 'never-112' => [$o, 'never', 1, 1, 2], + 'never-115' => [$u, 'never', 1, 1, 5], + + 'warning-000' => [$o, 'warning', 0, 0, 0], + 'warning-001' => [$o, 'warning', 0, 0, 1], + 'warning-002' => [$o, 'warning', 0, 0, 2], + 'warning-005' => [$u, 'warning', 0, 0, 5], + + 'warning-010' => [$w, 'warning', 0, 1, 0], + 'warning-011' => [$w, 'warning', 0, 1, 1], + 'warning-012' => [$w, 'warning', 0, 1, 2], + 'warning-015' => [$u, 'warning', 0, 1, 5], + + 'warning-100' => [$e, 'warning', 1, 0, 0], + 'warning-101' => [$e, 'warning', 1, 0, 1], + 'warning-102' => [$e, 'warning', 1, 0, 2], + 'warning-105' => [$u, 'warning', 1, 0, 5], + + 'warning-110' => [$e, 'warning', 1, 1, 0], + 'warning-111' => [$e, 'warning', 1, 1, 1], + 'warning-112' => [$e, 'warning', 1, 1, 2], + 'warning-115' => [$u, 'warning', 1, 1, 5], + + 'error-000' => [$o, 'error', 0, 0, 0], + 'error-001' => [$o, 'error', 0, 0, 1], + 'error-002' => [$o, 'error', 0, 0, 2], + 'error-005' => [$u, 'error', 0, 0, 5], + + 'error-010' => [$o, 'error', 0, 1, 0], + 'error-011' => [$o, 'error', 0, 1, 1], + 'error-012' => [$o, 'error', 0, 1, 2], + 'error-015' => [$u, 'error', 0, 1, 5], + + 'error-100' => [$e, 'error', 1, 0, 0], + 'error-101' => [$e, 'error', 1, 0, 1], + 'error-102' => [$e, 'error', 1, 0, 2], + 'error-105' => [$u, 'error', 1, 0, 5], + + 'error-110' => [$e, 'error', 1, 1, 0], + 'error-111' => [$e, 'error', 1, 1, 1], + 'error-112' => [$e, 'error', 1, 1, 2], + 'error-115' => [$u, 'error', 1, 1, 5], ]; } @@ -284,19 +346,24 @@ public function casesGetTaskExitCode() * @dataProvider casesGetTaskExitCode * * @param int $expected - * @param array $options - * @param int $exit_code + * @param string $failOn + * @param int $numOfErrors + * @param int $numOfWarnings + * @param int $exitCode */ - public function testGetTaskExitCode($expected, $options, $exit_code) + public function testGetTaskExitCode($expected, $failOn, $numOfErrors, $numOfWarnings, $exitCode) { - /** @var Run $scss_lint */ - $scss_lint = Stub::construct( - Run::class, - [$options, []], - ['exitCode' => $exit_code] + /** @var RunTask $runTask */ + $runTask = Stub::construct( + RunTask::class, + [['failOn' => $failOn]], + ['exitCode' => $exitCode] ); - static::assertEquals($expected, $scss_lint->getTaskExitCode()); + static::assertEquals( + $expected, + static::getMethod('getTaskExitCode')->invokeArgs($runTask, [$numOfErrors, $numOfWarnings]) + ); } /** @@ -305,19 +372,58 @@ public function testGetTaskExitCode($expected, $options, $exit_code) public function casesRun() { return [ - 'without asset jar' => [ + 'withoutJar - success' => [ 0, - 'my-dummy-output', + [], + false, + ], + 'withoutJar - warning' => [ + 1, + [ + 'a.ts' => [ + [ + 'severity' => 'warning', + ], + ], + ], + false, + ], + 'withoutJar - error' => [ + 2, + [ + 'a.ts' => [ + [ + 'severity' => 'error', + ], + ] + ], false, ], - 'with_asset_jar-success' => [ + 'withJar - success' => [ 0, [], true, ], - 'with_asset_jar-fail' => [ + 'withJar - warning' => [ 1, - ['file-01.ts' => []], + [ + 'a.ts' => [ + [ + 'severity' => 'warning', + ], + ], + ], + true, + ], + 'withJar - error' => [ + 2, + [ + 'a.ts' => [ + [ + 'severity' => 'error', + ], + ], + ], true, ], ]; @@ -328,99 +434,113 @@ public function casesRun() * * @dataProvider casesRun * - * @param int $exit_code - * @param string $stdOutput + * @param int $expectedExitCode + * @param array $expectedReport * @param bool $withJar */ - public function testRunSuccess($exit_code, $stdOutput, $withJar) + public function testRun($expectedExitCode, array $expectedReport, $withJar) { $options = [ 'workingDirectory' => 'my-working-dir', 'assetJarMapping' => ['report' => ['tsLintRun', 'report']], 'format' => 'yaml', + 'failOn' => 'warning', 'convertFormatTo' => 'yaml2jsonGroupByFiles', ]; - /** @var Run $task */ - $task = Stub::construct( - Run::class, + /** @var RunTask $runTask */ + $runTask = Stub::construct( + RunTask::class, [$options, []], [ - 'processClass' => \Helper\Dummy\Process::class, + 'processClass' => DummyProcess::class, ] ); $output = new \Helper\Dummy\Output(); - \Helper\Dummy\Process::$exitCode = $exit_code; - \Helper\Dummy\Process::$stdOutput = $withJar ? json_encode($stdOutput) : $stdOutput; + DummyProcess::$exitCode = $expectedExitCode; + DummyProcess::$stdOutput = json_encode($expectedReport); - $task->setConfig(Robo::config()); - $task->setLogger($this->container->get('logger')); - $task->setOutput($output); + $runTask->setLogger($this->container->get('logger')); + $runTask->setOutput($output); $assetJar = null; if ($withJar) { - $assetJar = new \Cheppers\AssetJar\AssetJar(); - $task->setAssetJar($assetJar); + $assetJar = new AssetJar(); + $runTask->setAssetJar($assetJar); } - $result = $task->run(); + $result = $runTask->run(); - static::assertEquals($exit_code, $result->getExitCode()); + static::assertEquals($expectedExitCode, $result->getExitCode(), 'Exit code'); static::assertEquals( $options['workingDirectory'], - \Helper\Dummy\Process::$instance->getWorkingDirectory() + DummyProcess::$instance->getWorkingDirectory(), + 'Working directory' ); if ($withJar) { + /** @var \Cheppers\LintReport\ReportWrapperInterface $reportWrapper */ + $reportWrapper = $assetJar->getValue(['tsLintRun', 'report']); static::assertEquals( - $stdOutput, - $assetJar->getValue(['tsLintRun', 'report']) + $expectedReport, + $reportWrapper->getReport(), + 'Output equals with jar' ); } else { - static::assertContains( - $stdOutput, - $output->output, - 'Output contains' + static::assertEquals( + $expectedReport, + json_decode($output->output, true), + 'Output equals without jar' ); } } public function testRunFailed() { - $exit_code = 1; - $std_output = '{"foo": "bar"}'; + $exitCode = 1; + $expectedReport = [ + 'a.ts' => [ + [ + 'severity' => 'warning', + ], + ], + ]; + $expectedReportJson = json_encode($expectedReport); $options = [ 'workingDirectory' => 'my-working-dir', 'assetJarMapping' => ['report' => ['tsLintRun', 'report']], + 'failOn' => 'warning', 'format' => 'yaml', 'convertFormatTo' => 'yaml2jsonGroupByFiles', ]; - /** @var Run $task */ + /** @var RunTask $task */ $task = Stub::construct( - Run::class, + RunTask::class, [$options, []], [ - 'processClass' => \Helper\Dummy\Process::class, + 'processClass' => DummyProcess::class, ] ); - \Helper\Dummy\Process::$exitCode = $exit_code; - \Helper\Dummy\Process::$stdOutput = $std_output; + DummyProcess::$exitCode = $exitCode; + DummyProcess::$stdOutput = $expectedReportJson; $task->setConfig(Robo::config()); $task->setLogger($this->container->get('logger')); - $asset_jar = new \Cheppers\AssetJar\AssetJar(); - $task->setAssetJar($asset_jar); + $assetJar = new AssetJar(); + $task->setAssetJar($assetJar); $result = $task->run(); - static::assertEquals($exit_code, $result->getExitCode()); + static::assertEquals($exitCode, $result->getExitCode()); static::assertEquals( $options['workingDirectory'], - \Helper\Dummy\Process::$instance->getWorkingDirectory() + DummyProcess::$instance->getWorkingDirectory() ); - static::assertEquals(['foo' => 'bar'], $asset_jar->getValue(['tsLintRun', 'report'])); + /** @var \Cheppers\LintReport\ReportWrapperInterface $reportWrapper */ + $reportWrapper = $assetJar->getValue(['tsLintRun', 'report']); + static::assertEquals($expectedReport, $reportWrapper->getReport()); } }