Skip to content

Commit cef45ed

Browse files
committed
Collaborator implementation and generator wrapper refactoring.
1 parent a7294f2 commit cef45ed

11 files changed

+445
-27
lines changed

phpspec.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ code_coverage:
1313

1414
extensions:
1515
- PhpSpec\Extension\CodeCoverageExtension
16+
- EcomDev\PHPSpec\FileMatcher\Extension

phpspec.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ suites:
77
formatter.name: nyan.cat
88
extensions:
99
- PhpSpec\NyanFormattersExtension\Extension
10+
- EcomDev\PHPSpec\FileMatcher\Extension

spec/Fixture/Catcher.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace spec\EcomDev\PHPSpec\MagentoDiAdapter\Fixture;
4+
5+
class Catcher
6+
{
7+
public function invoke($args)
8+
{
9+
return $args;
10+
}
11+
}

spec/Fixture/SignatureClass.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
4+
namespace spec\EcomDev\PHPSpec\MagentoDiAdapter\Fixture;
5+
6+
class SignatureClass
7+
{
8+
function valid_class_factory_param(ValidClassFactory $parameter, $ignoredParam)
9+
{
10+
11+
}
12+
13+
function non_existent_class_param(InvalidClass $parameter)
14+
{
15+
16+
}
17+
18+
}

spec/EntityGeneratorSpec.php renamed to spec/GeneratorWrapperSpec.php

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
namespace spec\EcomDev\PHPSpec\MagentoDiAdapter;
44

5-
use EcomDev\PHPSpec\MagentoDiAdapter\EntityGeneratorInterface;
65
use Magento\Framework\Code\Generator\EntityAbstract;
76
use PhpSpec\ObjectBehavior;
87
use Prophecy\Argument;
98

10-
class EntityGeneratorSpec extends ObjectBehavior
9+
class GeneratorWrapperSpec extends ObjectBehavior
1110
{
1211
/**
1312
* @var EntityAbstract
@@ -23,11 +22,6 @@ function () {},
2322
);
2423
}
2524

26-
function it_implements_entity_generator_interface()
27-
{
28-
$this->shouldImplement(EntityGeneratorInterface::class);
29-
}
30-
3125
function it_should_support_class_that_is_prefixed_with_suffix_in_argument()
3226
{
3327
// Supporting
@@ -43,7 +37,8 @@ function it_should_support_class_that_is_prefixed_with_suffix_in_argument()
4337
$this->supports('Some\EntityClass')->shouldReturn(false);
4438
}
4539

46-
function it_allow_suffixed_class_name_and_generates_it()
40+
41+
function it_generates_a_class_with_created_generator()
4742
{
4843
$this->entityGenerator->init('Some\Class', 'Some\ClassEntity')->shouldBeCalled();
4944
$this->entityGenerator->generate()->willReturn('path/to/SomeClassEntity.php')->shouldBeCalled();
@@ -52,12 +47,18 @@ function it_allow_suffixed_class_name_and_generates_it()
5247
$this->generate('Some\ClassEntity')->shouldReturn('path/to/SomeClassEntity.php');
5348
}
5449

55-
function it_allow_separated_class_name_in_subnamespace_and_generates_it()
50+
function it_allows_suffixed_class_name_in_subnamespace()
51+
{
52+
$this->entityGenerator->init('Some\Class', 'Some\ClassEntity')->shouldBeCalled();
53+
$this->beConstructedWith($this->entityFactoryClosure(), 'entity');
54+
$this->createGenerator('Some\ClassEntity')->shouldReturn($this->entityGenerator);
55+
}
56+
57+
function it_allows_separated_class_name_in_subnamespace()
5658
{
5759
$this->entityGenerator->init('Some\Class', 'Some\Class\Entity')->shouldBeCalled();
58-
$this->entityGenerator->generate()->willReturn('path/to/SomeClassEntity.php')->shouldBeCalled();
5960
$this->beConstructedWith($this->entityFactoryClosure(), 'entity');
60-
$this->generate('Some\Class\Entity')->shouldReturn('path/to/SomeClassEntity.php');
61+
$this->createGenerator('Some\Class\Entity')->shouldReturn($this->entityGenerator);
6162
}
6263

6364
private function entityFactoryClosure()

spec/ParameterValidatorSpec.php

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
namespace spec\EcomDev\PHPSpec\MagentoDiAdapter;
4+
5+
use EcomDev\PHPSpec\MagentoDiAdapter\Generator\SimplifiedDefinedClasses;
6+
use Magento\Framework\ObjectManager\Code\Generator;
7+
use Magento\Framework\Code\Generator\Io;
8+
use Magento\Framework\Filesystem\Driver\File;
9+
use org\bovigo\vfs\vfsStream;
10+
use org\bovigo\vfs\vfsStreamDirectory;
11+
use spec\EcomDev\PHPSpec\MagentoDiAdapter\Fixture\Catcher;
12+
use spec\EcomDev\PHPSpec\MagentoDiAdapter\Fixture\SignatureClass;
13+
use PhpSpec\ObjectBehavior;
14+
use Prophecy\Argument;
15+
16+
class ParameterValidatorSpec extends ObjectBehavior
17+
{
18+
/**
19+
* Root virtual directories
20+
*
21+
* @var vfsStreamDirectory
22+
*/
23+
private $vfs;
24+
25+
/**
26+
* Io for code generation
27+
*
28+
* @var Io
29+
*/
30+
private $io;
31+
32+
/**
33+
* Definer classes
34+
*
35+
* @var SimplifiedDefinedClasses
36+
*/
37+
private $definedClasses;
38+
39+
/**
40+
* Class reflection for autoload tests
41+
*
42+
* @var \ReflectionClass
43+
*/
44+
private $classReflection;
45+
46+
function let()
47+
{
48+
$this->vfs = vfsStream::setup('testcase');
49+
$this->io = new Io(new File(), $this->vfs->url());
50+
$this->definedClasses = new SimplifiedDefinedClasses();
51+
$this->classReflection = new \ReflectionClass(SignatureClass::class);
52+
53+
$this->beConstructedWith($this->io, $this->definedClasses);
54+
}
55+
56+
function it_is_possible_to_add_multiple_entity_generators()
57+
{
58+
$this->addGenerator(Generator\Factory::class, Generator\Factory::ENTITY_TYPE)->shouldReturn($this);
59+
$this->addGenerator(Generator\Repository::class, Generator\Repository::ENTITY_TYPE)->shouldReturn($this);
60+
61+
$this->generator('ClassFactory')->shouldImplement(Generator\Factory::class);
62+
$this->generator('ClassRepository')->shouldImplement(Generator\Repository::class);
63+
}
64+
65+
function it_is_possible_to_add_custom_generator_creation_closure(Catcher $catcher)
66+
{
67+
$catcher->invoke([
68+
'Some\Class',
69+
'Some\ClassFactory',
70+
$this->io,
71+
$this->definedClasses,
72+
Generator\Factory::class
73+
])->shouldBeCalled();
74+
75+
$this->addGenerator(Generator\Factory::class, Generator\Factory::ENTITY_TYPE, function () use ($catcher) {
76+
$catcher = $catcher->getWrappedObject();
77+
$catcher->invoke(func_get_args());
78+
return $catcher;
79+
})->shouldReturn($this);
80+
81+
$this->generator('Some\ClassFactory')->shouldBe($catcher);
82+
}
83+
84+
function it_returns_false_if_generator_does_not_exists_for_a_class()
85+
{
86+
$this->generator('Some\ClassFactory')->shouldReturn(false);
87+
}
88+
89+
function it_generates_a_class_via_generator_for_parameter_that_does_not_exits()
90+
{
91+
$functionReflection = $this->classReflection->getMethod('valid_class_factory_param');
92+
93+
$this->addGenerator(Generator\Factory::class, Generator\Factory::ENTITY_TYPE)->shouldReturn($this);
94+
95+
$this->validate($functionReflection)->shouldReturn($this);
96+
97+
$this->shouldCreateFile($this->vfs->url() . '/spec/EcomDev/PHPSpec/MagentoDiAdapter/Fixture/ValidClassFactory.php');
98+
}
99+
100+
function it_does_not_generate_a_class_for_which_we_do_not_have_a_rule()
101+
{
102+
$functionReflection = $this->classReflection->getMethod('non_existent_class_param');
103+
104+
$this->validate($functionReflection)->shouldReturn($this);
105+
106+
$this->shouldNotCreateFile($this->vfs->url() . '/spec/EcomDev/PHPSpec/MagentoDiAdapter/Fixture/InvalidClass.php');
107+
}
108+
109+
110+
111+
}

spec/Runner/CollaboratorMaintainerSpec.php

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,31 @@
22

33
namespace spec\EcomDev\PHPSpec\MagentoDiAdapter\Runner;
44

5-
use PhpSpec\Loader\Node\ExampleNode;
5+
use EcomDev\PHPSpec\MagentoDiAdapter\ParameterValidator;
6+
use PhpSpec\Loader\Node\SpecificationNode;
67
use PhpSpec\ObjectBehavior;
8+
use PhpSpec\Loader\Node\ExampleNode;
79
use PhpSpec\Runner\Maintainer\MaintainerInterface;
10+
use PhpSpec\Runner\CollaboratorManager;
11+
use PhpSpec\Runner\MatcherManager;
12+
use PhpSpec\SpecificationInterface;
813
use Prophecy\Argument;
914

1015
class CollaboratorMaintainerSpec extends ObjectBehavior
1116
{
17+
/**
18+
* Parameter validator
19+
*
20+
* @var ParameterValidator
21+
*/
22+
private $parameterValidator;
23+
24+
function let(ParameterValidator $parameterValidator)
25+
{
26+
$this->parameterValidator = $parameterValidator;
27+
$this->beConstructedWith($this->parameterValidator);
28+
}
29+
1230
function it_should_implement_maintainer_interface()
1331
{
1432
$this->shouldImplement(MaintainerInterface::class);
@@ -23,4 +41,62 @@ function it_has_higher_priority_than_current_collaborator_maintainer()
2341
{
2442
$this->getPriority()->shouldReturn(49);
2543
}
44+
45+
46+
function it_does_pass_regular_example_into_parameter_validator(
47+
ExampleNode $example,
48+
SpecificationInterface $context,
49+
MatcherManager $matchers,
50+
CollaboratorManager $collaborators,
51+
SpecificationNode $specificationNode,
52+
\ReflectionClass $reflectionClass
53+
)
54+
{
55+
56+
$example->getSpecification()->willReturn($specificationNode);
57+
$specificationNode->getClassReflection()->willReturn($reflectionClass);
58+
$reflectionClass->hasMethod('let')->willReturn(false);
59+
60+
$exampleClosureReflection = new \ReflectionFunction(function () {});
61+
$example->getFunctionReflection()->willReturn($exampleClosureReflection)->shouldBeCalled();
62+
$this->parameterValidator->validate($exampleClosureReflection)->shouldBeCalled();
63+
64+
$this->prepare($example, $context, $matchers, $collaborators)->shouldReturn($this);
65+
}
66+
67+
function it_does_pass_regular_example_into_parameter_validator_and_let_method_if_they_are_defined(
68+
ExampleNode $example,
69+
SpecificationInterface $context,
70+
MatcherManager $matchers,
71+
CollaboratorManager $collaborators,
72+
SpecificationNode $specificationNode,
73+
\ReflectionClass $reflectionClass
74+
)
75+
{
76+
$example->getSpecification()->willReturn($specificationNode);
77+
$specificationNode->getClassReflection()->willReturn($reflectionClass);
78+
$reflectionClass->hasMethod('let')->willReturn(true);
79+
80+
$exampleClosureReflection = new \ReflectionFunction(function () {});
81+
$letClosureReflection = new \ReflectionFunction(function () {});
82+
$reflectionClass->getMethod('let')->willReturn($letClosureReflection)->shouldBeCalled();
83+
$example->getFunctionReflection()->willReturn($exampleClosureReflection)->shouldBeCalled();
84+
85+
$this->parameterValidator->validate($letClosureReflection)->shouldBeCalled();
86+
$this->parameterValidator->validate($exampleClosureReflection)->shouldBeCalled();
87+
88+
$this->prepare($example, $context, $matchers, $collaborators)->shouldReturn($this);
89+
}
90+
91+
92+
93+
function it_does_not_have_anything_to_cleanup_on_teardown(
94+
ExampleNode $example,
95+
SpecificationInterface $context,
96+
MatcherManager $matchers,
97+
CollaboratorManager $collaborators
98+
)
99+
{
100+
$this->teardown($example, $context, $matchers, $collaborators)->shouldReturn($this);
101+
}
26102
}

src/EntityGeneratorInterface.php

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/EntityGenerator.php renamed to src/GeneratorWrapper.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22

33
namespace EcomDev\PHPSpec\MagentoDiAdapter;
44

5-
class EntityGenerator implements EntityGeneratorInterface
5+
use Magento\Framework\Code\Generator\EntityAbstract;
6+
7+
/**
8+
* Wrapper for Magento native DI generators to simplify testing
9+
*/
10+
class GeneratorWrapper
611
{
712
/**
813
* Abstract entity code generator
@@ -50,10 +55,22 @@ public function supports($className)
5055
* @return bool|string
5156
*/
5257
public function generate($className)
58+
{
59+
return $this->createGenerator($className)->generate();
60+
}
61+
62+
/**
63+
* Creates a generator
64+
*
65+
* @param string $className
66+
*
67+
* @return EntityAbstract
68+
*/
69+
public function createGenerator($className)
5370
{
5471
$factory = $this->generatorFactory;
5572
$sourceClass = rtrim(substr($className, 0, strpos($className, ucfirst($this->classSuffix))), '\\');
5673
$entityGenerator = $factory($sourceClass, $className);
57-
return $entityGenerator->generate();
74+
return $entityGenerator;
5875
}
5976
}

0 commit comments

Comments
 (0)