Skip to content

Commit

Permalink
Add PHPUnit and automate testing
Browse files Browse the repository at this point in the history
  • Loading branch information
mglaman committed Dec 21, 2018
1 parent 02ea689 commit 0a9696f
Show file tree
Hide file tree
Showing 9 changed files with 241 additions and 21 deletions.
12 changes: 11 additions & 1 deletion .editorconfig
@@ -1,8 +1,18 @@
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

# PHP PSR-2 Coding Standards
# http://www.php-fig.org/psr/psr-2/

root = true

[*.php]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
indent_style = space
indent_size = 4

[*.neon]
indent_style = tab
5 changes: 1 addition & 4 deletions .gitignore
@@ -1,7 +1,4 @@
composer.phar
composer.lock
/vendor/

# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
# composer.lock
/clover.xml
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -14,6 +14,7 @@ install:
script:
- ./vendor/bin/phpcs src
- ./vendor/bin/phpstan analyze src
- ./vendor/bin/phpunit
cache:
directories:
- $HOME/.composer/cache
16 changes: 10 additions & 6 deletions composer.json
Expand Up @@ -13,16 +13,20 @@
"phpstan/phpstan": "^0.10.6",
"symfony/yaml": "^4.2"
},
"autoload": {
"psr-4": {
"PHPStan\\": "src/"
}
},
"require-dev": {
"phpstan/phpstan-strict-rules": "^0.10.1",
"squizlabs/php_codesniffer": "^3.3"
"squizlabs/php_codesniffer": "^3.3",
"phpunit/phpunit": "^7.5"
},
"suggest": {
"phpstan/phpstan-deprecation-rules": "For catching deprecations, especially in Drupal core."
},
"autoload": {
"psr-4": {
"PHPStan\\": "src/"
}
},
"autoload-dev": {
"classmap": ["tests/"]
}
}
28 changes: 28 additions & 0 deletions phpunit.xml
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/7.5/phpunit.xsd"
bootstrap="vendor/autoload.php"
forceCoversAnnotation="true"
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
verbose="true">
<testsuites>
<testsuite name="default">
<directory suffix="Test.php">tests</directory>
</testsuite>
</testsuites>
<logging>
<log type="coverage-text" target="php://stdout" showUncoveredFiles="true" lowUpperBound="50" highLowerBound="80" />
<log type="coverage-clover" target="./clover.xml" />
</logging>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
<exclude>
<directory>./vendor</directory>
<directory>./tests</directory>
</exclude>
</whitelist>
</filter>
</phpunit>
14 changes: 5 additions & 9 deletions src/Drupal/ServiceMap.php
Expand Up @@ -16,7 +16,11 @@ public function __construct(array $drupalServices)
foreach ($drupalServices as $serviceId => $serviceDefinition) {
// @todo support factories
if (!isset($serviceDefinition['class'])) {
continue;
if (isset($serviceDefinition['alias'], $drupalServices[$serviceDefinition['alias']])) {
$serviceDefinition['class'] = $drupalServices[$serviceDefinition['alias']]['class'];
} else {
continue;
}
}
$this->services[$serviceId] = new DrupalServiceDefinition(
$serviceId,
Expand All @@ -27,14 +31,6 @@ public function __construct(array $drupalServices)
}
}

/**
* @return DrupalServiceDefinition[]
*/
public function getServices(): array
{
return $this->services;
}

public function getService(string $id): ?DrupalServiceDefinition
{
return $this->services[$id] ?? null;
Expand Down
Expand Up @@ -8,6 +8,7 @@
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\ShouldNotHappenException;

class EntityTypeManagerGetStorageDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
{
Expand Down Expand Up @@ -38,7 +39,8 @@ public function getTypeFromMethodCall(
): Type {
$returnType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
if (!isset($methodCall->args[0])) {
return $returnType;
// Parameter is required.
throw new ShouldNotHappenException();
}

$arg1 = $methodCall->args[0]->value;
Expand Down
105 changes: 105 additions & 0 deletions tests/EntityTypeManagerGetStorageDynamicReturnTypeExtensionTest.php
@@ -0,0 +1,105 @@
<?php

namespace PHPStan\Drupal;

use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Scalar\String_;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParametersAcceptor;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\EntityTypeManagerGetStorageDynamicReturnTypeExtension;
use PHPStan\Type\ObjectType;
use PHPUnit\Framework\TestCase;

final class EntityTypeManagerGetStorageDynamicReturnTypeExtensionTest extends TestCase
{

/**
* @covers \PHPStan\Type\EntityTypeManagerGetStorageDynamicReturnTypeExtension::__construct
* @covers \PHPStan\Type\EntityTypeManagerGetStorageDynamicReturnTypeExtension::getClass
*/
public function testGetClass()
{
$x = new EntityTypeManagerGetStorageDynamicReturnTypeExtension([]);
self::assertEquals('Drupal\Core\Entity\EntityTypeManagerInterface', $x->getClass());
}

/**
* @dataProvider getEntityStorageProvider
*
* @covers \PHPStan\Type\EntityTypeManagerGetStorageDynamicReturnTypeExtension::__construct
* @covers \PHPStan\Type\EntityTypeManagerGetStorageDynamicReturnTypeExtension::getTypeFromMethodCall
*/
public function testGetTypeFromMethodCall($entityType, $storageClass)
{
$x = new EntityTypeManagerGetStorageDynamicReturnTypeExtension([
'node' => 'Drupal\node\NodeStorage',
'search_api_index' => 'Drupal\search_api\Entity\SearchApiConfigEntityStorage',
]);

$methodReflection = $this->prophesize(MethodReflection::class);
$methodReflection->getName()->willReturn('getStorage');

$defaultObjectType = $this->prophesize(ObjectType::class);
$defaultObjectType->getClassName()->willReturn('Drupal\Core\Entity\EntityStorageInterface');
$variantsParametersAcceptor = $this->prophesize(ParametersAcceptor::class);
$variantsParametersAcceptor->getReturnType()->willReturn($defaultObjectType->reveal());
$methodReflection->getVariants()->willReturn([$variantsParametersAcceptor->reveal()]);

if ($entityType === null) {
$this->expectException(ShouldNotHappenException::class);
$methodCall = new MethodCall(
$this->prophesize(Expr::class)->reveal(),
'getStorage'
);
} else {
$methodCall = new MethodCall(
$this->prophesize(Expr::class)->reveal(),
'getStorage',
[new Arg($entityType)]
);
}

$scope = $this->prophesize(Scope::class);

$type = $x->getTypeFromMethodCall(
$methodReflection->reveal(),
$methodCall,
$scope->reveal()
);
self::assertInstanceOf(ObjectType::class, $type);
assert($type instanceof ObjectType);
self::assertEquals($storageClass, $type->getClassName());
}

public function getEntityStorageProvider(): \Iterator
{
yield [new String_('node'), 'Drupal\node\NodeStorage'];
yield [new String_('user'), 'Drupal\Core\Entity\EntityStorageInterface'];
yield [new String_('search_api_index'), 'Drupal\search_api\Entity\SearchApiConfigEntityStorage'];
yield [null, null];
yield [$this->prophesize(MethodCall::class)->reveal(), 'Drupal\Core\Entity\EntityStorageInterface'];
yield [$this->prophesize(Expr\StaticCall::class)->reveal(), 'Drupal\Core\Entity\EntityStorageInterface'];
yield [$this->prophesize(Expr\BinaryOp\Concat::class)->reveal(), 'Drupal\Core\Entity\EntityStorageInterface'];
}

/**
* @covers \PHPStan\Type\EntityTypeManagerGetStorageDynamicReturnTypeExtension::__construct
* @covers \PHPStan\Type\EntityTypeManagerGetStorageDynamicReturnTypeExtension::isMethodSupported
*/
public function testIsMethodSupported()
{
$x = new EntityTypeManagerGetStorageDynamicReturnTypeExtension([]);

$valid = $this->prophesize(MethodReflection::class);
$valid->getName()->willReturn('getStorage');
self::assertTrue($x->isMethodSupported($valid->reveal()));

$invalid = $this->prophesize(MethodReflection::class);
$invalid->getName()->willReturn('getAccessControlHandler');
self::assertFalse($x->isMethodSupported($invalid->reveal()));
}
}
77 changes: 77 additions & 0 deletions tests/ServiceMapFactoryTest.php
@@ -0,0 +1,77 @@
<?php

namespace PHPStan\Drupal;

use PHPUnit\Framework\TestCase;

final class ServiceMapFactoryTest extends TestCase
{

/**
* @dataProvider getServiceProvider
*
* @covers \PHPStan\Drupal\ServiceMapFactory::__construct
* @covers \PHPStan\Drupal\ServiceMapFactory::create
* @covers \PHPStan\Drupal\DrupalServiceDefinition::__construct
* @covers \PHPStan\Drupal\DrupalServiceDefinition::getClass
* @covers \PHPStan\Drupal\DrupalServiceDefinition::isPublic
* @covers \PHPStan\Drupal\DrupalServiceDefinition::getAlias
* @covers \PHPStan\Drupal\DrupalServiceDefinition::getId
* @covers \PHPStan\Drupal\ServiceMap::__construct
* @covers \PHPStan\Drupal\ServiceMap::getService
*/
public function testFactory(string $id, callable $validator)
{
$factory = new ServiceMapFactory([
'entity_type.manager' => [
'class' => 'Drupal\Core\Entity\EntityTypeManager'
],
'skipped_factory' => [
'factory' => 'cache_factory:get',
'arguments' => ['cache'],
],
'config.storage.staging' => [
'class' => 'Drupal\Core\Config\FileStorage',
],
'config.storage.sync' => [
'alias' => 'config.storage.staging',
]
]);
$validator($factory->create()->getService($id));
}

public function getServiceProvider(): \Iterator
{
yield [
'unknown',
function (?DrupalServiceDefinition $service): void {
self::assertNull($service, 'unknown');
},
];
yield [
'entity_type.manager',
function (?DrupalServiceDefinition $service): void {
self::assertNotNull($service);
self::assertEquals('entity_type.manager', $service->getId());
self::assertEquals('Drupal\Core\Entity\EntityTypeManager', $service->getClass());
self::assertTrue($service->isPublic());
self::assertNull($service->getAlias());
}
];
// For now factories are skipped.
yield [
'skipped_factory',
function (?DrupalServiceDefinition $service): void {
self::assertNull($service);
},
];
yield [
'config.storage.sync',
function (?DrupalServiceDefinition $service): void {
self::assertNotNull($service);
self::assertEquals('config.storage.staging', $service->getAlias());
}
];
}

}

0 comments on commit 0a9696f

Please sign in to comment.