diff --git a/src/Type.php b/src/Type.php new file mode 100644 index 0000000..33ca559 --- /dev/null +++ b/src/Type.php @@ -0,0 +1,18 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection; + +interface Type +{ + public function __toString(); +} diff --git a/src/Types/Array_.php b/src/Types/Array_.php new file mode 100644 index 0000000..ffb364a --- /dev/null +++ b/src/Types/Array_.php @@ -0,0 +1,63 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +class Array_ implements Type +{ + /** @var Type */ + private $valueType; + + /** @var Type */ + private $keyType; + + public function __construct(Type $valueType = null, Type $keyType = null) + { + if ($keyType === null) { + $keyType = new Mixed(); + } + if ($valueType === null) { + $valueType = new Mixed(); + } + + $this->valueType = $valueType; + $this->keyType = $keyType; + } + + /** + * @return Type + */ + public function getKeyType() + { + return $this->keyType; + } + + /** + * @return Type + */ + public function getValueType() + { + return $this->valueType; + } + + public function __toString() + { + if ($this->valueType instanceof Mixed) { + return 'array'; + } + + return $this->valueType . '[]'; + } +} diff --git a/src/Types/Boolean.php b/src/Types/Boolean.php new file mode 100644 index 0000000..08db91c --- /dev/null +++ b/src/Types/Boolean.php @@ -0,0 +1,23 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +final class Boolean implements Type +{ + public function __toString() + { + return 'bool'; + } +} diff --git a/src/Types/Callable_.php b/src/Types/Callable_.php new file mode 100644 index 0000000..4479a93 --- /dev/null +++ b/src/Types/Callable_.php @@ -0,0 +1,23 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +final class Callable_ implements Type +{ + public function __toString() + { + return 'callable'; + } +} diff --git a/src/Types/Collection.php b/src/Types/Collection.php new file mode 100644 index 0000000..796d9e7 --- /dev/null +++ b/src/Types/Collection.php @@ -0,0 +1,113 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Types\Resolver; +use phpDocumentor\Reflection\DocBlock\Context; + +/** + * Collection + */ +class Collection extends \ArrayObject +{ + /** @var string Definition of the OR operator for types */ + const OPERATOR_OR = '|'; + + /** + * Current invoking location. + * + * This is used to prepend to type with a relative location. + * May also be 'default' or 'global', in which case they are ignored. + * + * @var Context + */ + protected $context = null; + /** + * @var Resolver + */ + private $resolver; + + /** + * Registers the namespace and aliases; uses that to add and expand the given types. + * + * @param string[] $types Array containing a list of types to add to this container. + * @param Context $context + * @param Resolver $resolver + */ + public function __construct(array $types = array(), Context $context = null, Resolver $resolver = null) + { + $this->context = $context ?: new Context(''); + $this->resolver = $resolver ?: new Resolver(); + + foreach ($types as $type) { + $this->add($type); + } + } + + /** + * Returns the current invoking location. + * + * @return Context + */ + public function getContext() + { + return $this->context; + } + + /** + * Adds a new type to the collection and expands it if it contains a + * relative namespace. + * + * If a class in the type contains a relative namespace than this collection + * will try to expand that into a FQCN. + * + * @param string $type A 'Type' as defined in the phpDocumentor + * documentation. + * + * @throws \InvalidArgumentException if a non-string argument is passed. + * + * @see http://phpdoc.org/docs/latest/for-users/types.html for the + * definition of a type. + * + * @return void + */ + public function add($type) + { + if (!is_string($type)) { + throw new \InvalidArgumentException( + 'A type should be represented by a string, received: ' + . var_export($type, true) + ); + } + + // separate the type by the OR operator + $type_parts = explode(self::OPERATOR_OR, $type); + foreach ($type_parts as $part) { + $expanded_type = $this->resolver->resolve($part, $this->context); + if ($expanded_type) { + $this[] = $expanded_type; + } + } + } + + /** + * Returns a string representation of the collection. + * + * @return string The resolved types across the collection, separated with + * {@link self::OPERATOR_OR}. + */ + public function __toString() + { + return implode(self::OPERATOR_OR, $this->getArrayCopy()); + } +} diff --git a/src/Types/Compound.php b/src/Types/Compound.php new file mode 100644 index 0000000..5421ede --- /dev/null +++ b/src/Types/Compound.php @@ -0,0 +1,60 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Fqsen; +use phpDocumentor\Reflection\Type; + +final class Compound implements Type +{ + /** @var Type[] */ + private $types = []; + + /** + * @param Type[]|Fqsen[] $types + */ + public function __construct($types) + { + $this->types = $types; + } + + /** + * @param integer $index + * + * @return null|Type|Fqsen + */ + public function get($index) + { + if (!$this->has($index)) { + return null; + } + + return $this->types[$index]; + } + + /** + * @param integer $index + * + * @return bool + */ + public function has($index) + { + return isset($this->types[$index]); + } + + public function __toString() + { + return implode('|', $this->types); + } +} diff --git a/src/Types/Float.php b/src/Types/Float.php new file mode 100644 index 0000000..a51dcaa --- /dev/null +++ b/src/Types/Float.php @@ -0,0 +1,23 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +final class Float implements Type +{ + public function __toString() + { + return 'float'; + } +} diff --git a/src/Types/Integer.php b/src/Types/Integer.php new file mode 100644 index 0000000..99c8f96 --- /dev/null +++ b/src/Types/Integer.php @@ -0,0 +1,23 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +final class Integer implements Type +{ + public function __toString() + { + return 'int'; + } +} diff --git a/src/Types/Mixed.php b/src/Types/Mixed.php new file mode 100644 index 0000000..904315b --- /dev/null +++ b/src/Types/Mixed.php @@ -0,0 +1,23 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +final class Mixed implements Type +{ + public function __toString() + { + return 'mixed'; + } +} diff --git a/src/Types/Null_.php b/src/Types/Null_.php new file mode 100644 index 0000000..6a78cb8 --- /dev/null +++ b/src/Types/Null_.php @@ -0,0 +1,23 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +final class Null_ implements Type +{ + public function __toString() + { + return 'null'; + } +} diff --git a/src/Types/Object_.php b/src/Types/Object_.php new file mode 100644 index 0000000..77cecb0 --- /dev/null +++ b/src/Types/Object_.php @@ -0,0 +1,23 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +final class Object_ implements Type +{ + public function __toString() + { + return 'object'; + } +} diff --git a/src/Types/Resolver.php b/src/Types/Resolver.php new file mode 100644 index 0000000..451bbb0 --- /dev/null +++ b/src/Types/Resolver.php @@ -0,0 +1,251 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\DocBlock\Context; +use phpDocumentor\Reflection\Fqsen; +use phpDocumentor\Reflection\Type; + +class Resolver +{ + /** @var string Definition of the ARRAY operator for types */ + const OPERATOR_ARRAY = '[]'; + + /** @var string Definition of the NAMESPACE operator in PHP */ + const OPERATOR_NAMESPACE = '\\'; + + /** @var string[] List of recognized keywords and unto which Value Object they map */ + private $keywords = array( + 'string' => 'phpDocumentor\Reflection\Types\String', + 'int' => 'phpDocumentor\Reflection\Types\Integer', + 'integer' => 'phpDocumentor\Reflection\Types\Integer', + 'bool' => 'phpDocumentor\Reflection\Types\Boolean', + 'boolean' => 'phpDocumentor\Reflection\Types\Boolean', + 'float' => 'phpDocumentor\Reflection\Types\Float', + 'double' => 'phpDocumentor\Reflection\Types\Float', + 'object' => 'phpDocumentor\Reflection\Types\Object_', + 'mixed' => 'phpDocumentor\Reflection\Types\Mixed', + 'array' => 'phpDocumentor\Reflection\Types\Array_', + 'resource' => 'phpDocumentor\Reflection\Types\Resource', + 'void' => 'phpDocumentor\Reflection\Types\Void', + 'null' => 'phpDocumentor\Reflection\Types\Null_', + 'scalar' => 'phpDocumentor\Reflection\Types\Scalar', + 'callback' => 'phpDocumentor\Reflection\Types\Callable_', + 'callable' => 'phpDocumentor\Reflection\Types\Callable_', + 'false' => 'phpDocumentor\Reflection\Types\Boolean', + 'true' => 'phpDocumentor\Reflection\Types\Boolean', + 'self' => 'phpDocumentor\Reflection\Types\Self_', + '$this' => 'phpDocumentor\Reflection\Types\This', + 'static' => 'phpDocumentor\Reflection\Types\Static_' + ); + + /** + * Analyzes the given type and returns the FQCN variant. + * + * When a type is provided this method checks whether it is not a keyword or + * Fully Qualified Class Name. If so it will use the given namespace and + * aliases to expand the type to a FQCN representation. + * + * This method only works as expected if the namespace and aliases are set; + * no dynamic reflection is being performed here. + * + * @param string $type The relative or absolute type. + * + * @uses Context::getNamespace() to determine with what to prefix the type name. + * @uses Context::getNamespaceAliases() to check whether the first part of the relative type name should not be + * replaced with another namespace. + * + * @return Fqsen|Type|null + */ + public function resolve($type, Context $context) + { + if (!is_string($type)) { + throw new \InvalidArgumentException( + 'Attempted to resolve type but it appeared not to be a string, received: ' . var_export($type, true) + ); + } + + $type = trim($type); + if (!$type) { + throw new \InvalidArgumentException('Attempted to resolve "' . $type . '" but it appears to be empty'); + } + + switch (true) { + case $this->isKeyword($type): + return $this->resolveKeyword($type); + case ($this->isCompoundType($type)): + return $this->resolveCompoundType($type, $context); + case $this->isFqsen($type): + return $this->resolveFqsen($type); + case $this->isTypedArray($type): + return $this->resolveTypedArray($type, $context); + case $this->isPartialStructuralElementName($type): + return $this->resolvePartialStructuralElementName($type, $context); + // @codeCoverageIgnoreStart + default: + // I haven't got the foggiest how the logic would come here but added this as a defense. + throw new \RuntimeException( + 'Unable to resolve type "' . $type . '", there is no known method to resolve it' + ); + } + // @codeCoverageIgnoreEnd + } + + /** + * Detects whether the given type represents an array. + * + * @param string $type A relative or absolute type as defined in the phpDocumentor documentation. + * + * @return bool + */ + private function isTypedArray($type) + { + return substr($type, -2) === self::OPERATOR_ARRAY; + } + + /** + * Detects whether the given type represents a PHPDoc keyword. + * + * @param string $type A relative or absolute type as defined in the phpDocumentor documentation. + * + * @return bool + */ + private function isKeyword($type) + { + return in_array(strtolower($type), array_keys($this->keywords), true); + } + + /** + * Detects whether the given type represents a relative structural element name. + * + * @param string $type A relative or absolute type as defined in the phpDocumentor documentation. + * + * @return bool + */ + private function isPartialStructuralElementName($type) + { + return ($type[0] !== self::OPERATOR_NAMESPACE) && !$this->isKeyword($type); + } + + /** + * Tests whether the given type is a Fully Qualified Structural Element Name. + * + * @param string $type + * + * @return bool + */ + private function isFqsen($type) + { + return strpos($type, self::OPERATOR_NAMESPACE) === 0; + } + + /** + * Tests whether the given type is a compound type (i.e. `string|int`). + * + * @param string $type + * + * @return bool + */ + private function isCompoundType($type) + { + return strpos($type, '|') !== false; + } + + /** + * Resolves the given typed array string (i.e. `string[]`) into an Array object with the right types set. + * + * @param string $type + * @param Context $context + * + * @return Array_ + */ + private function resolveTypedArray($type, Context $context) + { + return new Array_($this->resolve(substr($type, 0, -2), $context)); + } + + /** + * Resolves the given keyword (such as `string`) into a Type object representing that keyword. + * + * @param string $type + * + * @return Type + */ + private function resolveKeyword($type) + { + $className = $this->keywords[strtolower($type)]; + + return new $className(); + } + + /** + * Resolves the given FQSEN string into an FQSEN object. + * + * @param string $type + * + * @return Fqsen + */ + private function resolveFqsen($type) + { + return new Fqsen($type); + } + + /** + * Resolves a partial Structural Element Name (i.e. `Reflection\DocBlock`) to its FQSEN representation + * (i.e. `\phpDocumentor\Reflection\DocBlock`) based on the Namespace and aliases mentioned in the Context. + * + * @param string $type + * @param Context $context + * + * @return Fqsen + */ + private function resolvePartialStructuralElementName($type, Context $context) + { + $typeParts = explode(self::OPERATOR_NAMESPACE, $type, 2); + + $namespaceAliases = $context->getNamespaceAliases(); + + // if the first segment is not an alias; prepend namespace name and return + if (!isset($namespaceAliases[$typeParts[0]])) { + $namespace = $context->getNamespace(); + if ('' !== $namespace) { + $namespace .= self::OPERATOR_NAMESPACE; + } + + return new Fqsen(self::OPERATOR_NAMESPACE . $namespace . $type); + } + + $typeParts[0] = $namespaceAliases[$typeParts[0]]; + + return new Fqsen(self::OPERATOR_NAMESPACE . implode(self::OPERATOR_NAMESPACE, $typeParts)); + } + + /** + * Resolves a compound type (i.e. `string|int`) into the appropriate Type objects or FQSEN. + * + * @param string $type + * @param Context $context + * + * @return Compound + */ + private function resolveCompoundType($type, Context $context) + { + $types = []; + + foreach (explode('|', $type) as $part) { + $types[] = $this->resolve($part, $context); + } + + return new Compound($types); + } +} diff --git a/src/Types/Resource.php b/src/Types/Resource.php new file mode 100644 index 0000000..2a8a201 --- /dev/null +++ b/src/Types/Resource.php @@ -0,0 +1,23 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +final class Resource implements Type +{ + public function __toString() + { + return 'resource'; + } +} diff --git a/src/Types/Scalar.php b/src/Types/Scalar.php new file mode 100644 index 0000000..5dadde8 --- /dev/null +++ b/src/Types/Scalar.php @@ -0,0 +1,23 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +class Scalar implements Type +{ + public function __toString() + { + return 'scalar'; + } +} diff --git a/src/Types/Self_.php b/src/Types/Self_.php new file mode 100644 index 0000000..933b4b8 --- /dev/null +++ b/src/Types/Self_.php @@ -0,0 +1,23 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +final class Self_ implements Type +{ + public function __toString() + { + return 'self'; + } +} diff --git a/src/Types/Static_.php b/src/Types/Static_.php new file mode 100644 index 0000000..4922fd3 --- /dev/null +++ b/src/Types/Static_.php @@ -0,0 +1,23 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +final class Static_ implements Type +{ + public function __toString() + { + return 'static'; + } +} diff --git a/src/Types/String.php b/src/Types/String.php new file mode 100644 index 0000000..8e4e5a2 --- /dev/null +++ b/src/Types/String.php @@ -0,0 +1,23 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +final class String implements Type +{ + public function __toString() + { + return 'string'; + } +} diff --git a/src/Types/This.php b/src/Types/This.php new file mode 100644 index 0000000..d0aec28 --- /dev/null +++ b/src/Types/This.php @@ -0,0 +1,23 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +final class This implements Type +{ + public function __toString() + { + return '$this'; + } +} diff --git a/src/Types/Void.php b/src/Types/Void.php new file mode 100644 index 0000000..f323349 --- /dev/null +++ b/src/Types/Void.php @@ -0,0 +1,23 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\Type; + +final class Void implements Type +{ + public function __toString() + { + return 'void'; + } +} diff --git a/tests/phpDocumentor/Reflection/Types/ResolverTest.php b/tests/phpDocumentor/Reflection/Types/ResolverTest.php new file mode 100644 index 0000000..2c07b9e --- /dev/null +++ b/tests/phpDocumentor/Reflection/Types/ResolverTest.php @@ -0,0 +1,235 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\Types; + +use phpDocumentor\Reflection\DocBlock\Context; + +/** + * @coversDefaultClass phpDocumentor\Reflection\Types\Resolver + */ +class ResolverTest extends \PHPUnit_Framework_TestCase +{ + /** + * @param string $keyword + * @param string $expectedClass + * + * @covers ::resolve + * @covers :: + * + * @uses phpDocumentor\Reflection\DocBlock\Context + * @uses phpDocumentor\Reflection\Types\Array_ + * + * @dataProvider provideKeywords + */ + public function testResolvingKeywords($keyword, $expectedClass) + { + $fixture = new Resolver(); + + $resolvedType = $fixture->resolve($keyword, new Context('')); + + $this->assertInstanceOf($expectedClass, $resolvedType); + } + + /** + * @param string $fqsen + * + * @covers ::resolve + * @covers :: + * + * @uses phpDocumentor\Reflection\DocBlock\Context + * @uses phpDocumentor\Reflection\Fqsen + * + * @dataProvider provideFqsen + */ + public function testResolvingFQSENs($fqsen) + { + $fixture = new Resolver(); + + $resolvedType = $fixture->resolve($fqsen, new Context('')); + + $this->assertInstanceOf('phpDocumentor\Reflection\Fqsen', $resolvedType); + $this->assertSame($fqsen, (string)$resolvedType); + } + + + /** + * @covers ::resolve + * @covers :: + * + * @uses phpDocumentor\Reflection\DocBlock\Context + * @uses phpDocumentor\Reflection\Fqsen + */ + public function testResolvingRelativeQSENsBasedOnNamespace() + { + $fixture = new Resolver(); + + $resolvedType = $fixture->resolve('DocBlock', new Context('phpDocumentor\Reflection')); + + $this->assertInstanceOf('phpDocumentor\Reflection\Fqsen', $resolvedType); + $this->assertSame('\phpDocumentor\Reflection\DocBlock', (string)$resolvedType); + } + + /** + * @covers ::resolve + * @covers :: + * + * @uses phpDocumentor\Reflection\DocBlock\Context + * @uses phpDocumentor\Reflection\Fqsen + */ + public function testResolvingRelativeQSENsBasedOnNamespaceAlias() + { + $fixture = new Resolver(); + + $resolvedType = $fixture->resolve( + 'm\MockInterface', + new Context('phpDocumentor\Reflection', ['m' => '\Mockery']) + ); + + $this->assertInstanceOf('phpDocumentor\Reflection\Fqsen', $resolvedType); + $this->assertSame('\Mockery\MockInterface', (string)$resolvedType); + } + + /** + * @covers ::resolve + * @covers :: + * + * @uses phpDocumentor\Reflection\DocBlock\Context + * @uses phpDocumentor\Reflection\Types\Array_ + * @uses phpDocumentor\Reflection\Types\String + */ + public function testResolvingTypedArrays() + { + $fixture = new Resolver(); + + /** @var Array_ $resolvedType */ + $resolvedType = $fixture->resolve('string[]', new Context('')); + + $this->assertInstanceOf('phpDocumentor\Reflection\Types\Array_', $resolvedType); + $this->assertSame('string[]', (string)$resolvedType); + $this->assertInstanceOf('phpDocumentor\Reflection\Types\Mixed', $resolvedType->getKeyType()); + $this->assertInstanceOf('phpDocumentor\Reflection\Types\String', $resolvedType->getValueType()); + } + + /** + * @covers ::resolve + * @covers :: + * + * @uses phpDocumentor\Reflection\DocBlock\Context + * @uses phpDocumentor\Reflection\Types\Array_ + * @uses phpDocumentor\Reflection\Types\String + */ + public function testResolvingNestedTypedArrays() + { + $fixture = new Resolver(); + + /** @var Array_ $resolvedType */ + $resolvedType = $fixture->resolve('string[][]', new Context('')); + + /** @var Array_ $childValueType */ + $childValueType = $resolvedType->getValueType(); + + $this->assertInstanceOf('phpDocumentor\Reflection\Types\Array_', $resolvedType); + + $this->assertSame('string[][]', (string)$resolvedType); + $this->assertInstanceOf('phpDocumentor\Reflection\Types\Mixed', $resolvedType->getKeyType()); + $this->assertInstanceOf('phpDocumentor\Reflection\Types\Array_', $childValueType); + + $this->assertSame('string[]', (string)$childValueType); + $this->assertInstanceOf('phpDocumentor\Reflection\Types\Mixed', $childValueType->getKeyType()); + $this->assertInstanceOf('phpDocumentor\Reflection\Types\String', $childValueType->getValueType()); + } + + /** + * @covers ::resolve + * @covers :: + * + * @uses phpDocumentor\Reflection\DocBlock\Context + * @uses phpDocumentor\Reflection\Types\Compound + * @uses phpDocumentor\Reflection\Types\String + * @uses phpDocumentor\Reflection\Fqsen + */ + public function testResolvingCompoundTypes() + { + $fixture = new Resolver(); + + /** @var Compound $resolvedType */ + $resolvedType = $fixture->resolve('string|Reflection\DocBlock', new Context('phpDocumentor')); + + $this->assertInstanceOf('phpDocumentor\Reflection\Types\Compound', $resolvedType); + $this->assertSame('string|\phpDocumentor\Reflection\DocBlock', (string)$resolvedType); + $this->assertInstanceOf('phpDocumentor\Reflection\Types\String', $resolvedType->get(0)); + $this->assertInstanceOf('phpDocumentor\Reflection\Fqsen', $resolvedType->get(1)); + } + + /** + * @covers ::resolve + * @uses phpDocumentor\Reflection\DocBlock\Context + * + * @expectedException \InvalidArgumentException + */ + public function testExceptionIsThrownIfTypeIsEmpty() + { + $fixture = new Resolver(); + $fixture->resolve(' ', new Context('')); + } + + /** + * @covers ::resolve + * @uses phpDocumentor\Reflection\DocBlock\Context + * + * @expectedException \InvalidArgumentException + */ + public function testExceptionIsThrownIfTypeIsNotAString() + { + $fixture = new Resolver(); + $fixture->resolve(['a'], new Context('')); + } + + public function provideKeywords() + { + return [ + ['string', 'phpDocumentor\Reflection\Types\String'], + ['int', 'phpDocumentor\Reflection\Types\Integer'], + ['integer', 'phpDocumentor\Reflection\Types\Integer'], + ['float', 'phpDocumentor\Reflection\Types\Float'], + ['double', 'phpDocumentor\Reflection\Types\Float'], + ['bool', 'phpDocumentor\Reflection\Types\Boolean'], + ['boolean', 'phpDocumentor\Reflection\Types\Boolean'], + ['resource', 'phpDocumentor\Reflection\Types\Resource'], + ['null', 'phpDocumentor\Reflection\Types\Null_'], + ['callable', 'phpDocumentor\Reflection\Types\Callable_'], + ['callback', 'phpDocumentor\Reflection\Types\Callable_'], + ['array', 'phpDocumentor\Reflection\Types\Array_'], + ['scalar', 'phpDocumentor\Reflection\Types\Scalar'], + ['object', 'phpDocumentor\Reflection\Types\Object_'], + ['mixed', 'phpDocumentor\Reflection\Types\Mixed'], + ['void', 'phpDocumentor\Reflection\Types\Void'], + ['$this', 'phpDocumentor\Reflection\Types\This'], + ['static', 'phpDocumentor\Reflection\Types\Static_'], + ['self', 'phpDocumentor\Reflection\Types\Self_'], + ]; + } + + public function provideFqsen() + { + return [ + 'namespace' => ['\phpDocumentor\Reflection'], + 'class' => ['\phpDocumentor\Reflection\DocBlock'], + 'function' => ['\DI\object()'], + 'constant' => ['\phpDocumentor\Reflection\GLOBAL_CONSTANT'], + 'classConstant' => ['\phpDocumentor\Reflection\DocBlock::CONSTANT'], + 'property' => ['\phpDocumentor\Reflection\DocBlock::$summary'], + 'method' => ['\phpDocumentor\Reflection\DocBlock::getSummary()'], + ]; + } +}