Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
cbb7e5e
Initial workflow file
mglaman Dec 13, 2020
c557fe6
Add PHPCS and PHPStan to workflow
mglaman Dec 13, 2020
5b7f627
Flag 8.0 as continue-on-error
mglaman Dec 13, 2020
24da053
Fix analyze typo
mglaman Dec 13, 2020
78c2454
Fix typo for PHPStan command
mglaman Dec 13, 2020
4a72a4a
Add Drupal install to workflow
mglaman Dec 13, 2020
70f8cbe
Add remaining TravisCI jobs
mglaman Dec 13, 2020
c34b0f4
Downgrade PHPUnit for D8
mglaman Dec 13, 2020
7604737
Fix workflow syntax error
mglaman Dec 13, 2020
bb25fec
Downgrade phpunit using `--with-all-dependencies`
mglaman Dec 13, 2020
53bf7fc
7.1 and 7.2 not support by D9
mglaman Dec 13, 2020
6d65032
Revert change to `on`
mglaman Dec 13, 2020
eec9093
Reduce matrix size to get actions to run again
mglaman Dec 13, 2020
3aee9c6
Adjust trigger events
mglaman Dec 13, 2020
02fafe5
Ensure PHP extensions; drop 8.8
mglaman Dec 13, 2020
b44054d
Only run deprecation rules test on ~8
mglaman Dec 13, 2020
bfc6de2
Add cron, ensure to downgrade Drupal along with PHPUnit
mglaman Dec 13, 2020
de7a70f
Catch error on SplString concat
mglaman Dec 13, 2020
9e62d4f
Missing experimental falg
mglaman Dec 13, 2020
003d3d1
Add Composer 2 support for composer/installers
mglaman Mar 10, 2021
312a319
composer/installers again
mglaman Mar 10, 2021
ab5a07b
Reduce the testing matrix
mglaman Mar 10, 2021
deb74ae
Add core-dev-pinned to dev dependencies
mglaman Mar 10, 2021
b068204
PHPUnit 6.5 for 8.9
mglaman Mar 10, 2021
b9eb161
Fix downgrade
mglaman Mar 10, 2021
0a6554b
Cross phpunit version fix for assertStringContainsString
mglaman Mar 10, 2021
2c108ee
Test the UnitTestCase dies
mglaman Mar 10, 2021
031bf41
Forgot `/web`
mglaman Mar 10, 2021
97f9301
Analyze test extended UnitTestCase
mglaman Mar 10, 2021
02a48f5
Add PHPUnit hack for tests
mglaman Mar 10, 2021
6e35bfc
Make sure mutated test case is ignored
mglaman Mar 10, 2021
232e126
Fix integration test for d8/d9
mglaman Mar 10, 2021
4542dad
Move mutated TestCase out of src
mglaman Mar 10, 2021
0a4ebb8
Updated Drush integration test
mglaman Mar 10, 2021
02aae33
Add back 7.3 testing
mglaman Mar 10, 2021
6bef3cc
Add 7.2 for Drupal 8.9
mglaman Mar 10, 2021
1577a64
Add PHP8/D9
mglaman Mar 10, 2021
fd23117
Add with-all-dependencies for php8 build_integration
mglaman Mar 10, 2021
b1958d3
Disable PHP8 for now
mglaman Mar 10, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
name: Tests
on:
push:
branches: [master]
pull_request:
branches: [master]
schedule:
- cron: 0 0 * * *

jobs:
tests:
continue-on-error: ${{ matrix.experimental }}
runs-on: "ubuntu-latest"
name: "PHP ${{ matrix.php-version }} | Drupal ${{ matrix.drupal }}"
strategy:
matrix:
experimental: [false]
php-version:
- "7.3"
- "7.4"
drupal:
- "^8.9"
- "^9.0"
include:
- php-version: "7.2"
drupal: "~8.9"
experimental: false
# @todo D9 is compat, but drupal/core-dev-pinned is not?
# core-dev-pinned sets phar-io/manifest to 1.0.3, where ^2.0 is
# - php-version: "8.0"
# drupal: "^9.0"
# experimental: true
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
tools: composer:v2
extensions: dom, curl, libxml, mbstring, zip, pdo, mysql, pdo_mysql, bcmath, gd, exif, iconv
- name: "Install dependencies"
run: "composer update --no-progress --prefer-dist"
- name: "Downgrade dev dependencies"
run: "composer require phpunit/phpunit:6.5.14 drush/drush:~9 drupal/core-recommended:${{ matrix.drupal }} drupal/core-dev-pinned:${{ matrix.drupal }} --with-all-dependencies"
if: ${{ matrix.drupal == '^8.9' }}
- name: "PHPCS"
run: "php vendor/bin/phpcs src"
- name: "PHPStan"
run: "php vendor/bin/phpstan analyze src"
- name: "PHPUnit"
run: "php vendor/bin/phpunit --debug"

build_integration:
continue-on-error: ${{ matrix.experimental }}
runs-on: "ubuntu-latest"
name: "PHP ${{ matrix.php-version }} | Drupal ${{ matrix.drupal }}"
strategy:
matrix:
experimental: [false]
php-version:
- "7.3"
- "7.4"
drupal:
- "^8.9"
- "^9.0"
include:
- php-version: "7.2"
drupal: "~8.9"
experimental: false
# @todo D9 is compat, but drupal/core-dev-pinned is not?
# core-dev-pinned sets phar-io/manifest to 1.0.3, where ^2.0 is
# - php-version: "8.0"
# drupal: "^9.0"
# experimental: true
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
tools: composer:v2
extensions: dom, curl, libxml, mbstring, zip, pdo, mysql, pdo_mysql, bcmath, gd, exif, iconv
- name: Setup Drupal
run: |
COMPOSER_MEMORY_LIMIT=-1 composer create-project drupal/recommended-project:${{ matrix.drupal }} ~/drupal --no-interaction
cd ~/drupal
composer config minimum-stability dev
composer config prefer-stable true
composer config preferred-install dist
composer config repositories.0 path $GITHUB_WORKSPACE
composer config repositories.1 composer https://packages.drupal.org/8
COMPOSER_MEMORY_LIMIT=-1 composer require drupal/core-dev-pinned:${{ matrix.drupal }} --with-all-dependencies
- name: "require phpstan-drupal"
run: |
cd ~/drupal
COMPOSER_MEMORY_LIMIT=-1 composer require mglaman/phpstan-drupal *@dev
cp $GITHUB_WORKSPACE/tests/fixtures/config/drupal-phpstan.neon phpstan.neon
- name: "Test core/install.php"
run: |
cd ~/drupal
./vendor/bin/phpstan analyze web/core/install.php --debug
- name: "Test core/tests/Drupal/Tests/UnitTestCase.php"
run: |
cd ~/drupal
./vendor/bin/phpstan analyze web/core/tests/Drupal/Tests/SkippedDeprecationTest.php --debug
- name: "Test BrowserTestBase is autoloaded"
run: |
cd ~/drupal
./vendor/bin/phpstan analyze web/core/modules/dynamic_page_cache | grep -q "Class Drupal\Tests\BrowserTestBase not found and could not be autoloaded." && false || true
- name: "Verify test fixtures are ignored."
run: |
cd ~/drupal
./vendor/bin/phpstan analyze web/core/modules/migrate_drupal --no-progress | grep -q "tests/fixtures" && false || true
- name: 'Check "Cannot redeclare token_theme() due to blazy_test.module"'
run: |
cd ~/drupal
COMPOSER_MEMORY_LIMIT=-1 composer require drupal/token drupal/blazy
./vendor/bin/phpstan analyze web/modules/contrib/blazy --no-progress || if (($? == 255)); then false; else true; fi
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ composer.lock
/vendor/
/clover.xml
.circleci/config_local.yml

# Fix PHPUnit compatibility mutated class.
/tests/fixtures/TestCase.php
.phpunit.result.cache
14 changes: 9 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
}
],
"require": {
"php": "^7.1",
"php": "^7.1 || ^8.0",
"nette/finder": "^2.5",
"phpstan/phpstan": "^0.12.64",
"symfony/yaml": "~3.4.5|^4.2",
Expand All @@ -19,18 +19,22 @@
"require-dev": {
"phpstan/phpstan-strict-rules": "^0.12.0",
"squizlabs/php_codesniffer": "^3.3",
"phpunit/phpunit": "^7.5",
"phpunit/phpunit": "^6.5 || ^7.5 || ^8.0 || ^9",
"phpstan/phpstan-deprecation-rules": "~0.12.0",
"composer/installers": "^1.6",
"drupal/core-recommended": "^8.8@alpha",
"drush/drush": "^9.6"
"composer/installers": "^1.9",
"drupal/core-recommended": "^8.8@alpha || ^9.0",
"drupal/core-dev-pinned": "^8.8@alpha || ^9.0",
"drush/drush": "^9.6 | ^10.0"
},
"minimum-stability": "dev",
"prefer-stable": true,
"suggest": {
"phpstan/phpstan-deprecation-rules": "For catching deprecations, especially in Drupal core."
},
"autoload": {
"files": [
"drupal-phpunit-hack.php"
],
"psr-4": {
"PHPStan\\": "src/"
}
Expand Down
33 changes: 33 additions & 0 deletions drupal-phpunit-hack.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php declare(strict_types=1);

/**
* @file
*
* Implements PHPUnit compatibility hack provided by ClassWriter
*
* This ensures we can run our PHPUnit tests against 8.9 and 9, and more.
*
* @see \Drupal\TestTools\PhpUnitCompatibility\PhpUnit8\ClassWriter::mutateTestBase()
*/
$autoloader = null;
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
$autoloader = require __DIR__ . '/vendor/autoload.php';
}
if (!$autoloader instanceof \Composer\Autoload\ClassLoader) {
return;
}

// Inspired by Symfony's simple-phpunit remove typehints from TestCase.
$alteredFile = $autoloader->findFile('PHPUnit\Framework\TestCase');
$phpunit_dir = dirname($alteredFile, 3);
// Mutate TestCase code to make it compatible with Drupal 8 and 9 tests.
$alteredCode = file_get_contents($alteredFile);
$alteredCode = preg_replace('/^ ((?:protected|public)(?: static)? function \w+\(\)): void/m', ' $1', $alteredCode);
$alteredCode = str_replace("__DIR__ . '/../Util/", "'$phpunit_dir/src/Util/", $alteredCode);
// Only write when necessary.
$filename = __DIR__ . '/tests/fixtures/TestCase.php';

if (!file_exists($filename) || md5_file($filename) !== md5($alteredCode)) {
file_put_contents($filename, $alteredCode);
}
include $filename;
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class TestDrushCommands extends DrushCommands {
public function example() {
if (drush_is_osx()) {
$this->io()->writeln('macOS');
} elseif (drush_is_cygwin() || drush_is_mingw()) {
} elseif (drush_is_windows()) {
$this->io()->writeln('Windows');
} else {
$this->io()->writeln('Linux ¯\_(ツ)_/¯');
Expand Down
3 changes: 3 additions & 0 deletions tests/src/DeprecationRulesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ class DeprecationRulesTest extends AnalyzerTestBase
*/
public function testDeprecationRules(string $path, int $count, array $errorMessages)
{
if (version_compare('9.0.0', \Drupal::VERSION) !== 1) {
$this->markTestSkipped('Only tested on Drupal 8.x.x');
}
$errors = $this->runAnalyze($path);
$this->assertCount($count, $errors->getErrors(), var_export($errors, true));
foreach ($errors->getErrors() as $key => $error) {
Expand Down
56 changes: 42 additions & 14 deletions tests/src/DrupalIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@

final class DrupalIntegrationTest extends AnalyzerTestBase {

public function testInstallPhp() {
public function testInstallPhp(): void
{
$errors = $this->runAnalyze(__DIR__ . '/../fixtures/drupal/core/install.php');
$this->assertCount(0, $errors->getErrors());
$this->assertCount(0, $errors->getInternalErrors());
self::assertCount(0, $errors->getErrors());
self::assertCount(0, $errors->getInternalErrors());
}

public function testTestSuiteAutoloading() {
Expand Down Expand Up @@ -39,37 +40,47 @@ public function testDrupalTestInChildSiteContant() {
}

public function testExtensionReportsError() {
$is_d9 = version_compare('9.0.0', \Drupal::VERSION) !== 1;
$errors = $this->runAnalyze(__DIR__ . '/../fixtures/drupal/modules/phpstan_fixtures/phpstan_fixtures.module');
$this->assertCount(3, $errors->getErrors(), var_export($errors, true));
$this->assertCount(0, $errors->getInternalErrors(), var_export($errors, true));
// @todo this only broke on D9.
self::assertCount($is_d9 ? 4 : 3, $errors->getErrors(), var_export($errors, true));
self::assertCount(0, $errors->getInternalErrors(), var_export($errors, true));

$errors = $errors->getErrors();
$error = array_shift($errors);
$this->assertEquals('If condition is always false.', $error->getMessage());
self::assertEquals('If condition is always false.', $error->getMessage());
$error = array_shift($errors);
$this->assertEquals('Function phpstan_fixtures_MissingReturnRule() should return string but return statement is missing.', $error->getMessage());
self::assertEquals('Function phpstan_fixtures_MissingReturnRule() should return string but return statement is missing.', $error->getMessage());
if ($is_d9) {
$error = array_shift($errors);
self::assertEquals('Binary operation "." between SplString and \'/core/includes…\' results in an error.', $error->getMessage());
}
$error = array_shift($errors);
$this->assertStringContainsString('phpstan_fixtures/phpstan_fixtures.fetch.inc could not be loaded from Drupal\\Core\\Extension\\ModuleHandlerInterface::loadInclude', $error->getMessage());

self::assertNotFalse(strpos($error->getMessage(), 'phpstan_fixtures/phpstan_fixtures.fetch.inc could not be loaded from Drupal\\Core\\Extension\\ModuleHandlerInterface::loadInclude'));
}

public function testExtensionTestSuiteAutoloading()
public function testExtensionTestSuiteAutoloading(): void
{
$paths = [
__DIR__ . '/../fixtures/drupal/modules/module_with_tests/tests/src/Unit/ModuleWithTestsTest.php',
// __DIR__ . '/../fixtures/drupal/modules/module_with_tests/tests/src/Traits/ModuleWithTestsTrait.php',
// __DIR__ . '/../fixtures/drupal/modules/module_with_tests/tests/src/TestSite/ModuleWithTestsTestSite.php',
__DIR__ . '/../fixtures/drupal/modules/module_with_tests/tests/src/Traits/ModuleWithTestsTrait.php',
__DIR__ . '/../fixtures/drupal/modules/module_with_tests/tests/src/TestSite/ModuleWithTestsTestSite.php',
];
foreach ($paths as $path) {
$errors = $this->runAnalyze($path);
$this->assertCount(0, $errors->getErrors(), implode(PHP_EOL, array_map(static function (Error $error) {
self::assertCount(0, $errors->getErrors(), implode(PHP_EOL, array_map(static function (Error $error) {
return $error->getMessage();
}, $errors->getErrors())));
$this->assertCount(0, $errors->getInternalErrors(), implode(PHP_EOL, $errors->getInternalErrors()));
self::assertCount(0, $errors->getInternalErrors(), implode(PHP_EOL, $errors->getInternalErrors()));
}
}

public function testServiceMapping()
public function testServiceMapping8()
{
if (version_compare('9.0.0', \Drupal::VERSION) !== 1) {
$this->markTestSkipped('Only tested on Drupal 8.x.x');
}
$errorMessages = [
'\Drupal calls should be avoided in classes, use dependency injection instead',
'Call to an undefined method Drupal\Core\Entity\EntityManager::thisMethodDoesNotExist().',
Expand All @@ -86,6 +97,23 @@ public function testServiceMapping()
}
}

public function testServiceMapping9()
{
if (version_compare('9.0.0', \Drupal::VERSION) === 1) {
$this->markTestSkipped('Only tested on Drupal 9.x.x');
}
// @todo: the actual error should be the fact `entity.manager` does not exist.
$errorMessages = [
'\Drupal calls should be avoided in classes, use dependency injection instead',
];
$errors = $this->runAnalyze(__DIR__ . '/../fixtures/drupal/modules/phpstan_fixtures/src/TestServicesMappingExtension.php');
$this->assertCount(1, $errors->getErrors());
$this->assertCount(0, $errors->getInternalErrors());
foreach ($errors->getErrors() as $key => $error) {
$this->assertEquals($errorMessages[$key], $error->getMessage());
}
}

public function testAppRootPseudoService() {
$errors = $this->runAnalyze(__DIR__ . '/../fixtures/drupal/modules/phpstan_fixtures/src/AppRootParameter.php');
$this->assertCount(0, $errors->getErrors(), var_export($errors, TRUE));
Expand Down
11 changes: 9 additions & 2 deletions tests/src/DrushIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,16 @@ final class DrushIntegrationTest extends AnalyzerTestBase
*/
public function testPaths($path) {
$errors = $this->runAnalyze($path);
$this->assertCount(0, $errors->getErrors(), var_export($errors, TRUE));
$errorMessages = [
'Call to deprecated function drush_is_windows():
. Use \\Consolidation\\SiteProcess\\Util\\Escape.',
];
$this->assertCount(1, $errors->getErrors(), var_export($errors, TRUE));
$this->assertCount(0, $errors->getInternalErrors(), var_export($errors, TRUE));
}
foreach ($errors->getErrors() as $key => $error) {
$this->assertEquals($errorMessages[$key], $error->getMessage());
}
}

public function dataPaths(): \Generator
{
Expand Down