diff --git a/.gitignore b/.gitignore index 335df2d..d53f981 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /vendor composer.lock -.idea +.idea/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6825241 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,26 @@ +language: php +php: + - 5.4 + - 5.5 + - 5.6 + - hhvm + +matrix: + include: + - php: 5.3 + dist: precise + allow_failures: + - php: hhvm + fast_finish: true + +cache: + directories: + - vendor + - $HOME/.composer/cache + +before_script: + - travis_retry composer self-update + - travis_retry composer install --no-interaction --no-suggest --no-progress + +script: + - vendor/bin/phpunit diff --git a/composer.json b/composer.json index 17d5c95..7a67142 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,8 @@ "kdyby/parse-use-statements": "~0.2" }, "require-dev": { - "doctrine/dbal": "~2.3" + "doctrine/dbal": "~2.3", + "phpunit/phpunit": "~4.0" }, "suggest": { "doctrine/dbal": "Load information from the database about models for phpdocs (~2.3)" diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..7660980 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,18 @@ + + + + + ./tests/ + + + diff --git a/src/Console/MetaCommand.php b/src/Console/MetaCommand.php index f236f82..1e36bf0 100644 --- a/src/Console/MetaCommand.php +++ b/src/Console/MetaCommand.php @@ -39,10 +39,9 @@ class MetaCommand extends Command { protected $view; protected $methods = array( - '\Illuminate\Foundation\Application::make', - 'new \Illuminate\Foundation\Application', - '\Illuminate\Container\Container::make', + //'\Illuminate\Foundation\Application::make', 'new \Illuminate\Container\Container', + '\Illuminate\Container\Container::make', '\App::make', 'app', ); @@ -67,8 +66,16 @@ class MetaCommand extends Command { */ public function fire() { - $bindings = array(); + $bindings = array_flip($this->getAppAliases()); + $exclude = $this->option('exclude'); + if (!empty($exclude)) { + $exclude = '/' . str_replace('\|', '|', preg_quote($exclude, '/')) . '/'; + } + foreach ($this->getAbstracts() as $abstract) { + if (!empty($exclude) && preg_match($exclude, $abstract)) + continue; + try { $concrete = $this->laravel->make($abstract); if (is_object($concrete)) { @@ -78,6 +85,7 @@ class MetaCommand extends Command { $this->error("Cannot make $abstract: " . $e->getMessage()); } } + asort($bindings); $content = $this->view->make('laravel-ide-helper::meta', array( 'bindings' => $bindings, @@ -104,6 +112,21 @@ class MetaCommand extends Command { return array_keys($this->laravel->getBindings()); } + /** + * Get a list of aliases from the Laravel Application. + * + * @return array + */ + protected function getAppAliases() + { + static $aliasProp; + if (!isset($aliasProp)) { + $aliasProp = new \ReflectionProperty('Illuminate\Container\Container', 'aliases'); + $aliasProp->setAccessible(true); + } + return $aliasProp->getValue($this->laravel); + } + /** * {@inheritdoc} */ @@ -111,6 +134,7 @@ class MetaCommand extends Command { { return array( array('filename', 'F', InputOption::VALUE_OPTIONAL, 'The path to the meta file', $this->filename), + array('exclude', 'E', InputOption::VALUE_OPTIONAL, 'Laravel bindings to exclude (e.g. "bar.|.foo")'), ); } } diff --git a/src/Method.php b/src/Method.php index 6a88196..5852d3a 100644 --- a/src/Method.php +++ b/src/Method.php @@ -24,7 +24,6 @@ class Method /** @var \ReflectionMethod */ protected $method; - protected $output = ''; protected $name; protected $namespace; protected $params = array(); @@ -230,7 +229,16 @@ class Method */ protected static function convertKeywords($string) { - return preg_replace(array('/(^|\|)Closure(\||$)/', '/(^|\|)dynamic(\||$)/'), array('$1\Closure$2', '$1mixed$2'), $string); + $types = explode('|', $string); + foreach ($types as &$type) { + if ($type === 'Closure') + $type = '\Closure'; + elseif ($type === 'dynamic') + $type = 'mixed'; + elseif (strrpos($type, '\\') && $type[0] !== '\\' && (class_exists($type) || interface_exists($type))) + $type = '\\' . $type; + } + return implode('|', $types); } /** diff --git a/src/views/meta.php b/src/views/meta.php index 7f32ead..837617a 100644 --- a/src/views/meta.php +++ b/src/views/meta.php @@ -13,7 +13,7 @@ => array( $class): ?> - '' instanceof \, + instanceof \, ), diff --git a/tests/MethodTest.php b/tests/MethodTest.php new file mode 100644 index 0000000..c8b64bc --- /dev/null +++ b/tests/MethodTest.php @@ -0,0 +1,38 @@ +assertSame('\PHPUnit_Framework_TestCase', $object->getDeclaringClass()); + $this->assertSame('\\' . get_class($this), $object->getRoot()); + $this->assertSame('getMock', $object->getName()); + + $prop = new \ReflectionProperty(get_class($object), 'namespace'); + $prop->setAccessible(true); + $this->assertSame('', $prop->getValue($object)); + + $this->assertFalse($object->isDeprecated()); + $this->assertCount($method->getNumberOfParameters(), $object->getDocParams()); + + $doc = $object->getDocComment('', true); + $this->assertContains("\n * " . '@param array|null $methods', $doc); + $this->assertContains("\n * " . '@return \PHPUnit_Framework_MockObject_MockObject', $doc); + $this->assertContains("\n * " . '@throws \PHPUnit_Framework_Exception', $doc); + + $this->assertTrue($object->shouldReturn()); + } + +} diff --git a/tests/ServiceProviderTest.php b/tests/ServiceProviderTest.php new file mode 100644 index 0000000..ae72be0 --- /dev/null +++ b/tests/ServiceProviderTest.php @@ -0,0 +1,83 @@ +getMock('Illuminate\Container\Container', array('make', 'bind')); + + $fs = $testCase->getMock('Illuminate\Filesystem\Filesystem', null); + $config = $testCase->getMock('Illuminate\Config\Repository', array('get', 'set', 'package'), array(), '', false); + $events = $testCase->getMock('Illuminate\Events\Dispatcher', array('listen'), array($app)); + $view = $testCase->getMock('Illuminate\View\Factory', array('addNamespace'), array(), '', false); + + $app->expects($testCase->any())->method('make')->willReturnMap(array( + array('files', array(), $fs), + array('config', array(), $config), + array('events', array(), $events), + array('view', array(), $view), + array('path', array(), __DIR__), + )); + + return $app; + } + + /** + * {@inheritdoc} + */ + protected function setUp() + { + $this->app = static::makeAppMock($this); + /** @noinspection PhpParamsInspection */ + $this->provider = new IdeHelperServiceProvider($this->app); + } + + public function testDeferred() + { + $this->assertTrue($this->provider->isDeferred()); + } + + public function testProvides() + { + $this->assertEquals(array('command.ide-helper.generate', 'command.ide-helper.models', 'command.ide-helper.meta'), $this->provider->provides()); + } + + public function testRegister() + { + $this->app->expects($this->exactly(3))->method('bind')->withConsecutive( + array('command.ide-helper.generate', $this->isType(\PHPUnit_Framework_Constraint_IsType::TYPE_CALLABLE), $this->isFalse()), + array('command.ide-helper.models', $this->isType(\PHPUnit_Framework_Constraint_IsType::TYPE_CALLABLE), $this->isFalse()), + array('command.ide-helper.meta', $this->isType(\PHPUnit_Framework_Constraint_IsType::TYPE_CALLABLE), $this->isFalse()) + ); + + /** @var \PHPUnit_Framework_MockObject_MockObject|\Illuminate\Events\Dispatcher $events */ + $events = $this->app['events']; + $events->expects($this->once())->method('listen')->with('artisan.start', $this->callback(function ($listener) { + $params = print_r(array('commands' => array('command.ide-helper.generate', 'command.ide-helper.models', 'command.ide-helper.meta')), true); + return strpos(preg_replace('/^\s+/mu', '', print_r($listener, true)), preg_replace('/^\s+/mu', '', $params)); + }), 0); + + $this->provider->register(); + } + + public function testBoot() + { + $path = realpath(__DIR__ . '/../src'); + + /** @var \PHPUnit_Framework_MockObject_MockObject|\Illuminate\Config\Repository $config */ + $config = $this->app['config']; + $config->expects($this->once())->method('package')->with('barryvdh/laravel-ide-helper', $path . '/config', 'laravel-ide-helper'); + + /** @var \PHPUnit_Framework_MockObject_MockObject|\Illuminate\View\Factory $view */ + $view = $this->app['view']; + $view->expects($this->once())->method('addNamespace')->with('laravel-ide-helper', $path . '/views'); + + $this->provider->boot(); + } + +}