public function pass(FuncCall $funcCall, Context $context) { $functionName = $this->resolveFunctionName($funcCall, $context); if (!$functionName || !isset($this->map[$functionName])) { return false; } if ($funcCall->getDocComment()) { $phpdoc = $this->docBlockFactory->create($funcCall->getDocComment()->getText()); if ($phpdoc->hasTag('expected')) { return false; } } $context->notice('debug.code', sprintf('Function %s() is a debug function, please don`t use it in production.', $functionName), $funcCall); return true; }
/** * @param ClassMethod $methodStmt * @param Context $context * @return bool */ public function pass(ClassMethod $methodStmt, Context $context) { $functionName = $methodStmt->name; if (!$functionName) { return false; } if (substr($functionName, 0, 4) !== 'test') { return false; } if ($methodStmt->getDocComment()) { $phpdoc = $this->docBlockFactory->create($methodStmt->getDocComment()->getText()); if ($phpdoc->hasTag('test')) { $context->notice('test.annotation', 'Annotation @test is not needed when the method is prefixed with test.', $methodStmt); return true; } } return false; }
/** * Gets DocBlock from accessor or mutator method. * * @param string $class * @param string $ucFirstProperty * @param int $type * * @return array */ private function getDocBlockFromMethod($class, $ucFirstProperty, $type) { $prefixes = $type === self::ACCESSOR ? ReflectionExtractor::$accessorPrefixes : ReflectionExtractor::$mutatorPrefixes; $prefix = null; foreach ($prefixes as $prefix) { $methodName = $prefix . $ucFirstProperty; try { $reflectionMethod = new \ReflectionMethod($class, $methodName); if (self::ACCESSOR === $type && 0 === $reflectionMethod->getNumberOfRequiredParameters() || self::MUTATOR === $type && $reflectionMethod->getNumberOfParameters() >= 1) { break; } } catch (\ReflectionException $reflectionException) { // Try the next prefix if the method doesn't exist } } if (!isset($reflectionMethod)) { return; } return array($this->docBlockFactory->create($reflectionMethod, $this->contextFactory->createFromReflector($reflectionMethod)), $prefix); }
/** * @param \ReflectionClass $reflectionClass * @param \ReflectionProperty $reflectionProperty */ protected function _assertCorrectSetterImplementation(\ReflectionClass $reflectionClass, \ReflectionProperty $reflectionProperty) { /** @var \phpDocumentor\Reflection\Type $propertyVarType */ /** @var \phpDocumentor\Reflection\DocBlock\Tags\Param $methodParamTag */ /** @var \phpDocumentor\Reflection\DocBlock\Tags\Return_ $methodReturnTag */ $className = $reflectionClass->getName(); $propertyName = $reflectionProperty->getName(); $expectedSetterName = sprintf('set%s', ucfirst($propertyName)); if ($this->requiresSetters) { $this->assertTrue(method_exists($className, $expectedSetterName), sprintf('Class "%s" must have a setter named "%s" for property "%s"', $className, $expectedSetterName, $propertyName)); } else { if (!$reflectionClass->hasMethod($expectedSetterName)) { return; } } // Get method reflection $reflectionMethod = $reflectionClass->getMethod($expectedSetterName); // Validate we have one parameter $this->assertEquals(1, $reflectionMethod->getNumberOfParameters(), sprintf('Setter "%s" for property "%s" in class "%s" must have one parameter', $expectedSetterName, $propertyName, $className)); $this->assertEquals(1, $reflectionMethod->getNumberOfRequiredParameters(), sprintf('Setter "%s" for property "%s" in class "%s" must have one required parameter', $expectedSetterName, $propertyName, $className)); // Get first parameter $reflectionParameter = $reflectionMethod->getParameters()[0]; // Validate name $parameterName = $reflectionParameter->getName(); $this->assertEquals($propertyName, $parameterName, sprintf('Setter "%s" for property "%s" in class "%s" must have a parameter with the same name as the property', $expectedSetterName, $propertyName, $className)); // Get method doc block $methodDockBlock = $this->docBlockFactory->create($reflectionMethod->getDocComment()); // Try to locate param doc block tag $methodParamTags = $methodDockBlock->getTagsByName('param'); $this->assertCount(1, $methodParamTags, sprintf('Parameter "%s" for setter "%s" for property "%s" in class "%s" must have a "@param" doc block attribute', $parameterName, $expectedSetterName, $propertyName, $className)); // Grab doc block definition from class property declaration $propertyDocBlock = $this->docBlockFactory->create($reflectionProperty->getDocComment()); $propertyVarType = $propertyDocBlock->getTagsByName('var')[0]->getType(); // Pull out the @param attribute from the doc block comment $methodParamTag = $methodParamTags[0]; $methodParamType = $methodParamTag->getType(); $parameterClass = $reflectionParameter->getClass(); // Finally, attempt to validate setter declaration sanity switch (true) { // If the setter is designed to expect more than 1 type of variable, ensure that // there is no type-hinting going on. case $methodParamType instanceof Compound: $this->assertNull($parameterClass, sprintf('The "@param" docblock for parameter "%s" in setter "%s" for property "%s" in class "%s" indicates that the value can be one of "%s", but the param TypeHint explicitly requires "%s".', $parameterName, $expectedSetterName, $propertyName, $className, (string) $methodParamType, null !== $parameterClass ? $parameterClass->getName() : '')); break; // If we're dealing with a scalar types, don't allow type-hinting as we need to work with php5 // If we're dealing with a scalar types, don't allow type-hinting as we need to work with php5 case $propertyVarType instanceof String_: case $propertyVarType instanceof Integer: case $propertyVarType instanceof Float_: case $propertyVarType instanceof Boolean: $this->assertNull($parameterClass, sprintf('Parameter "%s" in setter "%s" for property "%s" in class "%s" must not use type-hinting to maintain php 5 compatibility', $parameterName, $expectedSetterName, $propertyName, $className)); break; case $propertyVarType instanceof Array_: $this->assertTrue($reflectionParameter->isArray(), sprintf('Parameter "%s" in setter "%s" for property "%s" in class "%s" must use type-hint of "array" or have it\'s doc block param tag value changed.', $parameterName, $expectedSetterName, $propertyName, $className)); break; case $propertyVarType instanceof Object_: $fqsn = ltrim((string) $propertyVarType->getFqsen(), "\\"); $this->assertEquals($fqsn, $parameterClass->getName(), sprintf('Parameter "%s" in setter "%s" for property "%s" in class "%s" must use type-hint equal to "%s". Currently specifies "%s"', $parameterName, $expectedSetterName, $propertyName, $className, (string) $propertyVarType->getFqsen(), $parameterClass->getName())); break; default: $this->fail(sprintf('The parameter "%s" in setter "%s" for property "%s" in class "%s" is of type "%s", and there is no setter sanity check. Please add one to the test suite.', $parameterName, $expectedSetterName, $propertyName, $className, (string) $propertyVarType)); } }
/** * @covers ::__construct * @covers ::create * @uses phpDocumentor\Reflection\DocBlock\DescriptionFactory * @uses phpDocumentor\Reflection\DocBlock\Description */ public function testTagsAreInterpretedUsingFactory() { $tagString = <<<TAG @author Mike van Riel <*****@*****.**> This is with multiline description. TAG; $tag = m::mock(Tag::class); $tagFactory = m::mock(TagFactory::class); $tagFactory->shouldReceive('create')->with($tagString)->andReturn($tag); $fixture = new DocBlockFactory(new DescriptionFactory($tagFactory), $tagFactory); $given = <<<DOCBLOCK /** * This is a summary. * * @author Mike van Riel <*****@*****.**> This is with * multiline description. */ DOCBLOCK; $docblock = $fixture->create($given, new Context('')); $this->assertEquals([$tag], $docblock->getTags()); }
/** * @covers ::__construct * @covers ::create * @uses phpDocumentor\Reflection\DocBlock\DescriptionFactory * @uses phpDocumentor\Reflection\DocBlock\Description * @uses phpDocumentor\Reflection\Types\Context * @uses phpDocumentor\Reflection\DocBlock\Tags\Param */ public function testTagsWithContextNamespace() { $tagFactoryMock = m::mock(TagFactory::class); $fixture = new DocBlockFactory(m::mock(DescriptionFactory::class), $tagFactoryMock); $context = new Context('MyNamespace'); $tagFactoryMock->shouldReceive('create')->with(m::any(), $context)->andReturn(new Param('param')); $docblock = $fixture->create('/** @param MyType $param */', $context); }