From a4b04767759f792e3b5ec72acd3afa8d0eecbcb7 Mon Sep 17 00:00:00 2001 From: Tobias Schlitt Date: Tue, 29 May 2012 17:13:22 +0200 Subject: [PATCH] Implemented: Composite resolver. --- .../resolvers/CompositeResolver.php | 147 ++++++++++++ .../resolvers/CompositeResolverTest.php | 211 ++++++++++++++++++ 2 files changed, 358 insertions(+) create mode 100644 src/main/php/pdepend/reflection/resolvers/CompositeResolver.php create mode 100644 src/test/php/pdepend/reflection/resolvers/CompositeResolverTest.php diff --git a/src/main/php/pdepend/reflection/resolvers/CompositeResolver.php b/src/main/php/pdepend/reflection/resolvers/CompositeResolver.php new file mode 100644 index 0000000..fea481b --- /dev/null +++ b/src/main/php/pdepend/reflection/resolvers/CompositeResolver.php @@ -0,0 +1,147 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Manuel Pichler nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category PHP + * @package pdepend\reflection\resolvers + * @author Manuel Pichler + * @copyright 2009-2011 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version SVN: $Id$ + * @link http://pdepend.org/ + */ + +namespace pdepend\reflection\resolvers; + +use pdepend\reflection\interfaces\SourceResolver; +use pdepend\reflection\exceptions\PathnameNotFoundException; + +/** + * This file resolver implementation makes use of multiple source resolvers to + * actually resolve a class name. + * + * + * $resolver = new pdepend\reflection\resolvers\CompositeResolver(); + * $resolver->add( new pdepend\reflection\resolvers\Psr0Resolver( 'src/main/php/', 'MyApp' ) ); + * $resolver->add( new pdepend\reflection\resolvers\AutoloadArrayResolver( 'src/libraries/Zeta/Graph/src/graph_autoload.php' ) ); + * var_dump( $resolver->getPathnameForClass( '\MyApp\Module\SomeClass' ); + * var_dump( $resolver->getPathnameForClass( '\ezcGraphRenderer3d' ); + * + * + * @category PHP + * @package pdepend\reflection\resolvers + * @author Tobias Schlitt + * @copyright 2009-2011 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pdepend.org/ + */ +class CompositeResolver implements SourceResolver +{ + /** + * Inner resolvers + * + * @var array(\pdepend\reflection\SourceResolver) + */ + private $innerResolvers = array(); + + /** + * Creates a composite resolver consisting of $innerResolvers. + * + * @param array(\pdepend\reflection\SourceResolver) $innerResolvers + */ + public function __construct( array $innerResolvers = array() ) + { + foreach ( $innerResolvers as $innerResolver ) + { + $this->add( $innerResolver ); + } + } + + /** + * This method will return true when this resolver knows a source + * file for a class with the given $className. Otherwise this method + * will return false. + * + * @param string $className Name of the searched class that should. + * + * @return boolean + */ + public function hasPathnameForClass( $className ) + { + foreach ( $this->innerResolvers as $innerResolver ) + { + if ( $innerResolver->hasPathnameForClass( $className ) ) + { + return true; + } + } + return false; + } + + /** + * Returns the file pathname where the given class is defined. + * + * @param string $className Name of the searched class that should. + * + * @return string + * @throws \pdepend\reflection\exceptions\PathnameNotFoundException When + * not match can be found for the given class name. + */ + public function getPathnameForClass( $className ) + { + foreach ( $this->innerResolvers as $innerResolver ) + { + if ( $innerResolver->hasPathnameForClass( $className ) ) + { + return $innerResolver->getPathnameForClass( $className ); + } + } + throw new PathnameNotFoundException( $className ); + } + + /** + * Adds a new resolver. + * + * @param \pdepend\reflection\SourceResolver $innerResolver + * @return void + */ + public function add( SourceResolver $innerResolver ) + { + $this->innerResolvers[] = $innerResolver; + } +} diff --git a/src/test/php/pdepend/reflection/resolvers/CompositeResolverTest.php b/src/test/php/pdepend/reflection/resolvers/CompositeResolverTest.php new file mode 100644 index 0000000..3da3335 --- /dev/null +++ b/src/test/php/pdepend/reflection/resolvers/CompositeResolverTest.php @@ -0,0 +1,211 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Manuel Pichler nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category PHP + * @package pdepend\reflection\resolvers + * @author Tobias Schlitt + * @copyright 2009-2011 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version SVN: $Id$ + * @link http://pdepend.org/ + */ + +namespace pdepend\reflection\resolvers; + +require_once __DIR__ . '/../BaseTest.php'; + +/** + * Test cases for the parser class. + * + * @category PHP + * @package pdepend\reflection\resolvers + * @author Manuel Pichler + * @copyright 2009-2011 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pdepend.org/ + */ +class CompositeResolverTest extends \pdepend\reflection\BaseTest +{ + /** + * @return void + * @covers \pdepend\reflection\interfaces\SourceResolver + * @covers \pdepend\reflection\resolvers\CompositeResolver + * @group reflection + * @group reflection::resolvers + * @group unittest + */ + public function testHasPathnameForClassReturnsTrueWithFunctionalResolver() + { + $resolver = new CompositeResolver(); + $resolver->add( $this->getFunctionalResolver() ); + + $exists = $resolver->hasPathnameForClass( 'SomeClass' ); + + self::assertTrue( $exists ); + } + + /** + * @return void + * @covers \pdepend\reflection\interfaces\SourceResolver + * @covers \pdepend\reflection\resolvers\CompositeResolver + * @group reflection + * @group reflection::resolvers + * @group unittest + */ + public function testHasPathnameForClassReturnsFalseWithNonFunctionalResolver() + { + $resolver = new CompositeResolver(); + $resolver->add( $this->getNonFunctionalResolver() ); + + $exists = $resolver->hasPathnameForClass( 'SomeClass' ); + + self::assertFalse( $exists ); + } + + /** + * @return void + * @covers \pdepend\reflection\interfaces\SourceResolver + * @covers \pdepend\reflection\resolvers\CompositeResolver + * @group reflection + * @group reflection::resolvers + * @group unittest + */ + public function testHasPathnameForClassReturnsTrueWithNonFunctionalAndFunctionalResolver() + { + $resolver = new CompositeResolver(); + $resolver->add( $this->getNonFunctionalResolver() ); + $resolver->add( $this->getFunctionalResolver() ); + + $exists = $resolver->hasPathnameForClass( 'SomeClass' ); + + self::assertTrue( $exists ); + } + + /** + * @return void + * @covers \pdepend\reflection\interfaces\SourceResolver + * @covers \pdepend\reflection\resolvers\CompositeResolver + * @group reflection + * @group reflection::resolvers + * @group unittest + */ + public function testGetPathnameForClassReturnsTrueWithFunctionalResolver() + { + $resolver = new CompositeResolver(); + $resolver->add( $this->getFunctionalResolver() ); + + $path = $resolver->getPathnameForClass( 'SomeClass' ); + + self::assertEquals( 'found.php', $path ); + } + + /** + * @return void + * @covers \pdepend\reflection\interfaces\SourceResolver + * @covers \pdepend\reflection\resolvers\CompositeResolver + * @group reflection + * @group reflection::resolvers + * @group unittest + * @expectedException \pdepend\reflection\exceptions\PathnameNotFoundException + */ + public function testGetPathnameForClassThrowsExceptionWithNonFunctionalResolver() + { + $resolver = new CompositeResolver(); + $resolver->add( $this->getNonFunctionalResolver() ); + + $path = $resolver->getPathnameForClass( 'SomeClass' ); + } + + /** + * @return void + * @covers \pdepend\reflection\interfaces\SourceResolver + * @covers \pdepend\reflection\resolvers\CompositeResolver + * @group reflection + * @group reflection::resolvers + * @group unittest + */ + public function testGetPathnameForClassReturnsTrueWithNonFunctionalAndFunctionalResolver() + { + $resolver = new CompositeResolver(); + $resolver->add( $this->getNonFunctionalResolver() ); + $resolver->add( $this->getFunctionalResolver() ); + + $path = $resolver->getPathnameForClass( 'SomeClass' ); + + self::assertEquals( 'found.php', $path ); + } + + /** + * Returns a mock for a functional resolver + * + * @return \pdepend\reflection\resolver\SourceResolver + */ + private function getFunctionalResolver() + { + $resolver = $this->getMock( '\pdepend\reflection\interfaces\SourceResolver' ); + $resolver->expects( $this->any() ) + ->method( 'hasPathnameForClass' ) + ->will( $this->returnValue( true ) ); + $resolver->expects( $this->any() ) + ->method( 'getPathnameForClass' ) + ->will( $this->returnValue( 'found.php' ) ); + return $resolver; + } + + /** + * Returns a mock for a non functional resolver + * + * @return \pdepend\reflection\resolver\SourceResolver + */ + private function getNonFunctionalResolver() + { + $resolver = $this->getMock( '\pdepend\reflection\interfaces\SourceResolver' ); + $resolver->expects( $this->any() ) + ->method( 'hasPathnameForClass' ) + ->will( $this->returnValue( false ) ); + $resolver->expects( $this->any() ) + ->method( 'getPathnameForClass' ) + ->will( + $this->throwException( + new \pdepend\reflection\exceptions\PathnameNotFoundException( 'SomeClass' ) + ) + ); + return $resolver; + } +}