initial commit

This commit is contained in:
Marco Stoll 2019-06-12 12:51:46 +02:00
commit 5dac7ad856
17 changed files with 2620 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.idea/
/vendor
todos.md

36
composer.json Normal file
View File

@ -0,0 +1,36 @@
{
"name": "fastforward/factories",
"description": "A component providing a factory pattern implementation - part of the Fast Forward Components Collection",
"type": "library",
"license": "MIT",
"minimum-stability": "stable",
"authors": [
{
"name": "Marco Stoll",
"email": "marco@fast-forward-encoding.de",
"homepage": "http://marcostoll.de",
"role": "Developer"
}
],
"require": {
"php": ">=7.2",
"fastforward/utils": "^1.0.0"
},
"require-dev": {
"phpunit/phpunit": "^8"
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/marcostoll/FF-Utils"
}
],
"autoload": {
"psr-4": {
"FF\\Factories\\": "src/"
},
"classmap": [
"src/"
]
}
}

1588
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

22
license.md Normal file
View File

@ -0,0 +1,22 @@
MIT License
===============================================================================
Copyright (c) 2019-forever Marco Stoll <marco@fast-forward-encoding.de>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

120
readme.md Normal file
View File

@ -0,0 +1,120 @@
FF\Factories | Fast Forward Components Collection
===============================================================================
by Marco Stoll
- <marco.stoll@rocketmail.com>
- <http://marcostoll.de>
- <https://github.com/marcostoll>
- <https://github.com/marcostoll/FF-Common>
------------------------------------------------------------------------------------------------------------------------
# What is the Fast Forward Components Collection?
The Fast Forward Components Collection, in short **Fast Forward** or **FF**, is a loosely coupled collection of code
repositories each addressing common problems while building web application. Multiple **FF** components may be used
together if desired. And some more complex **FF** components depend on other rather basic **FF** components.
**FF** is not a framework in and of itself and therefore should not be called so.
But you may orchestrate multiple **FF** components to build an web application skeleton that provides the most common
tasks.
# Introduction
The Common component provides generic functionality used by many other **FF** components. You seldom want to require
this library by itself. In most cases you will get it by requiring one of the more complex **FF** components.
# The Factories
The `AbstractFactory` provides logic to introduce factory-style object instantiation. By configuring it with a
designated class locator you may invoke its `create()` method with a class identifier and the necessary constructor
arguments to get a fresh instance of this class.
The factory will instruct the its class locator to detect a suitable class definition and after that will invoke the
class's constructor and return the object.
An example:
namespace MyProject\Views\Helpers;
use FF\Factories\AbstractFactory;
use FF\Factories\ClassLocators\NamespaceClassLocator;
/**
* Definition of Helpers Factory
*/
class MyHelpersFactory extends AbstractFactory
{
public function __construct()
{
// configure the factory with its own namespace
// to search for Helper class
parent::__construct(new NamespaceClassLocator(__NAMESPACE__));
}
}
...
// Will get a MyViewHelper instance assumed the a MyProject\Views\Helpers\MyViewHelper class exists.
// In this example $arg1 and $arg2 will be passed to the MyViewHelper class's constructor in the given order.
$myHelper = $myHelpersFactory->create('MyViewHelper', $arg1, $arg2);
The `AbstractSingletonFactory` extends this behaviour by adding a singleton pattern to its implementation that will
ensure that an instance of a class identified by its identifier will only be instantiated a single time.
So any additional call to its `create()` method will return the same instance as the first time.
**Beware**: Only the class identifier will be taken into account for identifying already instantiated objects. Varying
any constructor arguments will not lead to generating new object instances.
# The Class Locators
Class locators implement various strategies to derive full-qualified class names based on a shorter class identifier.
Each class locator defines a different convention for specifying class identifiers and the logic to detect suitable
class definitions based on this.
## The Namespace Class Locator
This class locator can be configured with a list of base namespaces ro search for class definitions with a class
identifier relative to one of its base namespaces.
The base namespaces wil be search in the give order. So the locator will return the first match of an existing class.
An example:
use FF\Factories\ClassLocators\NamespaceClassLocator;
$myLocator = new NamespaceClassLocator('MyProject\Sub1', ''MyProject\Sub2');
// This will find MyProject\Sub1\MyClass or MyProject\Sub2\MyClass in this order.
// If none of the above exist, $class will be null.
$class = $myLocator->locateClass('MyClass');
// This will find MyProject\Sub1\Foo\MyClass or MyProject\Sub2\Foo\MyClass in this order.
// If none of the above exist, $class will be null.
$class = $myLocator->locateClass('Foo\MyClass');
## The Namespace Prefixed Class Locator
Sometimes you want to distribute class definitions of a certain kind (say Event classes) over various packages. To
provide a factory capable of creating this events objects you may use the `NamespacePrefixedClassLocator`. This
locator enforces you to place your various class definitions within a common class namespace prefix.
An example:
use FF\Factories\ClassLocators\NamespacePrefixedClassLocator;
// The first argumens ('Events') is the common class namespace prefix.
// The following argumentgs are the base namespaces to inspect.
$myLocator = new NamespaceClassLocator('Events', MyProject\Sub1', ''MyProject\Sub2');
// This will find MyProject\Sub1\Events\MyEvent or MyProject\Sub2\Events\MyEven in this order.
// If none of the above exist, $class will be null.
$class = $myLocator->locateClass('MyEvent');
// This will find MyProject\Sub1\Foo\Events\MyEvent or MyProject\Sub2\Foo\Events\MyEvent in this order.
// If none of the above exist, $class will be null.
$class = $myLocator->locateClass('Foo\MyEvent');
# Road map
The extend of the **Factories** component is mainly driven by the needs of other **FF** components, so not concrete
features are planned at this time. The component surely will grow as other **FF** components require additional logic
that is not part of their domain.

84
src/AbstractFactory.php Normal file
View File

@ -0,0 +1,84 @@
<?php
/**
* Definition of AbstractFactory
*
* @author Marco Stoll <marco@fast-forward-encoding.de>
* @copyright 2019-forever Marco Stoll
* @filesource
*/
declare(strict_types=1);
namespace FF\Factories;
use FF\Factories\Exceptions\ClassNotFoundException;
use FF\Factories\Exceptions\InstantiationException;
use FF\Factories\ClassLocators\ClassLocatorInterface;
/**
* Class AbstractFactory
*
* @package FF\Factories
*/
abstract class AbstractFactory
{
/**
* @var ClassLocatorInterface
*/
protected $classLocator;
/**
* @param ClassLocatorInterface $classLocator
*/
public function __construct(ClassLocatorInterface $classLocator)
{
$this->classLocator = $classLocator;
}
/**
* Creates an object instance of a suitable class
*
* Any arguments provided will be passed to the class's constructor.
* The amount and order of the $args given must match the constructor signature of the class to instantiate.
*
* @param string $classIdentifier
* @param array $args
* @return object
* @throws ClassNotFoundException no suitable class definition found
* @throws InstantiationException error while trying to instantiate object
*/
public function create(string $classIdentifier, ...$args)
{
$fqClassName = $this->classLocator->locateClass($classIdentifier);
if (is_null($fqClassName)) {
throw new ClassNotFoundException('no suitable class definition found for [' . $classIdentifier . ']');
}
try {
return (new \ReflectionClass($fqClassName))->newInstance(...$args);
} catch (\ReflectionException $e) {
throw new InstantiationException(
'error while trying to instantiate object of class [' . $fqClassName . ']',
0,
$e
);
}
}
/**
* @return ClassLocatorInterface
*/
public function getClassLocator(): ClassLocatorInterface
{
return $this->classLocator;
}
/**
* @param ClassLocatorInterface $classLocator
* @return AbstractFactory
*/
public function setClassLocator(ClassLocatorInterface $classLocator)
{
$this->classLocator = $classLocator;
return $this;
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* Definition of AbstractSingletonFactory
*
* @author Marco Stoll <marco@fast-forward-encoding.de>
* @copyright 2019-forever Marco Stoll
* @filesource
*/
declare(strict_types=1);
namespace FF\Factories;
/**
* Class AbstractSingletonFactory
*
* @package FF\Factories
*/
abstract class AbstractSingletonFactory extends AbstractFactory
{
/**
* @var array
*/
protected $instanceCache = [];
/**
* {@inheritdoc}
*
* Successfully created instances will be stored within the instance cache using their $classIdentifier as key.
* Retrieves the object from the instance cache if already present. If not, attempts to create it.
*/
public function create(string $classIdentifier, ...$args)
{
// check instance cache first
if (isset($this->instanceCache[$classIdentifier])) {
return $this->instanceCache[$classIdentifier];
}
$instance = parent::create($classIdentifier, ...$args);
$this->instanceCache[$classIdentifier] = $instance;
return $instance;
}
/**
* Clears all created instances from the cache
*
* @return $this
*/
public function clearInstanceCache()
{
$this->instanceCache = [];
return $this;
}
}

View File

@ -0,0 +1,29 @@
<?php
/**
* Definition of ClassLocatorInterface
*
* @author Marco Stoll <marco@fast-forward-encoding.de>
* @copyright 2019-forever Marco Stoll
* @filesource
*/
declare(strict_types=1);
namespace FF\Factories\ClassLocators;
/**
* Interface ClassLocatorInterface
*
* @package FF\Factories\ClassLocators
*/
interface ClassLocatorInterface
{
/**
* Locates a full-qualified class name using the given identifier
*
* Returns null if no suitable class found.
*
* @param string $classIdentifier
* @return string|null
*/
public function locateClass(string $classIdentifier): ?string;
}

View File

@ -0,0 +1,118 @@
<?php
/**
* Definition of NamespaceClassLocator
*
* @author Marco Stoll <marco@fast-forward-encoding.de>
* @copyright 2019-forever Marco Stoll
* @filesource
*/
declare(strict_types=1);
namespace FF\Factories\ClassLocators;
use FF\Utils\ClassUtils;
/**
* Class NamespaceClassLocator
*
* Expects a class name relative to any of the registered namespaces as class identifier.
*
* Example 1:
* Registered namespace: 'FF\Forms\Fields'
* valid $classIdentifiers:
* - 'TextField' => finds FF\Forms\Fields\TextField
* - 'RadioField' => finds FF\Forms\Fields\RadioField
*
* Example 2:
* Registered namespace: 'FF\Forms'
* valid $classIdentifiers:
* - 'Fields\TextField' => finds FF\Forms\Fields\TextField
* - 'Fields\RadioField' => finds FF\Forms\Fields\RadioField
*
* "Going up" in the namespace path by using '..\\' will not work.
*
* @package FF\Factories\ClassLocators
*/
class NamespaceClassLocator implements ClassLocatorInterface
{
/**
* @var string[]
*/
protected $namespaces = [];
/**
* @param string[] $namespaces
*/
public function __construct(string ...$namespaces)
{
$this->setNamespaces($namespaces);
}
/**
* Locates a full-qualified class name using the given identifier
*
* Returns null if no suitable class found.
*
* @param string $classIdentifier
* @return string|null
*/
public function locateClass(string $classIdentifier): ?string
{
foreach ($this->namespaces as $ns) {
$fqClassname = $this->buildFqClassName($ns, $classIdentifier);
if (!class_exists($fqClassname)) continue;
return $fqClassname;
}
return null;
}
/**
* @return string[]
*/
public function getNamespaces(): array
{
return $this->namespaces;
}
/**
* @param array $namespaces
* @return $this
*/
public function setNamespaces(array $namespaces)
{
$this->normalizeNamespaces($namespaces);
$this->namespaces = $namespaces;
return $this;
}
/**
* @param string[] $namespaces
* @return $this
*/
public function prependNamespaces(string ...$namespaces)
{
$this->normalizeNamespaces($namespaces);
$this->namespaces = array_merge($namespaces, $this->namespaces);
return $this;
}
/**
* @param string $ns
* @param string $classIdentifier
* @return string
*/
protected function buildFqClassName(string $ns, string $classIdentifier): string
{
return $ns . '\\' . $classIdentifier;
}
/**
* @param array $namespaces
*/
protected function normalizeNamespaces(array &$namespaces)
{
array_walk($namespaces, [ClassUtils::class, 'normalizeNamespace']);
}
}

View File

@ -0,0 +1,84 @@
<?php
/**
* Definition of NamespacePrefixedClassLocator
*
* @author Marco Stoll <marco@fast-forward-encoding.de>
* @copyright 2019-forever Marco Stoll
* @filesource
*/
declare(strict_types=1);
namespace FF\Factories\ClassLocators;
use FF\Utils\ClassUtils;
/**
* Class NamespacePrefixedClassLocator
*
* Expects a class name prefixed by a specific path relative to any of the registered namespaces as class identifier.
*
* Example 1:
* Registered namespace: 'FF\Runtime'
* $prefix: 'Events'
* valid $classIdentifiers:
* - 'OnError' => finds FF\Runtime\Events\OnError
*
* Example 2:
* Registered namespace: 'FF'
* $prefix: 'Events'
* valid $classIdentifiers:
* - 'Runtime\OnError' => finds FF\Runtime\Events\OnError
*
* "Going up" in the namespace path by using '..\\' will not work.
*
* @package FF\Factories\ClassLocators
*/
class NamespacePrefixedClassLocator extends NamespaceClassLocator
{
/**
* @var string
*/
protected $prefix;
/**
* @param string $prefix
* @param string[] $namespaces
*/
public function __construct(string $prefix, string ...$namespaces)
{
parent::__construct(...$namespaces);
$this->prefix = $prefix;
}
/**
* @return string
*/
public function getPrefix(): string
{
return $this->prefix;
}
/**
* @param string $prefix
* @return $this
*/
public function setPrefix(string $prefix)
{
$this->prefix = ClassUtils::normalizeNamespace($prefix);
return $this;
}
/**
* @param string $ns
* @param string $classIdentifier
* @return string
*/
protected function buildFqClassName(string $ns, string $classIdentifier): string
{
$classPath = explode('\\', ClassUtils::normalizeNamespace($classIdentifier));
$localClassName = array_pop($classPath);
$subNs = !empty($classPath) ? implode('\\', $classPath) . '\\' : '';
return $ns . '\\' . $subNs . $this->prefix . '\\' . $localClassName;
}
}

View File

@ -0,0 +1,21 @@
<?php
/**
* Definition of ClassNotFoundException
*
* @author Marco Stoll <marco@fast-forward-encoding.de>
* @copyright 2019-forever Marco Stoll
* @filesource
*/
declare(strict_types=1);
namespace FF\Factories\Exceptions;
/**
* Class ClassNotFoundException
*
* @package FF\Factories\Exceptions
*/
class ClassNotFoundException extends \RuntimeException
{
}

View File

@ -0,0 +1,21 @@
<?php
/**
* Definition of InstantiationException
*
* @author Marco Stoll <marco@fast-forward-encoding.de>
* @copyright 2019-forever Marco Stoll
* @filesource
*/
declare(strict_types=1);
namespace FF\Factories\Exceptions;
/**
* Class InstantiationException
*
* @package FF\Factories\Exceptions
*/
class InstantiationException extends \RuntimeException
{
}

View File

@ -0,0 +1,136 @@
<?php
/**
* Definition of AbstractFactoryTest
*
* @author Marco Stoll <marco@fast-forward-encoding.de>
* @copyright 2019-forever Marco Stoll
* @filesource
*/
declare(strict_types=1);
namespace FF\Tests\Factories
{
use FF\Factories\AbstractFactory;
use FF\Factories\ClassLocators\NamespaceClassLocator;
use FF\Factories\Exceptions\ClassNotFoundException;
use FF\Tests\Factories\Sub\MySubObject;
use PHPUnit\Framework\TestCase;
/**
* Test AbstractFactoryTest
*
* @package FF\Tests
*/
class AbstractFactoryTest extends TestCase
{
/**
* @var MyFactory
*/
protected $uut;
/**
* {@inheritdoc}
*/
protected function setUp(): void
{
$this->uut = new MyFactory();
}
/**
* Tests the namesake method/feature
*/
public function testSetGetClassLocator()
{
$value = new NamespaceClassLocator();
$same = $this->uut->setClassLocator($value);
$this->assertSame($this->uut, $same);
$this->assertEquals($value, $this->uut->getClassLocator());
}
/**
* Tests the namesake method/feature
*/
public function testCreate()
{
/** @var MyObject $obj */
$obj = $this->uut->create('MyObject', 'foo', true);
$this->assertInstanceOf(MyObject::class, $obj);
$this->assertEquals('foo', $obj->arg1);
$this->assertTrue($obj->arg2);
}
/**
* Tests the namesake method/feature
*/
public function testCreateSubNamespace()
{
/** @var MySubObject $obj */
$obj = $this->uut->create('Sub\\MySubObject', 'foo', true);
$this->assertInstanceOf(MySubObject::class, $obj);
}
/**
* Tests the namesake method/feature
*/
public function testCreateWithInsufficientArgs()
{
$this->expectException(\ArgumentCountError::class);
$this->uut->create('MyObject', 'foo');
}
/**
* Tests the namesake method/feature
*/
public function testCreateUnknown()
{
$this->expectException(ClassNotFoundException::class);
$this->uut->create('foo');
}
}
class MyFactory extends AbstractFactory
{
/**
* Set to protected to prevent client instantiation.
*/
public function __construct()
{
parent::__construct(new NamespaceClassLocator(__NAMESPACE__));
}
}
class MyObject
{
/**
* @var string
*/
public $arg1;
/**
* @var bool
*/
public $arg2;
/**
* @param string $arg1
* @param bool $arg2
*/
public function __construct(string $arg1, bool $arg2)
{
$this->arg1 = $arg1;
$this->arg2 = $arg2;
}
}
}
namespace FF\Tests\Factories\Sub {
use FF\Tests\Factories\MyObject;
class MySubObject extends MyObject
{
}
}

View File

@ -0,0 +1,80 @@
<?php
/**
* Definition of AbstractSingletonFactoryTest
*
* @author Marco Stoll <marco@fast-forward-encoding.de>
* @copyright 2019-forever Marco Stoll
* @filesource
*/
declare(strict_types=1);
namespace FF\Tests\Factories;
use FF\Factories\AbstractSingletonFactory;
use FF\Factories\ClassLocators\NamespaceClassLocator;
use PHPUnit\Framework\TestCase;
/**
* Test AbstractSingletonFactoryTest
*
* @package FF\Tests
*/
class AbstractSingletonFactoryTest extends TestCase
{
/**
* @var MySingletonFactory
*/
protected $uut;
/**
* {@inheritdoc}
*/
protected function setUp(): void
{
$this->uut = new MySingletonFactory();
}
/**
* Tests the namesake method/feature
*/
public function testCreateSingleton()
{
/** @var MySingletonObject $obj1 */
$obj1 = $this->uut->create('MySingletonObject');
/** @var MySingletonObject $obj2 */
$obj2 = $this->uut->create('MySingletonObject');
$this->assertSame($obj1, $obj2);
}
/**
* Tests the namesake method/feature
*/
public function testClearInstanceCache()
{
/** @var MySingletonObject $obj1 */
$obj1 = $this->uut->create('MySingletonObject');
$same = $this->uut->clearInstanceCache();
$this->assertSame($this->uut, $same);
/** @var MySingletonObject $obj2 */
$obj2 = $this->uut->create('MySingletonObject');
$this->assertNotSame($obj1, $obj2);
}
}
class MySingletonFactory extends AbstractSingletonFactory
{
/**
* Set to protected to prevent client instantiation.
*/
public function __construct()
{
parent::__construct(new NamespaceClassLocator(__NAMESPACE__));
}
}
class MySingletonObject
{
}

View File

@ -0,0 +1,118 @@
<?php
/**
* Definition of NamespaceClassLocatorTest
*
* @author Marco Stoll <marco@fast-forward-encoding.de>
* @copyright 2019-forever Marco Stoll
* @filesource
*/
declare(strict_types=1);
namespace FF\Tests\Factories\ClassLocators
{
use FF\Factories\ClassLocators\NamespaceClassLocator;
use FF\Tests\Factories\ClassLocators\Sub\MySubObject;
use PHPUnit\Framework\TestCase;
/**
* Test NamespaceClassLocatorTest
*
* @package FF\Tests
*/
class NamespaceClassLocatorTest extends TestCase
{
/**
* @var NamespaceClassLocator
*/
protected $uut;
/**
* @var string[]
*/
protected $namespaceCache = [];
/**
* {@inheritdoc}
*/
protected function setUp(): void
{
$this->uut = new NamespaceClassLocator(__NAMESPACE__);
$this->namespaceCache = $this->uut->getNamespaces();
}
/**
* {@inheritdoc}
*/
protected function tearDown(): void
{
$this->uut->setNamespaces($this->namespaceCache);
}
/**
* Tests the namesake method/feature
*/
public function testSetGetNamespaces()
{
$value = ['foo', 'bar'];
$same = $this->uut->setNamespaces($value);
$this->assertSame($this->uut, $same);
$this->assertEquals($value, $this->uut->getNamespaces());
}
/**
* Tests the namesake method/feature
*/
public function testPrependNamespaces()
{
$same = $this->uut->setNamespaces(['foo', 'bar'])->prependNamespaces('baz');
$this->assertSame($this->uut, $same);
$this->assertEquals('baz', $this->uut->getNamespaces()[0]);
$this->assertEquals(3, count($this->uut->getNamespaces()));
}
/**
* Tests the namesake method/feature
*/
public function testLocateClass()
{
$result = $this->uut->locateClass('MyObject');
$this->assertEquals(MyObject::class, $result);
$result = $this->uut->locateClass('Sub\MySubObject');
$this->assertEquals(MySubObject::class, $result);
}
/**
* Tests the namesake method/feature
*/
public function testLocateClassNotFound()
{
$result = $this->uut->locateClass('Foo');
$this->assertNull($result);
}
/**
* Tests the namesake method/feature
*/
public function testLocateClassNotFoundUpFailure()
{
$result = $this->uut->locateClass('Sub\\..\\MyObject');
$this->assertNull($result);
}
}
class MyObject
{
}
}
namespace FF\Tests\Factories\ClassLocators\Sub {
use FF\Tests\Factories\ClassLocators\MyObject;
class MySubObject extends MyObject
{
}
}

View File

@ -0,0 +1,95 @@
<?php
/**
* Definition of NamespacePrefixedClassLocatorTest
*
* @author Marco Stoll <marco@fast-forward-encoding.de>
* @copyright 2019-forever Marco Stoll
* @filesource
*/
declare(strict_types=1);
namespace FF\Tests\Factories\ClassLocators
{
use FF\Factories\ClassLocators\NamespacePrefixedClassLocator;
use FF\Tests\Factories\ClassLocators\Foo\MyFooObject;
use FF\Tests\Factories\ClassLocators\Sub\Foo\MySubFooObject;
use PHPUnit\Framework\TestCase;
/**
* Test NamespacePrefixedClassLocatorTest
*
* @package FF\Tests
*/
class NamespacePrefixedClassLocatorTest extends TestCase
{
/**
* @var NamespacePrefixedClassLocator
*/
protected $uut;
/**
* {@inheritdoc}
*/
protected function setUp(): void
{
$this->uut = new NamespacePrefixedClassLocator('Foo', __NAMESPACE__);
}
/**
* Tests the namesake method/feature
*/
public function testSetGetPrefix()
{
$value = 'foo';
$same = $this->uut->setPrefix($value);
$this->assertSame($this->uut, $same);
$this->assertEquals($value, $this->uut->getPrefix());
}
/**
* Tests the namesake method/feature
*/
public function testLocateClass()
{
$result = $this->uut->locateClass('MyFooObject');
$this->assertEquals(MyFooObject::class, $result);
$result = $this->uut->locateClass('Sub\MySubFooObject');
$this->assertEquals(MySubFooObject::class, $result);
}
/**
* Tests the namesake method/feature
*/
public function testLocateClassNotFound()
{
$result = $this->uut->locateClass('Foo');
$this->assertNull($result);
}
/**
* Tests the namesake method/feature
*/
public function testLocateClassNotFoundUpFailure()
{
$result = $this->uut->locateClass('Sub\\..\\MyFooObject');
$this->assertNull($result);
}
}
}
namespace FF\Tests\Factories\ClassLocators\Foo {
class MyFooObject
{
}
}
namespace FF\Tests\Factories\ClassLocators\Sub\Foo {
class MySubFooObject
{
}
}

8
tests/testsuite.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit>
<testsuites>
<testsuite name="FastForward">
<directory>./</directory>
</testsuite>
</testsuites>
</phpunit>