add psalm and travis check

This commit is contained in:
Dominik Liebler
2019-08-31 14:31:01 +02:00
parent 88bd6ab7f1
commit 5fb2980b45
17 changed files with 1215 additions and 45 deletions

View File

@@ -24,3 +24,4 @@ install:
script: script:
- vendor/bin/phpunit - vendor/bin/phpunit
- vendor/bin/phpcs . - vendor/bin/phpcs .
- vendor/bin/psalm --show-info=false

View File

@@ -5,7 +5,10 @@ namespace DesignPatterns\Behavioral\ChainOfResponsibilities\Tests;
use DesignPatterns\Behavioral\ChainOfResponsibilities\Handler; use DesignPatterns\Behavioral\ChainOfResponsibilities\Handler;
use DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\HttpInMemoryCacheHandler; use DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\HttpInMemoryCacheHandler;
use DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\SlowDatabaseHandler; use DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\SlowDatabaseHandler;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\UriInterface;
class ChainTest extends TestCase class ChainTest extends TestCase
{ {
@@ -24,11 +27,11 @@ class ChainTest extends TestCase
public function testCanRequestKeyInFastStorage() public function testCanRequestKeyInFastStorage()
{ {
$uri = $this->createMock('Psr\Http\Message\UriInterface'); $uri = $this->createMock(UriInterface::class);
$uri->method('getPath')->willReturn('/foo/bar'); $uri->method('getPath')->willReturn('/foo/bar');
$uri->method('getQuery')->willReturn('index=1'); $uri->method('getQuery')->willReturn('index=1');
$request = $this->createMock('Psr\Http\Message\RequestInterface'); $request = $this->createMock(RequestInterface::class);
$request->method('getMethod') $request->method('getMethod')
->willReturn('GET'); ->willReturn('GET');
$request->method('getUri')->willReturn($uri); $request->method('getUri')->willReturn($uri);
@@ -38,11 +41,11 @@ class ChainTest extends TestCase
public function testCanRequestKeyInSlowStorage() public function testCanRequestKeyInSlowStorage()
{ {
$uri = $this->createMock('Psr\Http\Message\UriInterface'); $uri = $this->createMock(UriInterface::class);
$uri->method('getPath')->willReturn('/foo/baz'); $uri->method('getPath')->willReturn('/foo/baz');
$uri->method('getQuery')->willReturn(''); $uri->method('getQuery')->willReturn('');
$request = $this->createMock('Psr\Http\Message\RequestInterface'); $request = $this->createMock(RequestInterface::class);
$request->method('getMethod') $request->method('getMethod')
->willReturn('GET'); ->willReturn('GET');
$request->method('getUri')->willReturn($uri); $request->method('getUri')->willReturn($uri);

View File

@@ -2,25 +2,27 @@
namespace DesignPatterns\Behavioral\Observer; namespace DesignPatterns\Behavioral\Observer;
use SplSubject;
class UserObserver implements \SplObserver class UserObserver implements \SplObserver
{ {
/** /**
* @var User[] * @var SplSubject[]
*/ */
private $changedUsers = []; private $changedUsers = [];
/** /**
* It is called by the Subject, usually by SplSubject::notify() * It is called by the Subject, usually by SplSubject::notify()
* *
* @param \SplSubject $subject * @param SplSubject $subject
*/ */
public function update(\SplSubject $subject) public function update(SplSubject $subject)
{ {
$this->changedUsers[] = clone $subject; $this->changedUsers[] = clone $subject;
} }
/** /**
* @return User[] * @return SplSubject[]
*/ */
public function getChangedUsers(): array public function getChangedUsers(): array
{ {

View File

@@ -10,7 +10,7 @@ class AndSpecification implements Specification
private $specifications; private $specifications;
/** /**
* @param Specification[] ...$specifications * @param Specification[] $specifications
*/ */
public function __construct(Specification ...$specifications) public function __construct(Specification ...$specifications)
{ {

View File

@@ -10,14 +10,14 @@ class OrSpecification implements Specification
private $specifications; private $specifications;
/** /**
* @param Specification[] ...$specifications * @param Specification[] $specifications
*/ */
public function __construct(Specification ...$specifications) public function __construct(Specification ...$specifications)
{ {
$this->specifications = $specifications; $this->specifications = $specifications;
} }
/** /*
* if at least one specification is true, return true, else return false * if at least one specification is true, return true, else return false
*/ */
public function isSatisfiedBy(Item $item): bool public function isSatisfiedBy(Item $item): bool

View File

@@ -5,12 +5,12 @@ namespace DesignPatterns\Creational\AbstractFactory;
class ShippableProduct implements Product class ShippableProduct implements Product
{ {
/** /**
* @var float * @var int
*/ */
private $productPrice; private $productPrice;
/** /**
* @var float * @var int
*/ */
private $shippingCosts; private $shippingCosts;

View File

@@ -6,6 +6,6 @@ class FormatNumber implements Formatter
{ {
public function format(string $input): string public function format(string $input): string
{ {
return number_format($input); return number_format((int) $input);
} }
} }

View File

@@ -2,6 +2,8 @@
namespace DesignPatterns\Creational\StaticFactory\Tests; namespace DesignPatterns\Creational\StaticFactory\Tests;
use DesignPatterns\Creational\StaticFactory\FormatNumber;
use DesignPatterns\Creational\StaticFactory\FormatString;
use DesignPatterns\Creational\StaticFactory\StaticFactory; use DesignPatterns\Creational\StaticFactory\StaticFactory;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@@ -9,18 +11,12 @@ class StaticFactoryTest extends TestCase
{ {
public function testCanCreateNumberFormatter() public function testCanCreateNumberFormatter()
{ {
$this->assertInstanceOf( $this->assertInstanceOf(FormatNumber::class, StaticFactory::factory('number'));
'DesignPatterns\Creational\StaticFactory\FormatNumber',
StaticFactory::factory('number')
);
} }
public function testCanCreateStringFormatter() public function testCanCreateStringFormatter()
{ {
$this->assertInstanceOf( $this->assertInstanceOf(FormatString::class, StaticFactory::factory('string'));
'DesignPatterns\Creational\StaticFactory\FormatString',
StaticFactory::factory('string')
);
} }
public function testException() public function testException()

View File

@@ -2,10 +2,12 @@
namespace DesignPatterns\More\EAV; namespace DesignPatterns\More\EAV;
use SplObjectStorage;
class Entity class Entity
{ {
/** /**
* @var \SplObjectStorage * @var SplObjectStorage<Value,Value>
*/ */
private $values; private $values;
@@ -20,7 +22,7 @@ class Entity
*/ */
public function __construct(string $name, $values) public function __construct(string $name, $values)
{ {
$this->values = new \SplObjectStorage(); $this->values = new SplObjectStorage();
$this->name = $name; $this->name = $name;
foreach ($values as $value) { foreach ($values as $value) {

View File

@@ -24,6 +24,6 @@ class Value
public function __toString(): string public function __toString(): string
{ {
return sprintf('%s: %s', $this->attribute, $this->name); return sprintf('%s: %s', (string) $this->attribute, $this->name);
} }
} }

View File

@@ -5,18 +5,17 @@ namespace DesignPatterns\More\ServiceLocator;
class ServiceLocator class ServiceLocator
{ {
/** /**
* @var array|Service[] * @var string[][]
*/ */
private $services = []; private $services = [];
/** /**
* @var array|Service[] * @var Service[]
*/ */
private $instantiated = []; private $instantiated = [];
public function addInstance(string $class, Service $service) public function addInstance(string $class, Service $service)
{ {
$this->services[$class] = $service;
$this->instantiated[$class] = $service; $this->instantiated[$class] = $service;
} }
@@ -55,6 +54,10 @@ class ServiceLocator
throw new \OutOfRangeException('Too many arguments given'); throw new \OutOfRangeException('Too many arguments given');
} }
if (!$object instanceof Service) {
throw new \InvalidArgumentException('Could not register service: is no instance of Service');
}
$this->instantiated[$class] = $object; $this->instantiated[$class] = $object;
return $object; return $object;

View File

@@ -2,6 +2,7 @@
namespace DesignPatterns\Structural\Facade\Tests; namespace DesignPatterns\Structural\Facade\Tests;
use DesignPatterns\Structural\Facade\Bios;
use DesignPatterns\Structural\Facade\Facade; use DesignPatterns\Structural\Facade\Facade;
use DesignPatterns\Structural\Facade\OperatingSystem; use DesignPatterns\Structural\Facade\OperatingSystem;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@@ -10,27 +11,20 @@ class FacadeTest extends TestCase
{ {
public function testComputerOn() public function testComputerOn()
{ {
/** @var OperatingSystem|\PHPUnit_Framework_MockObject_MockObject $os */ $os = $this->createMock(OperatingSystem::class);
$os = $this->createMock('DesignPatterns\Structural\Facade\OperatingSystem');
$os->method('getName') $os->method('getName')
->will($this->returnValue('Linux')); ->will($this->returnValue('Linux'));
$bios = $this->getMockBuilder('DesignPatterns\Structural\Facade\Bios') $bios = $this->createMock(Bios::class);
->setMethods(['launch', 'execute', 'waitForKeyPress'])
->disableAutoload()
->getMock();
$bios->expects($this->once()) $bios->method('launch')
->method('launch')
->with($os); ->with($os);
/** @noinspection PhpParamsInspection */
$facade = new Facade($bios, $os); $facade = new Facade($bios, $os);
// the facade interface is simple
$facade->turnOn(); $facade->turnOn();
// but you can also access the underlying components
$this->assertSame('Linux', $os->getName()); $this->assertSame('Linux', $os->getName());
} }
} }

View File

@@ -20,6 +20,6 @@ class HeavyBankAccount implements BankAccount
// years and decades ago must be fetched from a database or web service // years and decades ago must be fetched from a database or web service
// and the balance must be calculated from it // and the balance must be calculated from it
return array_sum($this->transactions); return (int) array_sum($this->transactions);
} }
} }

View File

@@ -9,9 +9,6 @@ use PHPUnit\Framework\TestCase;
class RegistryTest extends TestCase class RegistryTest extends TestCase
{ {
/**
* @var Service|MockObject
*/
private $service; private $service;
protected function setUp(): void protected function setUp(): void
@@ -21,6 +18,7 @@ class RegistryTest extends TestCase
public function testSetAndGetLogger() public function testSetAndGetLogger()
{ {
/** @noinspection PhpParamsInspection */
Registry::set(Registry::LOGGER, $this->service); Registry::set(Registry::LOGGER, $this->service);
$this->assertSame($this->service, Registry::get(Registry::LOGGER)); $this->assertSame($this->service, Registry::get(Registry::LOGGER));

View File

@@ -16,7 +16,9 @@
"require-dev": { "require-dev": {
"phpunit/phpunit": "^8", "phpunit/phpunit": "^8",
"squizlabs/php_codesniffer": "^3", "squizlabs/php_codesniffer": "^3",
"flyeralarm/php-code-validator": "^2.2" "flyeralarm/php-code-validator": "^2.2",
"vimeo/psalm": "^3.4",
"psalm/plugin-phpunit": "^0.7.0"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

1111
composer.lock generated

File diff suppressed because it is too large Load Diff

60
psalm.xml Normal file
View File

@@ -0,0 +1,60 @@
<?xml version="1.0"?>
<psalm
totallyTyped="false"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="Behavioral"/>
<directory name="Creational"/>
<directory name="More"/>
<directory name="Structural"/>
<ignoreFiles>
<directory name="vendor"/>
</ignoreFiles>
</projectFiles>
<issueHandlers>
<LessSpecificReturnType errorLevel="info"/>
<!-- level 3 issues - slightly lazy code writing, but provably low false-negatives -->
<DeprecatedMethod errorLevel="info"/>
<DeprecatedProperty errorLevel="info"/>
<DeprecatedClass errorLevel="info"/>
<DeprecatedConstant errorLevel="info"/>
<DeprecatedFunction errorLevel="info"/>
<DeprecatedInterface errorLevel="info"/>
<DeprecatedTrait errorLevel="info"/>
<InternalMethod errorLevel="info"/>
<InternalProperty errorLevel="info"/>
<InternalClass errorLevel="info"/>
<MissingClosureReturnType errorLevel="info"/>
<MissingReturnType errorLevel="info"/>
<MissingPropertyType errorLevel="info"/>
<InvalidDocblock errorLevel="info"/>
<MisplacedRequiredParam errorLevel="info"/>
<PropertyNotSetInConstructor errorLevel="info"/>
<MissingConstructor errorLevel="info"/>
<MissingClosureParamType errorLevel="info"/>
<MissingParamType errorLevel="info"/>
<RedundantCondition errorLevel="info"/>
<DocblockTypeContradiction errorLevel="info"/>
<RedundantConditionGivenDocblockType errorLevel="info"/>
<UnresolvableInclude errorLevel="info"/>
<RawObjectIteration errorLevel="info"/>
<InvalidStringClass errorLevel="info"/>
</issueHandlers>
<plugins>
<pluginClass class="Psalm\PhpUnitPlugin\Plugin"/></plugins>
</psalm>