Compatibility tests #7

Closed
wants to merge 23 commits into
from
Select commit
+389 −0
Split
View
4 .gitignore
@@ -0,0 +1,4 @@
+.buildpath
+.project
+.settings/
+vendor/
View
91 accepted/tests/Psr0/CompatibilityTest.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * Test case containing test to verify PSR-0 copatibility of a project.
+ *
+ * @author Bastian Feder <lapistano@php.net>
+ * @copyright 2011 by Bastian Feder
+ *
+ */
+namespace figStandards\accepted\tests\Psr0;
+
+require __DIR__ . '/Scanner.php';
+
+class CompatibilityTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * Contains the result of the directory scan.
+ * @staticvar
+ * @var Psr0_Scanner
+ */
+ protected static $psr0;
+
+ /**
+ * Normalize given filename to a relative path.
+ *
+ * @param string $filename
+ * @return string
+ */
+ protected function normalizeFilename($filename)
+ {
+ $pattern = array();
+ $namespaces = explode(':', Psr0_ProjectRootNamespaces);
+
+ if (empty($namespaces)) {
+ return $filename;
+ }
+
+ foreach ($namespaces as $namespace) {
+ $pattern[] = "(^.*?(" . $namespace . ".*)$)";
+ }
+
+ $filename = preg_replace($pattern, '$1', $filename, 1);
+ return $filename;
+ }
+
+ /**
+ * @dataProvider psr0CompatibilityDataprovider
+ */
+ public function testPsr0Compatability($filename, $classname)
+ {
+ $this->assertEquals(
+ $this->normalizeFilename($filename),
+ Scanner::translateClassToFilename($classname),
+ 'The classname does not translate correctly into a PSR-0 compatible filename.'
+ );
+ }
+
+ /**
+ * Checks if any permission related errors were registered.
+ */
+ public function testReadErrorsOccured()
+ {
+ $errors = static::$psr0->getErrors('NotReadable');
+ $this->assertEmpty(
+ $errors,
+ "The following files could not been readed probably due to missing access permissions:\n\n".
+ implode(", \n", $errors).
+ "\n"
+ );
+ }
+
+
+/*************************************************************************/
+/* Dataprovider */
+/*************************************************************************/
+
+ /**
+ * This data provider gathers all filenames, classnames, and namespaces within the configured directory.
+ *
+ * @return array
+ */
+ public static function psr0CompatibilityDataprovider()
+ {
+ // preparations
+ static::$psr0 = new Scanner(
+ defined('Psr0_ScannerInclude') ? Psr0_ScannerInclude : '',
+ defined('Psr0_ScannerExclude') ? Psr0_ScannerExclude : ''
+ );
+
+ return static::$psr0->scan(Psr0_ScannerStartDir);
+ }
+}
View
176 accepted/tests/Psr0/Scanner.php
@@ -0,0 +1,176 @@
+<?php
+/**
+ *
+ *
+ * @author Bastian Feder <lapistano@php.net>
+ * @copyright 2011 by Bastian Feder
+ *
+ */
+
+namespace figStandards\accepted\tests\Psr0;
+
+class Scanner
+{
+ protected $includes = '';
+ protected $excludes = '';
+ protected $registry = array();
+ protected $errors = array();
+
+ public function __construct($includes = '', $excludes = '')
+ {
+ $this->includes = $includes;
+ $this->excludes = $excludes;
+ }
+
+ /**
+ *
+ *
+ * @param unknown_type $dir
+ */
+ public function scan($dir)
+ {
+ $scanner = $this->initScanner();
+ $files = $scanner($dir);
+ $classes = array();
+
+ foreach ($files as $file) {
+ $this->parseFile($file);
+ }
+
+ // $this->registry now has all information about used NS and classnames
+ foreach ($this->registry as $namespace => $classInfo) {
+ foreach ($classInfo as $class) {
+ $classname = $namespace . '\\' . $class['classname'];
+ $classes[$classname] = array(
+ 'filename' => $class['filename'],
+ 'classname' => $classname
+ );
+ }
+ }
+
+ return $classes;
+
+ }
+
+ /**
+ * Provides the list of errors accord during the parsing.
+ *
+ * @return array
+ */
+ public function getErrors($type = '')
+ {
+ if (!empty($type) && isset($this->errors[$type])) {
+ return $this->errors[$type];
+ }
+ return $this->errors;
+ }
+
+ /**
+ * Translates a classname to a filename according to the rules of PSR-0.
+ *
+ * This method is a clone of the autoload() function accepted to be the reference
+ * implementation to autoload classes following the PSR-0 FIG standard.
+ *
+ * @param string $className
+ * @return string
+ * @link https://github.com/php-fig/fig-standards
+ */
+ public static function translateClassToFilename($className)
+ {
+ $className = ltrim($className, '\\');
+ $fileName = '';
+ $namespace = '';
+ if ($lastNsPos = strripos($className, '\\')) {
+ $namespace = substr($className, 0, $lastNsPos);
+ $className = substr($className, $lastNsPos + 1);
+ $fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
+ }
+ $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
+ return $fileName;
+ }
+
+ /**
+ * Greps namespaces and classnames from the given file
+ *
+ * @param SplFileInfo $file
+ */
+ protected function parseFile($file)
+ {
+ if (!$file->isReadable()) {
+ $this->errors['NotReadable'][] = $file->getPathname();
+ return;
+ }
+ $content = file($file->getPathname());
+
+ foreach ($content as $line) {
+ // find namespace declarations
+ preg_match('(^\s*?namespace\s*([^;{]*))', $line, $matches);
+ if (isset($matches[1])) {
+ $namespace = $matches[1];
+ if (!isset($this->registry[$namespace])) {
+ $this->registry[$namespace] = array();
+ }
+ }
+
+ // find class declarations
+ preg_match('(^\s*?(?:class|interface)\s+([^\s]+)(?:extends|implements)?\s+[^{]*)m', $line, $matches);
+ if (isset($matches[1])) {
+ $this->registry[$namespace][] = array(
+ 'classname' => $matches[1],
+ 'filename' => $file->getPathname()
+ );
+ }
+ }
+ }
+
+ /**
+ * Initializes the directory scanner.
+ *
+ * @return DirectoryScanner
+ */
+ protected function initScanner()
+ {
+ if(! class_exists('\TheSeer\DirectoryScanner\DirectoryScanner', true)) {
+ $dirScanner = __DIR__ . '/../vendor/TheSeer/DirectoryScanner/autoload.php';
+ if (!file_exists($dirScanner)) {
+ throw new \BadFunctionCallException(
+ 'Cannot find directory scanner mandatory for PSR-0 compatibility tests. '.
+ 'Please run install.sh in the test root directory.'
+ );
+ }
+ require $dirScanner;
+ }
+
+ $scanner = new \TheSeer\DirectoryScanner\DirectoryScanner;
+ $this->registerExclusions($scanner);
+ $this->registerInclusions($scanner);
+
+ return $scanner;
+ }
+
+ /**
+ * Registers preset files/directories to be ignored when scanning the directory structure.
+ *
+ * @param DirectoryScanner $scanner
+ */
+ protected function registerExclusions(\TheSeer\DirectoryScanner\DirectoryScanner $scanner)
+ {
+ if (!empty($this->excludes)) {
+ $exclusions = explode(":", $this->excludes);
+ $scanner->setExcludes($exclusions);
+ }
+ }
+
+ /**
+ * Registers preset files/directories to be recognized when scanning the directory structure.
+ *
+ * @param DirectoryScanner $scanner
+ */
+ protected function registerInclusions(\TheSeer\DirectoryScanner\DirectoryScanner $scanner)
+ {
+ if (!empty($this->includes)) {
+ $inclusions = explode(":", $this->includes);
+ $scanner->setIncludes($inclusions);
+ }
+ }
+}
View
72 accepted/tests/README.md
@@ -0,0 +1,72 @@
+=============================
+PSR-0 Compatibility Testsuite
+=============================
+
+Purpose
+=======
+The PSR-0 compatibility test suite shall help you to easily and fast verify the compatability of your project
+directory and namespace structure to the [PSR-0 standard][1].
+
+
+Installation
+============
+Getting the sources
+-------------------
+The installation is pretty simple just clone the sources to your favorite directory.
+This might be the test directory of your project.
+
+ $> cd $PROJECT_HOME
+ $> git clone git://github.com/lapistano/fig-standards.git tests/fig-standards
+
+Due to the architecture of the test suite there is a dependency to a DirectoryScanner (see section Dependencies).
+If you already installed the *DirectoryScanner* from the [*pear.netpirates.net*][2] PEAR channel you just have to
+make sure your project does find it on demand.
+Otherwise change just run *install.sh* in the *accepted/tests* directory and the test suite will take care of this.
+
+ $> /bin/sh install.sh
+
+This clones the *DirectoryScanner* from github so a functional internet connection is mandatory for this action.
+After you ran *install.sh* you'll find the sources in the newly created *accepted/tests/vendor* directory.
+
+Setting up
+----------
+Once the sources are on your machine, you now have to tell PHPunit to run the suite. Therefore an example
+phpunit.xml.dist file is shipped with the sources. The following list is the set of mandatory and optional settings
+to configure the *DirectoryScanner*. Modify them to meet the requirements of your project.
+
+* (mandatory) __Psr0_ProjectRootNamespaces__
+ is a colon separates list of the root namespaces used in your project (e.g. Liip:Jns)..
+
+* (mandatory) __Psr0_ScannerStartDir__
+ represents the absolute or relative path to your source files (e.g. ../src/).
+
+* (optional) __Psr0_ScannerInclude__
+ is a colon separated set of patterns which directories/files are to be recognized when scanning.
+
+* (optional) __Psr0_ScannerExclude__
+ is a colon separated set of patterns which directories/files are to be ignored when scanning.
+ You usually want to exclude the directories containing the tests and 3rd party source probably located in a
+ vendor directory. This combines into the string shown in the following example:
+
+ */vendor/*:*/Test/*
+
+See [*DirectoryScanner*][3] on GitHub for further information.
+
+To make PHPUnit aware of the PSR-0 Compataibility Testsuite you have to add the *Psr0_CompatibilityTest.php* to the
+*\<testsuite\>* section of your phpunit configuration. The example assumes that the test file is in the original location
+after a checkout described as above.
+
+ …
+ <file>../tests/fig-standards/accepted/tests/Psr0/CompatibilityTest.php</file>
+ …
+
+Dependencies
+============
+Since the PSR-0 compatibility tests depend on a static code analysis it is necessary to scan each file for its
+class and namespace name. Arne Blankerts [*DirectoryScanner*][3] was the perfect library for this. Kudos to him.
+
+Links
+=====
+[1]: http://groups.google.com/group/php-standards
+[2]: http://pear.netpirates.net
+[3]: https://github.com/theseer/DirectoryScanner
View
4 accepted/tests/install.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# used to crawl the dir structure
+git clone git://github.com/theseer/DirectoryScanner.git vendor/TheSeer/DirectoryScanner
View
42 accepted/tests/phpunit.xml.dist
@@ -0,0 +1,42 @@
+<!--
+
+*Notice*
+
+This is not a fully functional phpunit configuration file and will not configure PHPunit to run properly.
+This file is just an example how to configure the Psr-0 Compatibility Testsuite.
+
+-->
+
+<phpunit strict="true"
+ verbose="true"
+>
+
+ <!-- PSR-0 test configuration
+
+ * (mandatory) __Psr0_ProjectRootNamespaces__
+ is a colon separates list of the root namespaces used in your project (e.g. Liip:Jns)..
+
+ * (mandatory) __Psr0_ScannerStartDir__
+ represents the absolute or relative path to your source files (e.g. ../src/).
+
+ * (optional) __Psr0_ScannerInclude__
+ is a colon separated set of patterns which directories/files are to be recognized when scanning.
+
+ * (optional) __Psr0_ScannerExclude__
+ is a colon separated set of patterns which directories/files are to be ignored when scanning.
+ You usually want to exclude the directories containing the tests and 3rd party source probably located in a
+ vendor directory. This combines into the string shown in the following example:
+
+ */vendor/*:*/Test/*
+
+ See [*DirectoryScanner*][3] on GitHub for further information.
+
+ -->
+ <php>
+ <const name="Psr0_ProjectRootNamespaces" value="PROJECT_ROOT_NAMESPACES"/>
+ <const name="Psr0_ScannerStartDir" value="../src"/>
+ <const name="Psr0_ScannerInclude" value="*.php"/>
+ <const name="Psr0_ScannerExclude" value="*/vendor/*:*/Test/*"/>
+ </php>
+
+</phpunit>