Skip to content

Commit

Permalink
- support PHP attributes as metadata source
Browse files Browse the repository at this point in the history
- changes for PSR-11 container integration to simplify metadata provider switch
  • Loading branch information
Arthur Mogliev committed Apr 4, 2021
1 parent 1fa3b07 commit 467ec6d
Show file tree
Hide file tree
Showing 56 changed files with 3,302 additions and 870 deletions.
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ composer.lock export-ignore
composer.lock.* export-ignore
composer.phar export-ignore
mkdocs.yml export-ignore
phpspec.yml export-ignore
phpspec.yml export-ignore
phpspec.yml.* export-ignore
7 changes: 6 additions & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ jobs:
# ext-uopz does not support PHP 8 officially yet, so have to use custom build https://github.com/krakjoe/uopz/pull/138
- php: '8.0'
upload_coverage: true
container: ghcr.io/articus/phpdbg-coveralls:${{ matrix.php }}_2.4.3_2021-01-16
has_unique_phpspec_tests: true
container: ghcr.io/articus/phpdbg-coveralls:${{ matrix.php }}_2.4.3_2021-03-21
steps:
- name: Checkout code
uses: actions/checkout@v2
Expand All @@ -33,6 +34,10 @@ jobs:
- name: Install dependencies via Composer
run: php ./composer.phar install --no-interaction --no-progress --prefer-dist --classmap-authoritative

- name: Use unique phpspec.yml
if: matrix.has_unique_phpspec_tests
run: cp ./phpspec.yml.${{ matrix.php }} ./phpspec.yml

- name: Run PhpSpec tests
run: phpdbg -qrr ./vendor/phpspec/phpspec/bin/phpspec run

Expand Down
11 changes: 10 additions & 1 deletion phpspec.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
bootstrap: spec/bootstrap.php
formatter.name: pretty
matchers:
- spec\Matcher\PropertyValue
- spec\Matcher\PropertyValueType
extensions:
FriendsOfPhpSpec\PhpSpec\CodeCoverage\CodeCoverageExtension:
format:
Expand All @@ -10,4 +13,10 @@ extensions:
#html: spec_output/phpspec.coverage
clover: spec_output/phpspec.coverage.xml
whitelist:
- src
- src
#Exclude files with PHP 8+ code
blacklist:
- src/Articus/PathHandler/PhpAttribute
blacklist_files:
- src/Articus/PathHandler/MetadataProvider/PhpAttribute.php
- src/Articus/PathHandler/MetadataProvider/Factory/PhpAttribute.php
16 changes: 16 additions & 0 deletions phpspec.yml.8.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
bootstrap: spec/bootstrap.php
formatter.name: pretty
matchers:
- spec\Matcher\PropertyValue
- spec\Matcher\PropertyValueType
extensions:
FriendsOfPhpSpec\PhpSpec\CodeCoverage\CodeCoverageExtension:
format:
#- html
- text
- clover
output:
#html: spec_output/phpspec.coverage
clover: spec_output/phpspec.coverage.xml
whitelist:
- src
61 changes: 61 additions & 0 deletions spec/Articus/PathHandler/Attribute/Factory/PluginManagerSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);

namespace spec\Articus\PathHandler\Attribute\Factory;

use Articus\PathHandler as PH;
use Interop\Container\ContainerInterface;
use PhpSpec\ObjectBehavior;

/**
* TODO add expected text for LogicExceptions
*/
class PluginManagerSpec extends ObjectBehavior
{
public function it_gets_configuration_from_default_config_key(ContainerInterface $container, \ArrayAccess $config)
{
$configKey = PH\Attribute\PluginManager::class;
$container->get('config')->shouldBeCalledOnce()->willReturn($config);
$config->offsetExists($configKey)->shouldBeCalledOnce()->willReturn(true);
$config->offsetGet($configKey)->shouldBeCalledOnce();

$service = $this->__invoke($container, '');
$service->shouldBeAnInstanceOf(PH\Attribute\PluginManager::class);
}

public function it_gets_configuration_from_custom_config_key(ContainerInterface $container, \ArrayAccess $config)
{
$configKey = 'test_config_key';
$container->get('config')->shouldBeCalledOnce()->willReturn($config);
$config->offsetExists($configKey)->shouldBeCalledOnce()->willReturn(true);
$config->offsetGet($configKey)->shouldBeCalledOnce();

$this->beConstructedWith($configKey);
$service = $this->__invoke($container, '');
$service->shouldBeAnInstanceOf(PH\Attribute\PluginManager::class);
}

public function it_constructs_itself_and_gets_configuration_from_custom_config_key(ContainerInterface $container, \ArrayAccess $config)
{
$configKey = 'test_config_key';
$container->get('config')->shouldBeCalledOnce()->willReturn($config);
$config->offsetExists($configKey)->shouldBeCalledOnce()->willReturn(true);
$config->offsetGet($configKey)->shouldBeCalledOnce();

$service = $this::__callStatic($configKey, [$container, '', null]);
$service->shouldBeAnInstanceOf(PH\Attribute\PluginManager::class);
}

public function it_throws_on_too_few_arguments_during_self_construct(ContainerInterface $container)
{
$configKey = 'test_config_key';
$error = new \InvalidArgumentException(\sprintf(
'To invoke %s with custom configuration key statically 3 arguments are required: container, service name and options.',
PH\Attribute\Factory\PluginManager::class
));

$this::shouldThrow($error)->during('__callStatic', [$configKey, []]);
$this::shouldThrow($error)->during('__callStatic', [$configKey, [$container]]);
$this::shouldThrow($error)->during('__callStatic', [$configKey, [$container, '']]);
}
}
25 changes: 25 additions & 0 deletions spec/Articus/PathHandler/Consumer/Factory/JsonSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);

namespace spec\Articus\PathHandler\Consumer\Factory;

use Articus\PathHandler as PH;
use Interop\Container\ContainerInterface;
use PhpSpec\ObjectBehavior;

class JsonSpec extends ObjectBehavior
{
public function it_builds_json_consumer_with_default_options(ContainerInterface $container)
{
$service = $this->__invoke($container, 'test');
$service->shouldBeAnInstanceOf(PH\Consumer\Json::class);
$service->shouldHaveProperty('parseAsStdClass', false);
}

public function it_builds_json_consumer_with_specified_options(ContainerInterface $container)
{
$service = $this->__invoke($container, 'test', ['parse_as_std_class' => true]);
$service->shouldBeAnInstanceOf(PH\Consumer\Json::class);
$service->shouldHaveProperty('parseAsStdClass', true);
}
}
61 changes: 61 additions & 0 deletions spec/Articus/PathHandler/Consumer/Factory/PluginManagerSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);

namespace spec\Articus\PathHandler\Consumer\Factory;

use Articus\PathHandler as PH;
use Interop\Container\ContainerInterface;
use PhpSpec\ObjectBehavior;

/**
* TODO add expected text for LogicExceptions
*/
class PluginManagerSpec extends ObjectBehavior
{
public function it_gets_configuration_from_default_config_key(ContainerInterface $container, \ArrayAccess $config)
{
$configKey = PH\Consumer\PluginManager::class;
$container->get('config')->shouldBeCalledOnce()->willReturn($config);
$config->offsetExists($configKey)->shouldBeCalledOnce()->willReturn(true);
$config->offsetGet($configKey)->shouldBeCalledOnce();

$service = $this->__invoke($container, '');
$service->shouldBeAnInstanceOf(PH\Consumer\PluginManager::class);
}

public function it_gets_configuration_from_custom_config_key(ContainerInterface $container, \ArrayAccess $config)
{
$configKey = 'test_config_key';
$container->get('config')->shouldBeCalledOnce()->willReturn($config);
$config->offsetExists($configKey)->shouldBeCalledOnce()->willReturn(true);
$config->offsetGet($configKey)->shouldBeCalledOnce();

$this->beConstructedWith($configKey);
$service = $this->__invoke($container, '');
$service->shouldBeAnInstanceOf(PH\Consumer\PluginManager::class);
}

public function it_constructs_itself_and_gets_configuration_from_custom_config_key(ContainerInterface $container, \ArrayAccess $config)
{
$configKey = 'test_config_key';
$container->get('config')->shouldBeCalledOnce()->willReturn($config);
$config->offsetExists($configKey)->shouldBeCalledOnce()->willReturn(true);
$config->offsetGet($configKey)->shouldBeCalledOnce();

$service = $this::__callStatic($configKey, [$container, '', null]);
$service->shouldBeAnInstanceOf(PH\Consumer\PluginManager::class);
}

public function it_throws_on_too_few_arguments_during_self_construct(ContainerInterface $container)
{
$configKey = 'test_config_key';
$error = new \InvalidArgumentException(\sprintf(
'To invoke %s with custom configuration key statically 3 arguments are required: container, service name and options.',
PH\Consumer\Factory\PluginManager::class
));

$this::shouldThrow($error)->during('__callStatic', [$configKey, []]);
$this::shouldThrow($error)->during('__callStatic', [$configKey, [$container]]);
$this::shouldThrow($error)->during('__callStatic', [$configKey, [$container, '']]);
}
}
24 changes: 18 additions & 6 deletions spec/Articus/PathHandler/Consumer/JsonSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,9 @@

class JsonSpec extends ObjectBehavior
{
public function let()
{
$this->shouldImplement(PH\Consumer\ConsumerInterface::class);
}

public function it_parses_valid_json_null_from_body(StreamInterface $body)
{
$this->beConstructedWith(false);
$data = null;
$json = 'null';
$body->getContents()->shouldBeCalledOnce()->willReturn($json);
Expand All @@ -24,6 +20,7 @@ public function it_parses_valid_json_null_from_body(StreamInterface $body)

public function it_parses_valid_json_int_in_body(StreamInterface $body)
{
$this->beConstructedWith(false);
$data = 123;
$json = '123';
$body->getContents()->shouldBeCalledOnce()->willReturn($json);
Expand All @@ -32,6 +29,7 @@ public function it_parses_valid_json_int_in_body(StreamInterface $body)

public function it_parses_valid_json_float_in_body(StreamInterface $body)
{
$this->beConstructedWith(false);
$data = 123.456;
$json = '123.456';
$body->getContents()->shouldBeCalledOnce()->willReturn($json);
Expand All @@ -40,6 +38,7 @@ public function it_parses_valid_json_float_in_body(StreamInterface $body)

public function it_parses_valid_json_string_in_body(StreamInterface $body)
{
$this->beConstructedWith(false);
$data = 'qwer';
$json = '"qwer"';
$body->getContents()->shouldBeCalledOnce()->willReturn($json);
Expand All @@ -48,22 +47,35 @@ public function it_parses_valid_json_string_in_body(StreamInterface $body)

public function it_parses_valid_json_array_from_body(StreamInterface $body)
{
$this->beConstructedWith(false);
$data = [null, 123, 123.456, 'qwer'];
$json = '[null,123,123.456,"qwer"]';
$body->getContents()->shouldBeCalledOnce()->willReturn($json);
$this->parse($body, null, 'mime/test', [])->shouldBe($data);
}

public function it_parses_valid_json_object_from_body(StreamInterface $body)
public function it_parses_valid_json_object_from_body_as_array(StreamInterface $body)
{
$this->beConstructedWith(false);
$data = ['test' => 123];
$json = '{"test": 123}';
$body->getContents()->shouldBeCalledOnce()->willReturn($json);
$this->parse($body, null, 'mime/test', [])->shouldBe($data);
}

public function it_parses_valid_json_object_from_body_as_std_class(StreamInterface $body)
{
$this->beConstructedWith(true);
$data = new \stdClass();
$data->test = 123;
$json = '{"test": 123}';
$body->getContents()->shouldBeCalledOnce()->willReturn($json);
$this->parse($body, null, 'mime/test', [])->shouldBeLike($data);
}

public function it_throws_on_invalid_json_in_body(StreamInterface $body)
{
$this->beConstructedWith(false);
$json = '{';
$body->getContents()->shouldBeCalledOnce()->willReturn($json);
$this->shouldThrow(PH\Exception\BadRequest::class)->during('parse', [$body, null, 'mime/test', []]);
Expand Down
61 changes: 61 additions & 0 deletions spec/Articus/PathHandler/Handler/Factory/PluginManagerSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);

namespace spec\Articus\PathHandler\Handler\Factory;

use Articus\PathHandler as PH;
use Interop\Container\ContainerInterface;
use PhpSpec\ObjectBehavior;

/**
* TODO add expected text for LogicExceptions
*/
class PluginManagerSpec extends ObjectBehavior
{
public function it_gets_configuration_from_default_config_key(ContainerInterface $container, \ArrayAccess $config)
{
$configKey = PH\Handler\PluginManager::class;
$container->get('config')->shouldBeCalledOnce()->willReturn($config);
$config->offsetExists($configKey)->shouldBeCalledOnce()->willReturn(true);
$config->offsetGet($configKey)->shouldBeCalledOnce();

$service = $this->__invoke($container, '');
$service->shouldBeAnInstanceOf(PH\Handler\PluginManager::class);
}

public function it_gets_configuration_from_custom_config_key(ContainerInterface $container, \ArrayAccess $config)
{
$configKey = 'test_config_key';
$container->get('config')->shouldBeCalledOnce()->willReturn($config);
$config->offsetExists($configKey)->shouldBeCalledOnce()->willReturn(true);
$config->offsetGet($configKey)->shouldBeCalledOnce();

$this->beConstructedWith($configKey);
$service = $this->__invoke($container, '');
$service->shouldBeAnInstanceOf(PH\Handler\PluginManager::class);
}

public function it_constructs_itself_and_gets_configuration_from_custom_config_key(ContainerInterface $container, \ArrayAccess $config)
{
$configKey = 'test_config_key';
$container->get('config')->shouldBeCalledOnce()->willReturn($config);
$config->offsetExists($configKey)->shouldBeCalledOnce()->willReturn(true);
$config->offsetGet($configKey)->shouldBeCalledOnce();

$service = $this::__callStatic($configKey, [$container, '', null]);
$service->shouldBeAnInstanceOf(PH\Handler\PluginManager::class);
}

public function it_throws_on_too_few_arguments_during_self_construct(ContainerInterface $container)
{
$configKey = 'test_config_key';
$error = new \InvalidArgumentException(\sprintf(
'To invoke %s with custom configuration key statically 3 arguments are required: container, service name and options.',
PH\Handler\Factory\PluginManager::class
));

$this::shouldThrow($error)->during('__callStatic', [$configKey, []]);
$this::shouldThrow($error)->during('__callStatic', [$configKey, [$container]]);
$this::shouldThrow($error)->during('__callStatic', [$configKey, [$container, '']]);
}
}
Loading

0 comments on commit 467ec6d

Please sign in to comment.