diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 0000000..f02b096 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,30 @@ +version: "2" + +checks: + method-complexity: + config: + threshold: 9 + +exclude_patterns: + - "config/" + - "db/" + - "dist/" + - "docs/" + - "features/" + - "**/node_modules/" + - "script/" + - "**/spec/" + - "**/test/" + - "**/tests/" + - "Tests/" + - "example.php" + - "examples/" + - "**/vendor/" + - "**/*_test.go" + - "**/*.d.ts" + +plugins: + phpcodesniffer: + enabled: true + config: + standard: "PSR2" diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 0000000..f7a98f9 --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,81 @@ +on: [push, pull_request] +jobs: + before: + runs-on: ubuntu-latest + steps: + - name: Prepare CodeClimate + env: + CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + run: | + wget https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 -qO ./cc-test-reporter + chmod +x ./cc-test-reporter + ./cc-test-reporter before-build + + unit-tests: + needs: [before] + strategy: + matrix: + include: + - image: 'iras/php7-composer:1' + php_version: 7.1 + - image: 'iras/php7-composer:2' + php_version: 7.2 + - image: 'iras/php7-composer:3' + php_version: 7.3 + - image: 'iras/php7-composer:4' + php_version: 7.4 + - image: 'iras/php8-composer:0' + php_version: 8.0 + name: PHP Unit Tests on PHP ${{ matrix.php_version }} + runs-on: ubuntu-latest + container: ${{ matrix.image }} + steps: + - name: Container Setup + run: | + apk add --no-cache tar openssl + mkdir coverage + wget https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 -qO /usr/bin/cc-test-reporter + chmod +x /usr/bin/cc-test-reporter + - name: Checkout + run: | + git init && git remote add origin https://github.com/${{ github.repository }}.git + git fetch origin ${{ github.sha }} && git reset --hard ${{ github.sha }} + - uses: actions/cache@v2 + with: + path: /composer/cache + key: composer-cache-7.${{ matrix.MINOR_VERSION }} + - name: Install dependencies + run: composer install --no-interaction --ansi + - name: Execute tests + run: | + php -dzend_extension=xdebug.so -dxdebug.mode=coverage vendor/bin/phpunit \ + -c phpunit.xml \ + --coverage-clover=coverage/clover.xml \ + --coverage-text \ + --color=always + - name: Format Coverage + run: | + cc-test-reporter format-coverage -t clover -o coverage/cc-${{ matrix.php_version }}.json coverage/clover.xml + - name: Store Coverage Result + uses: actions/upload-artifact@v3 + with: + name: coverage-results + path: coverage/ + + after: + needs: [unit-tests] + runs-on: ubuntu-latest + steps: + - name: Restore Coverage Result + uses: actions/download-artifact@v3 + with: + name: coverage-results + path: coverage/ + - name: Report Coverage + env: + CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + run: | + wget https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 -qO ./cc-test-reporter + chmod +x ./cc-test-reporter + ./cc-test-reporter sum-coverage coverage/cc-*.json -p 5 -o coverage/cc-total.json + ./cc-test-reporter upload-coverage -i coverage/cc-total.json diff --git a/.gitignore b/.gitignore index c10ac6e..d3c5cfd 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,8 @@ composer.phar # ide settings /.idea* +# phpunit result +/.phpunit.result.cache + # rendered documentation /docs/_site diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 495e31c..0000000 --- a/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -language: php -dist: trusty -php: - - 7.0 - - 7.1 - - 7.2 - -sudo: false - -cache: - directories: - - $HOME/.composer/cache - -matrix: - fast_finish: true - -before_script: - - composer install --no-interaction - - sh -c 'if [ "$TRAVIS_PHP_VERSION" = "7.1" ]; then composer require satooshi/php-coveralls:~0.6@stable; fi;' - - mkdir -p build/logs - -script: - - composer code-style - - vendor/bin/phpunit -c phpunit.xml --coverage-clover=build/logs/clover.xml --coverage-text - - sh -c 'if [ "$TRAVIS_PHP_VERSION" = "7.1" ]; then php vendor/bin/coveralls -v; fi;' diff --git a/README.md b/README.md index a49389f..1c7d53a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # tflori/verja -[![Build Status](https://travis-ci.org/tflori/verja.svg?branch=master)](https://travis-ci.org/tflori/verja) -[![Coverage Status](https://coveralls.io/repos/github/tflori/verja/badge.svg?branch=master)](https://coveralls.io/github/tflori/verja?branch=master) +[![.github/workflows/push.yml](https://github.com/tflori/verja/actions/workflows/push.yml/badge.svg)](https://github.com/tflori/verja/actions/workflows/push.yml) +[![Test Coverage](https://api.codeclimate.com/v1/badges/e07f4d5da0789699e27c/test_coverage)](https://codeclimate.com/github/tflori/verja/test_coverage) +[![Maintainability](https://api.codeclimate.com/v1/badges/e07f4d5da0789699e27c/maintainability)](https://codeclimate.com/github/tflori/verja/maintainability) [![Latest Stable Version](https://poser.pugx.org/tflori/verja/v/stable.svg)](https://packagist.org/packages/tflori/verja) [![Total Downloads](https://poser.pugx.org/tflori/verja/downloads.svg)](https://packagist.org/packages/tflori/verja) [![License](https://poser.pugx.org/tflori/verja/license.svg)](https://packagist.org/packages/tflori/verja) diff --git a/composer.json b/composer.json index 9e90864..cb5bbde 100644 --- a/composer.json +++ b/composer.json @@ -3,15 +3,16 @@ "description": "An validation tool for arrays filled by foreign input", "license": "MIT", "require": { - "php": "^7.0", + "php": "^7.0 || ^8.0", "ext-json": "*" }, "require-dev": { - "phpunit/phpunit": "^6.0", - "mockery/mockery": "^0.9", - "squizlabs/php_codesniffer": "^2.7", - "tflori/dependency-injector": "^1.3", - "nesbot/carbon": "^1.23" + "phpunit/phpunit": "*", + "tflori/phpunit-printer": "*", + "mockery/mockery": "^1.1", + "squizlabs/php_codesniffer": "^3.5", + "tflori/dependency-injector": "^2.2", + "nesbot/carbon": "^2.53" }, "autoload": { "psr-4": { diff --git a/phpunit.xml b/phpunit.xml index 3a97ae4..08eda2f 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -9,8 +9,7 @@ convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" - syntaxCheck="true" - printerClass="\Verja\Test\Printer"> + printerClass="PhpUnitPrinter\TextPrinter"> ./tests/ diff --git a/tests/ErrorsTest.php b/tests/ErrorsTest.php index 35f5252..a8f126c 100644 --- a/tests/ErrorsTest.php +++ b/tests/ErrorsTest.php @@ -43,9 +43,9 @@ public function errorsCanBeSerialized() $serialized = serialize($error); - self::assertContains('ERROR_KEY', $serialized); - self::assertContains('validated value', $serialized); - self::assertContains('Error message from validator', $serialized); + self::assertStringContainsString('ERROR_KEY', $serialized); + self::assertStringContainsString('validated value', $serialized); + self::assertStringContainsString('Error message from validator', $serialized); } /** @test */ diff --git a/tests/Field/ValidatorTest.php b/tests/Field/ValidatorTest.php index 36d46bc..21a432a 100644 --- a/tests/Field/ValidatorTest.php +++ b/tests/Field/ValidatorTest.php @@ -2,7 +2,6 @@ namespace Verja\Test\Field; -use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; use Verja\Field; use Verja\Gate; use Verja\Test\Examples\NotSerializable; @@ -13,8 +12,6 @@ class ValidatorTest extends TestCase { - use MockeryPHPUnitIntegration; - /** @dataProvider provideValidatorsValueExpected * @param ValidatorInterface[] $validators * @param mixed $value diff --git a/tests/Filter/DateTimeTest.php b/tests/Filter/DateTimeTest.php index c884a59..306da86 100644 --- a/tests/Filter/DateTimeTest.php +++ b/tests/Filter/DateTimeTest.php @@ -9,7 +9,7 @@ class DateTimeTest extends TestCase { - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { parent::setUpBeforeClass(); date_default_timezone_set('Europe/Berlin'); diff --git a/tests/Filter/EscapeTest.php b/tests/Filter/EscapeTest.php index b2c9e30..7b148e7 100644 --- a/tests/Filter/EscapeTest.php +++ b/tests/Filter/EscapeTest.php @@ -39,7 +39,7 @@ public function doesNotConvertNonStrings() $filtered = $filter->filter(42); - self::assertInternalType('integer', $filtered); + self::assertIsInt($filtered); } /** @dataProvider provideStringsWithHtmlEntities diff --git a/tests/Filter/FromStringTest.php b/tests/Filter/FromStringTest.php index a5074f2..258e531 100644 --- a/tests/Filter/FromStringTest.php +++ b/tests/Filter/FromStringTest.php @@ -9,7 +9,7 @@ class FromStringTest extends TestCase { - protected function tearDown() + protected function tearDown(): void { parent::tearDown(); Filter::resetNamespaces(); diff --git a/tests/Printer.php b/tests/Printer.php deleted file mode 100644 index a2c8ca5..0000000 --- a/tests/Printer.php +++ /dev/null @@ -1,207 +0,0 @@ - "\e[31m!\e[0m", // red ! - 'F' => "\e[31m\xe2\x9c\x96\e[0m", // red X - 'W' => "\e[33mW\e[0m", // yellow W - 'I' => "\e[33mI\e[0m", // yellow I - 'R' => "\e[33mR\e[0m", // yellow R - 'S' => "\e[36mS\e[0m", // cyan S - '.' => "\e[32m\xe2\x9c\x94\e[0m", // green checkmark - ]; - /** - * Structure of the outputted test row. - * - * @var string - */ - protected $testRow = ''; - - /** @var string */ - protected $previousClassName = ''; - - /** - * {@inheritdoc} - */ - protected function writeProgress($progress) - { - if ($this->hasReplacementSymbol($progress)) { - $progress = static::$symbols[$progress]; - } - $this->write(" {$progress} {$this->testRow}" . PHP_EOL); - $this->column++; - $this->numTestsRun++; - } - /** - * {@inheritdoc} - */ - public function addError(Test $test, \Exception $e, $time) - { - $this->buildTestRow(get_class($test), $test->getName(), $time, 'fg-red'); - parent::addError($test, $e, $time); - } - /** - * {@inheritdoc} - */ - public function addFailure(Test $test, AssertionFailedError $e, $time) - { - $this->buildTestRow(get_class($test), $test->getName(), $time, 'fg-red'); - parent::addFailure($test, $e, $time); - } - /** - * {@inheritdoc} - */ - public function addWarning(Test $test, Warning $e, $time) - { - $this->buildTestRow(get_class($test), $test->getName(), $time, 'fg-yellow'); - parent::addWarning($test, $e, $time); - } - /** - * {@inheritdoc} - */ - public function addIncompleteTest(Test $test, \Exception $e, $time) - { - $this->buildTestRow(get_class($test), $test->getName(), $time, 'fg-yellow'); - parent::addIncompleteTest($test, $e, $time); - } - /** - * {@inheritdoc} - */ - public function addRiskyTest(Test $test, \Exception $e, $time) - { - $this->buildTestRow(get_class($test), $test->getName(), $time, 'fg-yellow'); - parent::addRiskyTest($test, $e, $time); - } - /** - * {@inheritdoc} - */ - public function addSkippedTest(Test $test, \Exception $e, $time) - { - $this->buildTestRow(get_class($test), $test->getName(), $time, 'fg-cyan'); - parent::addSkippedTest($test, $e, $time); - } - /** - * {@inheritdoc} - */ - public function endTest(Test $test, $time) - { - $testName = \PHPUnit\Util\Test::describe($test); - if ($this->hasCompoundClassName($testName)) { - list($className, $methodName) = explode('::', $testName); - $this->buildTestRow($className, $methodName, $time); - } - parent::endTest($test, $time); - } - /** - * {@inheritdoc} - * - * We'll handle the coloring ourselves. - */ - protected function writeProgressWithColor($color, $buffer) - { - return $this->writeProgress($buffer); - } - /** - * Formats the results for a single test. - * - * @param $className - * @param $methodName - * @param $time - * @param $color - */ - protected function buildTestRow($className, $methodName, $time, $color = 'fg-white') - { - if ($className != $this->previousClassName) { - $this->write(PHP_EOL . $this->formatWithColor('fg-magenta', $className) . PHP_EOL); - $this->previousClassName = $className; - } - - $this->testRow = sprintf( - "(%s) %s", - $this->formatTestDuration($time), - $this->formatWithColor($color, "{$this->formatMethodName($methodName)}") - ); - } - /** - * Makes the method name more readable. - * - * @param $method - * @return mixed - */ - protected function formatMethodName($method) - { - return ucfirst( - $this->splitCamels( - $this->splitSnakes($method) - ) - ); - } - /** - * Replaces underscores in snake case with spaces. - * - * @param $name - * @return string - */ - protected function splitSnakes($name) - { - return str_replace('_', ' ', $name); - } - /** - * Splits camel-cased names while handling caps sections properly. - * - * @param $name - * @return string - */ - protected function splitCamels($name) - { - return preg_replace('/(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/', ' $1', $name); - } - /** - * Colours the duration if the test took longer than 500ms. - * - * @param $time - * @return string - */ - protected function formatTestDuration($time) - { - $testDurationInMs = round($time * 1000); - $duration = $testDurationInMs > 500 - ? $this->formatWithColor('fg-yellow', $testDurationInMs) - : $testDurationInMs; - return sprintf('%s ms', $duration); - } - /** - * Verifies if we have a replacement symbol available. - * - * @param $progress - * @return bool - */ - protected function hasReplacementSymbol($progress) - { - return in_array($progress, array_keys(static::$symbols)); - } - /** - * Checks if the class name is in format Class::method. - * - * @param $testName - * @return bool - */ - protected function hasCompoundClassName($testName) - { - return ! empty($testName) && strpos($testName, '::') > -1; - } -} diff --git a/tests/TestCase.php b/tests/TestCase.php index d874a70..420b0bd 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,35 +2,8 @@ namespace Verja\Test; -use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; +use Mockery\Adapter\Phpunit\MockeryTestCase; -class TestCase extends \PHPUnit\Framework\TestCase +class TestCase extends MockeryTestCase { - use MockeryPHPUnitIntegration; - - /** - * Performs assertions shared by all tests of a test case. This method is - * called before execution of a test ends and before the tearDown method. - */ - protected function assertPostConditions() - { - $this->addMockeryExpectationsToAssertionCount(); - $this->closeMockery(); - - parent::assertPostConditions(); - } - - protected function addMockeryExpectationsToAssertionCount() - { - $container = \Mockery::getContainer(); - if ($container != null) { - $count = $container->mockery_getExpectationCount(); - $this->addToAssertionCount($count); - } - } - - protected function closeMockery() - { - \Mockery::close(); - } } diff --git a/tests/Validator/FromStringTest.php b/tests/Validator/FromStringTest.php index f361b66..de5fb66 100644 --- a/tests/Validator/FromStringTest.php +++ b/tests/Validator/FromStringTest.php @@ -9,7 +9,7 @@ class FromStringTest extends TestCase { - protected function tearDown() + protected function tearDown(): void { parent::tearDown(); Validator::resetNamespaces(); diff --git a/tests/Validator/UrlTest.php b/tests/Validator/UrlTest.php index 47e6ae2..81a4bad 100644 --- a/tests/Validator/UrlTest.php +++ b/tests/Validator/UrlTest.php @@ -14,7 +14,7 @@ class UrlTest extends TestCase /** @var Helper|Mock */ protected $helperMock; - protected function setUp() + protected function setUp(): void { parent::setUp(); @@ -208,11 +208,10 @@ public function storesErrorWithoutListeningServer() public function provideInvalidUrls() { return [ - [':'], - ['//'], - ['//example.com:65536'], // port out of range - ['//example.com:0'], // port out of range - ['//:'], + 'only-colon' => [':'], + 'only-slashes' => ['//'], + 'port>65k' => ['//example.com:65536'], // port out of range + 'no-port-and-host' => ['//:'], ]; }