pax_global_header00006660000000000000000000000064126454224050014516gustar00rootroot0000000000000052 comment=2917d010fbfd503d9e836cefff249cb3c1b3f17a phploc-3.0.0/000077500000000000000000000000001264542240500130035ustar00rootroot00000000000000phploc-3.0.0/.gitattributes000066400000000000000000000000171264542240500156740ustar00rootroot00000000000000*.php diff=php phploc-3.0.0/.gitignore000066400000000000000000000002311264542240500147670ustar00rootroot00000000000000build/phar build/SebastianBergmann build/phploc.bat build/phploc.php build/*.phar* build/*.tgz .idea cache.properties composer.phar composer.lock vendor phploc-3.0.0/.travis.yml000066400000000000000000000003731264542240500151170ustar00rootroot00000000000000language: php install: - travis_retry composer install --no-interaction --prefer-source php: - 5.6 - 7.0 - hhvm script: phpunit --configuration ./build/travis-ci.xml matrix: allow_failures: - php: hhvm notifications: email: false phploc-3.0.0/LICENSE000066400000000000000000000030051264542240500140060ustar00rootroot00000000000000phploc Copyright (c) 2009-2016, Sebastian Bergmann . 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 Sebastian Bergmann 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. phploc-3.0.0/README.md000066400000000000000000000105701264542240500142650ustar00rootroot00000000000000[![Latest Stable Version](https://poser.pugx.org/phploc/phploc/v/stable.png)](https://packagist.org/packages/phploc/phploc) [![Build Status](https://travis-ci.org/sebastianbergmann/phploc.png?branch=master)](https://travis-ci.org/sebastianbergmann/phploc) # PHPLOC `phploc` is a tool for quickly measuring the size and analyzing the structure of a PHP project. ## Installation ### PHP Archive (PHAR) The easiest way to obtain PHPLOC is to download a [PHP Archive (PHAR)](http://php.net/phar) that has all required dependencies of PHPLOC bundled in a single file: wget https://phar.phpunit.de/phploc.phar chmod +x phploc.phar mv phploc.phar /usr/local/bin/phploc You can also immediately use the PHAR after you have downloaded it, of course: wget https://phar.phpunit.de/phploc.phar php phploc.phar ### Composer Simply add a dependency on `phploc/phploc` to your project's `composer.json` file if you use [Composer](http://getcomposer.org/) to manage the dependencies of your project. Here is a minimal example of a `composer.json` file that just defines a development-time dependency on PHPLOC: { "require-dev": { "phploc/phploc": "*" } } For a system-wide installation via Composer, you can run: composer global require 'phploc/phploc=*' Make sure you have `~/.composer/vendor/bin/` in your path. ## Usage Examples ### Analyse a directory and print the result ➜ ~ phploc src phploc 2.0.4 by Sebastian Bergmann. Directories 3 Files 8 Size Lines of Code (LOC) 1858 Comment Lines of Code (CLOC) 560 (30.14%) Non-Comment Lines of Code (NCLOC) 1298 (69.86%) Logical Lines of Code (LLOC) 289 (15.55%) Classes 260 (89.97%) Average Class Length 37 Average Method Length 9 Functions 5 (1.73%) Average Function Length 5 Not in classes or functions 24 (8.30%) Complexity Cyclomatic Complexity / LLOC 0.67 Cyclomatic Complexity / Number of Methods 7.86 Dependencies Global Accesses 2 Global Constants 2 (100.00%) Global Variables 0 (0.00%) Super-Global Variables 0 (0.00%) Attribute Accesses 48 Non-Static 48 (100.00%) Static 0 (0.00%) Method Calls 96 Non-Static 91 (94.79%) Static 5 (5.21%) Structure Namespaces 4 Interfaces 0 Traits 0 Classes 7 Abstract Classes 0 (0.00%) Concrete Classes 7 (100.00%) Methods 28 Scope Non-Static Methods 28 (100.00%) Static Methods 0 (0.00%) Visibility Public Method 10 (35.71%) Non-Public Methods 18 (64.29%) Functions 1 Named Functions 0 (0.00%) Anonymous Functions 1 (100.00%) Constants 1 Global Constants 1 (100.00%) Class Constants 0 (0.00%) ### Analyse a directory for each revision in a Git repository and write the result in CSV format ➜ ~ phploc --log-csv log.csv --progress --git-repository . src phploc 2.0.4 by Sebastian Bergmann. 295/295 [============================] 100% phploc-3.0.0/build.xml000066400000000000000000000124661264542240500146350ustar00rootroot00000000000000 phploc-3.0.0/build/000077500000000000000000000000001264542240500141025ustar00rootroot00000000000000phploc-3.0.0/build/phar-autoload.php.in000066400000000000000000000016401264542240500177610ustar00rootroot00000000000000#!/usr/bin/env php run(); __HALT_COMPILER(); phploc-3.0.0/build/phar-manifest.php000077500000000000000000000013371264542240500173600ustar00rootroot00000000000000#!/usr/bin/env php &1'); if (strpos($tag, '-') === false && strpos($tag, 'No names found') === false) { print $tag; } else { $branch = @exec('git rev-parse --abbrev-ref HEAD'); $hash = @exec('git log -1 --format="%H"'); print $branch . '@' . $hash; } print "\n"; $lock = json_decode(file_get_contents(__DIR__ . '/../composer.lock')); foreach ($lock->packages as $package) { print $package->name . ': ' . $package->version; if (!preg_match('/^[v= ]*(([0-9]+)(\\.([0-9]+)(\\.([0-9]+)(-([0-9]+))?(-?([a-zA-Z-+][a-zA-Z0-9\\.\\-:]*)?)?)?)?)$/', $package->version)) { print '@' . $package->source->reference; } print "\n"; } phploc-3.0.0/build/phpunit.xml000066400000000000000000000014341264542240500163150ustar00rootroot00000000000000 ../tests ../src phploc-3.0.0/build/travis-ci.xml000066400000000000000000000013021264542240500165210ustar00rootroot00000000000000 ../tests ../src ../src/autoload.php phploc-3.0.0/composer.json000066400000000000000000000016361264542240500155330ustar00rootroot00000000000000{ "name": "phploc/phploc", "description": "A tool for quickly measuring the size of a PHP project.", "homepage": "https://github.com/sebastianbergmann/phploc", "license": "BSD-3-Clause", "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "support": { "issues": "https://github.com/sebastianbergmann/phploc/issues" }, "require": { "php": ">=5.6", "sebastian/finder-facade": "~1.1", "sebastian/git": "~2.0", "sebastian/version": "~1.0.3", "symfony/console": "~2.5|~3.0" }, "require-dev": { "phpunit/phpunit": "~5" }, "autoload": { "classmap": [ "src/" ] }, "bin": [ "phploc" ], "extra": { "branch-alias": { "dev-master": "3.0-dev" } } } phploc-3.0.0/phploc000077500000000000000000000014171264542240500142210ustar00rootroot00000000000000#!/usr/bin/env php * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ $loaded = false; foreach (array(__DIR__ . '/../../autoload.php', __DIR__ . '/vendor/autoload.php') as $file) { if (file_exists($file)) { require $file; $loaded = true; break; } } if (!$loaded) { die( 'You need to set up the project dependencies using the following commands:' . PHP_EOL . 'wget http://getcomposer.org/composer.phar' . PHP_EOL . 'php composer.phar install' . PHP_EOL ); } $application = new SebastianBergmann\PHPLOC\CLI\Application; $application->run(); phploc-3.0.0/src/000077500000000000000000000000001264542240500135725ustar00rootroot00000000000000phploc-3.0.0/src/Analyser.php000066400000000000000000000632421264542240500160700ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\PHPLOC; /** * PHPLOC code analyser. * * @since Class available since Release 1.0.0 */ class Analyser { /** * @var array */ private $namespaces = []; /** * @var array */ private $classes = []; /** * @var array */ private $constants = []; /** * @var array */ private $possibleConstantAccesses = []; /** * @var array */ private $count = [ 'files' => 0, 'loc' => 0, 'lloc' => 0, 'llocClasses' => 0, 'llocFunctions' => 0, 'llocGlobal' => 0, 'cloc' => 0, 'ccn' => 0, 'ccnMethods' => 0, 'interfaces' => 0, 'traits' => 0, 'classes' => 0, 'abstractClasses' => 0, 'concreteClasses' => 0, 'functions' => 0, 'namedFunctions' => 0, 'anonymousFunctions' => 0, 'methods' => 0, 'publicMethods' => 0, 'nonPublicMethods' => 0, 'nonStaticMethods' => 0, 'staticMethods' => 0, 'constants' => 0, 'classConstants' => 0, 'globalConstants' => 0, 'testClasses' => 0, 'testMethods' => 0, 'ccnByLloc' => 0, 'llocByNof' => 0, 'methodCalls' => 0, 'staticMethodCalls' => 0, 'instanceMethodCalls' => 0, 'attributeAccesses' => 0, 'staticAttributeAccesses' => 0, 'instanceAttributeAccesses' => 0, 'globalAccesses' => 0, 'globalVariableAccesses' => 0, 'superGlobalVariableAccesses' => 0, 'globalConstantAccesses' => 0, 'classCcnMin' => 0, 'classCcnAvg' => 0, 'classCcnMax' => 0, 'classLlocMin' => 0, 'classLlocAvg' => 0, 'classLlocMax' => 0, 'methodCcnMin' => 0, 'methodCcnAvg' => 0, 'methodCcnMax' => 0, 'methodLlocMin' => 0, 'methodLlocAvg' => 0, 'methodLlocMax' => 0 ]; /** * @var array */ private $superGlobals = [ '$_ENV' => true, '$_POST' => true, '$_GET' => true, '$_COOKIE' => true, '$_SERVER' => true, '$_FILES' => true, '$_REQUEST' => true, '$HTTP_ENV_VARS' => true, '$HTTP_POST_VARS' => true, '$HTTP_GET_VARS' => true, '$HTTP_COOKIE_VARS' => true, '$HTTP_SERVER_VARS' => true, '$HTTP_POST_FILES' => true ]; /** * @var array */ private $classCcn = []; /** * @var array */ private $classLloc = []; /** * @var array */ private $methodCcn = []; /** * @var array */ private $methodLloc = []; /** * Processes a set of files. * * @param array $files * @param bool $countTests * @return array * @since Method available since Release 1.2.0 */ public function countFiles(array $files, $countTests) { if ($countTests) { foreach ($files as $file) { $this->preProcessFile($file); } } $directories = []; foreach ($files as $file) { $directory = dirname($file); if (!isset($directories[$directory])) { $directories[$directory] = true; } $this->countFile($file, $countTests); } $count = $this->count; $count['directories'] = count($directories) - 1; $count['namespaces'] = count($this->namespaces); $count['classes'] = $count['abstractClasses'] + $count['concreteClasses']; $count['functions'] = $count['namedFunctions'] + $count['anonymousFunctions']; $count['constants'] = $count['classConstants'] + $count['globalConstants']; $count['attributeAccesses'] = $count['staticAttributeAccesses'] + $count['instanceAttributeAccesses']; $count['methodCalls'] = $count['staticMethodCalls'] + $count['instanceMethodCalls']; $count['llocGlobal'] = $count['lloc'] - $count['llocClasses'] - $count['llocFunctions']; $count['ncloc'] = $count['loc'] - $count['cloc']; foreach ($this->possibleConstantAccesses as $possibleConstantAccess) { if (in_array($possibleConstantAccess, $this->constants)) { $count['globalConstantAccesses']++; } } $count['globalAccesses'] = $count['globalConstantAccesses'] + $count['globalVariableAccesses'] + $count['superGlobalVariableAccesses']; if ($count['lloc'] > 0) { $count['ccnByLloc'] = $count['ccn'] / $count['lloc']; } if (count($this->classCcn) > 0) { $count['classCcnMin'] = min($this->classCcn); $count['classCcnAvg'] = array_sum($this->classCcn) / count($this->classCcn); $count['classCcnMax'] = max($this->classCcn); } if (count($this->methodCcn) > 0) { $count['methodCcnMin'] = min($this->methodCcn); $count['methodCcnAvg'] = array_sum($this->methodCcn) / count($this->methodCcn); $count['methodCcnMax'] = max($this->methodCcn); } if (count($this->classLloc) > 0) { $count['classLlocMin'] = min($this->classLloc); $count['classLlocAvg'] = array_sum($this->classLloc) / count($this->classLloc); $count['classLlocMax'] = max($this->classLloc); } if (count($this->methodLloc) > 0) { $count['methodLlocMin'] = min($this->methodLloc); $count['methodLlocAvg'] = array_sum($this->methodLloc) / count($this->methodLloc); $count['methodLlocMax'] = max($this->methodLloc); } if ($count['functions'] > 0) { $count['llocByNof'] = $count['llocFunctions'] / $count['functions']; } return $count; } /** * Pre-processes a single file. * * @param string $filename * @since Method available since Release 1.2.0 */ public function preProcessFile($filename) { $tokens = token_get_all(file_get_contents($filename)); $numTokens = count($tokens); $namespace = false; for ($i = 0; $i < $numTokens; $i++) { if (is_string($tokens[$i])) { continue; } switch ($tokens[$i][0]) { case T_NAMESPACE: $namespace = $this->getNamespaceName($tokens, $i); break; case T_CLASS: if (!$this->isClassDeclaration($tokens, $i)) { continue; } $className = $this->getClassName($namespace, $tokens, $i); if (isset($tokens[$i+4]) && is_array($tokens[$i+4]) && $tokens[$i+4][0] == T_EXTENDS) { $parent = $this->getClassName($namespace, $tokens, $i + 4); } else { $parent = null; } $this->classes[$className] = $parent; break; } } } /** * Processes a single file. * * @param string $filename * @param bool $countTests */ public function countFile($filename, $countTests) { $buffer = file_get_contents($filename); $this->count['loc'] += substr_count($buffer, "\n"); $tokens = token_get_all($buffer); $numTokens = count($tokens); unset($buffer); $this->count['files']++; $blocks = []; $currentBlock = false; $namespace = false; $className = null; $functionName = null; $testClass = false; $currentClassData = null; $currentMethodData = null; for ($i = 0; $i < $numTokens; $i++) { if (is_string($tokens[$i])) { $token = trim($tokens[$i]); if ($token == ';') { if ($className !== null && !$testClass) { $this->count['llocClasses']++; $currentClassData['lloc']++; if ($functionName !== null) { $currentMethodData['lloc']++; } } elseif ($functionName !== null) { $this->count['llocFunctions']++; } $this->count['lloc']++; } elseif ($token == '?' && !$testClass) { if ($className !== null) { $this->count['ccnMethods']++; $currentClassData['ccn']++; $currentMethodData['ccn']++; } $this->count['ccn']++; } elseif ($token == '{') { if ($currentBlock == T_CLASS) { $block = $className; } elseif ($currentBlock == T_FUNCTION) { $block = $functionName; } else { $block = false; } array_push($blocks, $block); $currentBlock = false; } elseif ($token == '}') { $block = array_pop($blocks); if ($block !== false && $block !== null) { if ($block == $functionName) { $functionName = null; if ($currentMethodData !== null) { $this->methodCcn[] = $currentMethodData['ccn']; $this->methodLloc[] = $currentMethodData['lloc']; $currentMethodData = null; } } elseif ($block == $className) { $className = null; $testClass = false; $this->classCcn[] = $currentClassData['ccn']; $this->classLloc[] = $currentClassData['lloc']; $currentClassData = null; } } } continue; } list ($token, $value) = $tokens[$i]; switch ($token) { case T_NAMESPACE: $namespace = $this->getNamespaceName($tokens, $i); if (!isset($this->namespaces[$namespace])) { $this->namespaces[$namespace] = true; } break; case T_USE; while($tokens[++$i][0] !== ";" && $i < $numTokens); $i--; continue; case T_CLASS: case T_INTERFACE: case T_TRAIT: if (!$this->isClassDeclaration($tokens, $i)) { continue; } $currentClassData = ['ccn' => 1, 'lloc' => 0]; $className = $this->getClassName($namespace, $tokens, $i); $currentBlock = T_CLASS; if ($token == T_TRAIT) { $this->count['traits']++; } elseif ($token == T_INTERFACE) { $this->count['interfaces']++; } else { if ($countTests && $this->isTestClass($className)) { $testClass = true; $this->count['testClasses']++; } else { if (isset($tokens[$i-2]) && is_array($tokens[$i-2]) && $tokens[$i-2][0] == T_ABSTRACT) { $this->count['abstractClasses']++; } else { $this->count['concreteClasses']++; } } } break; case T_FUNCTION: $currentBlock = T_FUNCTION; $next = $this->getNextNonWhitespaceTokenPos($tokens, $i); if (!is_array($tokens[$next]) && $tokens[$next] == '&') { $next = $this->getNextNonWhitespaceTokenPos($tokens, $next); } if (is_array($tokens[$next]) && $tokens[$next][0] == T_STRING) { $functionName = $tokens[$next][1]; } else { $currentBlock = 'anonymous function'; $functionName = 'anonymous function'; $this->count['anonymousFunctions']++; } if ($currentBlock == T_FUNCTION) { if ($className === null && $functionName != 'anonymous function') { $this->count['namedFunctions']++; } else { $static = false; $visibility = T_PUBLIC; for ($j = $i; $j > 0; $j--) { if (is_string($tokens[$j])) { if ($tokens[$j] == '{' || $tokens[$j] == '}' || $tokens[$j] == ';') { break; } continue; } if (isset($tokens[$j][0])) { switch ($tokens[$j][0]) { case T_PRIVATE: $visibility = T_PRIVATE; break; case T_PROTECTED: $visibility = T_PROTECTED; break; case T_STATIC: $static = true; break; } } } if ($testClass && $this->isTestMethod($functionName, $visibility, $static, $tokens, $i)) { $this->count['testMethods']++; } elseif (!$testClass) { $currentMethodData = ['ccn' => 1, 'lloc' => 0]; if (!$static) { $this->count['nonStaticMethods']++; } else { $this->count['staticMethods']++; } if ($visibility == T_PUBLIC) { $this->count['publicMethods']++; } else { $this->count['nonPublicMethods']++; } $this->count['methods']++; } } } break; case T_CURLY_OPEN: $currentBlock = T_CURLY_OPEN; array_push($blocks, $currentBlock); break; case T_DOLLAR_OPEN_CURLY_BRACES: $currentBlock = T_DOLLAR_OPEN_CURLY_BRACES; array_push($blocks, $currentBlock); break; case T_IF: case T_ELSEIF: case T_FOR: case T_FOREACH: case T_WHILE: case T_CASE: case T_CATCH: case T_BOOLEAN_AND: case T_LOGICAL_AND: case T_BOOLEAN_OR: case T_LOGICAL_OR: if (!$testClass) { if ($currentMethodData !== null) { $this->count['ccnMethods']++; $currentClassData['ccn']++; $currentMethodData['ccn']++; } $this->count['ccn']++; } break; case T_COMMENT: case T_DOC_COMMENT: // We want to count all intermediate lines before the token ends // But sometimes a new token starts after a newline, we don't want to count that. // That happend with /* */ and /** */, but not with // since it'll end at the end $this->count['cloc'] += substr_count(rtrim($value, "\n"), "\n") + 1; break; case T_CONST: $this->count['classConstants']++; break; case T_STRING: if ($value == 'define') { $this->count['globalConstants']++; $j = $i + 1; while (isset($tokens[$j]) && $tokens[$j] != ';') { if (is_array($tokens[$j]) && $tokens[$j][0] == T_CONSTANT_ENCAPSED_STRING) { $this->constants[] = str_replace('\'', '', $tokens[$j][1]); break; } $j++; } } else { $this->possibleConstantAccesses[] = $value; } break; case T_DOUBLE_COLON: case T_OBJECT_OPERATOR: $n = $this->getNextNonWhitespaceTokenPos($tokens, $i); $nn = $this->getNextNonWhitespaceTokenPos($tokens, $n); if ($n && $nn && isset($tokens[$n][0]) && ($tokens[$n][0] == T_STRING || $tokens[$n][0] == T_VARIABLE) && $tokens[$nn] == '(') { if ($token == T_DOUBLE_COLON) { $this->count['staticMethodCalls']++; } else { $this->count['instanceMethodCalls']++; } } else { if ($token == T_DOUBLE_COLON && $tokens[$n][0] == T_VARIABLE) { $this->count['staticAttributeAccesses']++; } elseif ($token == T_OBJECT_OPERATOR) { $this->count['instanceAttributeAccesses']++; } } break; case T_GLOBAL: $this->count['globalVariableAccesses']++; break; case T_VARIABLE: if ($value == '$GLOBALS') { $this->count['globalVariableAccesses']++; } elseif (isset($this->superGlobals[$value])) { $this->count['superGlobalVariableAccesses']++; } break; } } } /** * @param array $tokens * @param int $i * @return string * @since Method available since Release 1.3.0 */ private function getNamespaceName(array $tokens, $i) { if (isset($tokens[$i+2][1])) { $namespace = $tokens[$i+2][1]; for ($j = $i+3;; $j += 2) { if (isset($tokens[$j]) && $tokens[$j][0] == T_NS_SEPARATOR) { $namespace .= '\\' . $tokens[$j+1][1]; } else { break; } } return $namespace; } return false; } /** * @param string $namespace * @param array $tokens * @param int $i * @return string * @since Method available since Release 1.3.0 */ private function getClassName($namespace, array $tokens, $i) { $i += 2; $namespaced = false; if (!isset($tokens[$i][1])) { return 'invalid class name'; } $className = $tokens[$i][1]; if ($className === '\\') { $namespaced = true; } while (is_array($tokens[$i+1]) && $tokens[$i+1][0] !== T_WHITESPACE) { $className .= $tokens[++$i][1]; } if (!$namespaced && $namespace !== false) { $className = $namespace . '\\' . $className; } return strtolower($className); } /** * @param string $className * @return bool * @since Method available since Release 1.2.0 */ private function isTestClass($className) { $parent = $this->classes[$className]; $result = false; $count = 0; // Check ancestry for PHPUnit_Framework_TestCase. while ($parent !== null) { $count++; if ($count > 100) { // Prevent infinite loops and just bail break; } if ($parent == 'phpunit_framework_testcase' || $parent == '\\phpunit_framework_testcase') { $result = true; break; } if (isset($this->classes[$parent]) && $parent !== $this->classes[$parent]) { $parent = $this->classes[$parent]; } else { // Class has a parent that is declared in a file // that was not pre-processed. break; } } // Fallback: Treat the class as a test case class if the name // of the parent class ends with "TestCase". if (!$result) { if (substr($this->classes[$className], -8) == 'testcase') { $result = true; } } return $result; } /** * @param string $functionName * @param int $visibility * @param bool $static * @param array $tokens * @param int $currentToken * @return bool * @since Method available since Release 2.0.0 */ private function isTestMethod($functionName, $visibility, $static, array $tokens, $currentToken) { if ($static || $visibility != T_PUBLIC) { return false; } if (strpos($functionName, 'test') === 0) { return true; } while ($tokens[$currentToken][0] != T_DOC_COMMENT) { if ($tokens[$currentToken] == '{' || $tokens[$currentToken] == '}') { return false; } --$currentToken; } return strpos($tokens[$currentToken][1], '@test') !== false || strpos($tokens[$currentToken][1], '@scenario') !== false; } /** * @param array $tokens * @param int $start * @return bool */ private function getNextNonWhitespaceTokenPos(array $tokens, $start) { if (isset($tokens[$start+1])) { if (isset($tokens[$start+1][0]) && $tokens[$start+1][0] == T_WHITESPACE && isset($tokens[$start+2])) { return $start + 2; } else { return $start + 1; } } return false; } /** * @param array $tokens * @param int $start * @return bool */ private function getPreviousNonWhitespaceTokenPos(array $tokens, $start) { if (isset($tokens[$start-1])) { if (isset($tokens[$start-1][0]) && $tokens[$start-1][0] == T_WHITESPACE && isset($tokens[$start-2])) { return $start - 2; } else { return $start - 1; } } return false; } /** * @param array $tokens * @param int $i * @return bool */ private function isClassDeclaration(array $tokens, $i) { $n = $this->getPreviousNonWhitespaceTokenPos($tokens, $i); if (isset($tokens[$n]) && is_array($tokens[$n]) && $tokens[$n][0] == T_DOUBLE_COLON) { return false; } return true; } } phploc-3.0.0/src/CLI/000077500000000000000000000000001264542240500142015ustar00rootroot00000000000000phploc-3.0.0/src/CLI/Application.php000066400000000000000000000050631264542240500171610ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\PHPLOC\CLI; use SebastianBergmann\Version; use Symfony\Component\Console\Application as AbstractApplication; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\ArrayInput; /** * TextUI frontend for PHPLOC. * * @since Class available since Release 2.0.0 */ class Application extends AbstractApplication { public function __construct() { $version = new Version('3.0.0', dirname(dirname(__DIR__))); parent::__construct('phploc', $version->getVersion()); } /** * Gets the name of the command based on input. * * @param InputInterface $input The input interface * * @return string The command name */ protected function getCommandName(InputInterface $input) { return 'phploc'; } /** * Gets the default commands that should always be available. * * @return array An array of default Command instances */ protected function getDefaultCommands() { $defaultCommands = parent::getDefaultCommands(); $defaultCommands[] = new Command; return $defaultCommands; } /** * Overridden so that the application doesn't expect the command * name to be the first argument. */ public function getDefinition() { $inputDefinition = parent::getDefinition(); $inputDefinition->setArguments(); return $inputDefinition; } /** * Runs the current application. * * @param InputInterface $input An Input instance * @param OutputInterface $output An Output instance * * @return int 0 if everything went fine, or an error code */ public function doRun(InputInterface $input, OutputInterface $output) { if (!$input->hasParameterOption('--quiet')) { $output->write( sprintf( "phploc %s by Sebastian Bergmann.\n\n", $this->getVersion() ) ); } if ($input->hasParameterOption('--version') || $input->hasParameterOption('-V')) { exit; } if (!$input->getFirstArgument()) { $input = new ArrayInput(['--help']); } parent::doRun($input, $output); } } phploc-3.0.0/src/CLI/Command.php000066400000000000000000000170251264542240500162750ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\PHPLOC\CLI; use SebastianBergmann\FinderFacade\FinderFacade; use SebastianBergmann\Git\Git; use SebastianBergmann\PHPLOC\Analyser; use SebastianBergmann\PHPLOC\Log\CSV\History; use SebastianBergmann\PHPLOC\Log\CSV\Single; use SebastianBergmann\PHPLOC\Log\Text; use SebastianBergmann\PHPLOC\Log\XML; use Symfony\Component\Console\Command\Command as AbstractCommand; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Helper\ProgressBar; /** * @since Class available since Release 2.0.0 */ class Command extends AbstractCommand { /** * Configures the current command. */ protected function configure() { $this->setName('phploc') ->setDefinition( [ new InputArgument( 'values', InputArgument::IS_ARRAY ) ] ) ->addOption( 'names', null, InputOption::VALUE_REQUIRED, 'A comma-separated list of file names to check', ['*.php'] ) ->addOption( 'names-exclude', null, InputOption::VALUE_REQUIRED, 'A comma-separated list of file names to exclude', [] ) ->addOption( 'count-tests', null, InputOption::VALUE_NONE, 'Count PHPUnit test case classes and test methods' ) ->addOption( 'git-repository', null, InputOption::VALUE_REQUIRED, 'Collect metrics over the history of a Git repository' ) ->addOption( 'exclude', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Exclude a directory from code analysis' ) ->addOption( 'log-csv', null, InputOption::VALUE_REQUIRED, 'Write result in CSV format to file' ) ->addOption( 'log-xml', null, InputOption::VALUE_REQUIRED, 'Write result in XML format to file' ) ->addOption( 'progress', null, InputOption::VALUE_NONE, 'Show progress bar' ); } /** * Executes the current command. * * @param InputInterface $input An InputInterface instance * @param OutputInterface $output An OutputInterface instance * * @return null|int null or 0 if everything went fine, or an error code */ protected function execute(InputInterface $input, OutputInterface $output) { if (!$input->getOption('git-repository')) { return $this->executeSingle($input, $output); } else { return $this->executeHistory($input, $output); } } /** * @param InputInterface $input An InputInterface instance * @param OutputInterface $output An OutputInterface instance * * @return null|int null or 0 if everything went fine, or an error code */ private function executeSingle(InputInterface $input, OutputInterface $output) { $count = $this->count( $input->getArgument('values'), $input->getOption('exclude'), $this->handleCSVOption($input, 'names'), $this->handleCSVOption($input, 'names-exclude'), $input->getOption('count-tests') ); if (!$count) { $output->writeln('No files found to scan'); exit(1); } $printer = new Text; $printer->printResult( $output, $count, $input->getOption('count-tests') ); if ($input->getOption('log-csv')) { $printer = new Single; $printer->printResult($input->getOption('log-csv'), $count); } if ($input->getOption('log-xml')) { $printer = new XML; $printer->printResult($input->getOption('log-xml'), $count); } } /** * @param InputInterface $input An InputInterface instance * @param OutputInterface $output An OutputInterface instance * * @return null|int null or 0 if everything went fine, or an error code */ private function executeHistory(InputInterface $input, OutputInterface $output) { $git = new Git($input->getOption('git-repository')); $currentBranch = $git->getCurrentBranch(); $revisions = $git->getRevisions(); $printer = null; $progressBar = null; if ($input->getOption('log-csv')) { $printer = new History($input->getOption('log-csv')); } if ($input->getOption('progress')) { $progressBar = new ProgressBar($output, count($revisions)); $progressBar->start(); } foreach ($revisions as $revision) { $git->checkout($revision['sha1']); $directories = []; foreach ($input->getArgument('values') as $value) { $directory = realpath($value); if ($directory) { $directories[] = $directory; } } $_count = $this->count( $directories, $input->getOption('exclude'), $this->handleCSVOption($input, 'names'), $this->handleCSVOption($input, 'names-exclude'), $input->getOption('count-tests') ); if ($_count) { $_count['commit'] = $revision['sha1']; $_count['date'] = $revision['date']->format(\DateTime::W3C); if ($printer) { $printer->printRow($_count); } } if ($progressBar !== null) { $progressBar->advance(); } } $git->checkout($currentBranch); if ($progressBar !== null) { $progressBar->finish(); $output->writeln(''); } } private function count(array $arguments, $excludes, $names, $namesExclude, $countTests) { try { $finder = new FinderFacade($arguments, $excludes, $names, $namesExclude); $files = $finder->findFiles(); } catch (\InvalidArgumentException $ex) { return false; } if (empty($files)) { return false; } $analyser = new Analyser; return $analyser->countFiles($files, $countTests); } /** * @param InputInterface $input * @param string $option * @return array */ private function handleCSVOption(InputInterface $input, $option) { $result = $input->getOption($option); if (!is_array($result)) { $result = explode(',', $result); array_map('trim', $result); } return $result; } } phploc-3.0.0/src/Log/000077500000000000000000000000001264542240500143135ustar00rootroot00000000000000phploc-3.0.0/src/Log/CSV/000077500000000000000000000000001264542240500147465ustar00rootroot00000000000000phploc-3.0.0/src/Log/CSV/History.php000066400000000000000000000035011264542240500171170ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\PHPLOC\Log\CSV; /** * A CSV ResultPrinter for the TextUI. * * @since Class available since Release 2.0.0 */ class History extends Single { /** * @var resource The file handle for this instance */ protected $file; /** * @var bool Is the file initialized */ protected $isInitialized = false; /** * Construct the history printer * * @param string $filename The name of the file to write to */ public function __construct($filename) { $this->file = fopen($filename, 'w+'); if (!$this->file) { throw new \RuntimeException("Could not open file for writing"); } } /** * Print a single row to the output file * * @param array $data A single row of data */ public function printRow(array $data) { if (!$this->isInitialized) { $this->isInitialized = true; fwrite($this->file, $this->getKeysLine($data)); } fwrite($this->file, $this->getValuesLine($data)); } /** * @param array $count * @return string */ protected function getValuesLine(array $count) { $values = [ 'commit' => $count['commit'], ]; return $count['date'] . ',"' . implode('","', $values) . '",' . parent::getValuesLine($count); } /** * @param array $count * @return string */ protected function getKeysLine(array $count) { $keys = ['Date', 'Commit']; return implode(',', $keys) . ',' . parent::getKeysLine($count); } } phploc-3.0.0/src/Log/CSV/Single.php000066400000000000000000000101501264542240500166750ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\PHPLOC\Log\CSV; /** * A CSV ResultPrinter for the TextUI. * * @since Class available since Release 1.6.0 */ class Single { /** * Mapping between internal and human-readable metric names * * @var array */ private $colmap = [ 'directories' => 'Directories', 'files' => 'Files', 'loc' => 'Lines of Code (LOC)', 'ccnByLloc' => 'Cyclomatic Complexity / Lines of Code', 'cloc' => 'Comment Lines of Code (CLOC)', 'ncloc' => 'Non-Comment Lines of Code (NCLOC)', 'lloc' => 'Logical Lines of Code (LLOC)', 'llocGlobal' => 'LLOC outside functions or classes', 'namespaces' => 'Namespaces', 'interfaces' => 'Interfaces', 'traits' => 'Traits', 'classes' => 'Classes', 'abstractClasses' => 'Abstract Classes', 'concreteClasses' => 'Concrete Classes', 'llocClasses' => 'Classes Length (LLOC)', 'methods' => 'Methods', 'nonStaticMethods' => 'Non-Static Methods', 'staticMethods' => 'Static Methods', 'publicMethods' => 'Public Methods', 'nonPublicMethods' => 'Non-Public Methods', 'methodCcnAvg' => 'Cyclomatic Complexity / Number of Methods', 'functions' => 'Functions', 'namedFunctions' => 'Named Functions', 'anonymousFunctions' => 'Anonymous Functions', 'llocFunctions' => 'Functions Length (LLOC)', 'llocByNof' => 'Average Function Length (LLOC)', 'constants' => 'Constants', 'globalConstants' => 'Global Constants', 'classConstants' => 'Class Constants', 'attributeAccesses' => 'Attribute Accesses', 'instanceAttributeAccesses' => 'Non-Static Attribute Accesses', 'staticAttributeAccesses' => 'Static Attribute Accesses', 'methodCalls' => 'Method Calls', 'instanceMethodCalls' => 'Non-Static Method Calls', 'staticMethodCalls' => 'Static Method Calls', 'globalAccesses' => 'Global Accesses', 'globalVariableAccesses' => 'Global Variable Accesses', 'superGlobalVariableAccesses' => 'Super-Global Variable Accesses', 'globalConstantAccesses' => 'Global Constant Accesses', 'testClasses' => 'Test Classes', 'testMethods' => 'Test Methods' ]; /** * Prints a result set. * * @param string $filename * @param array $count */ public function printResult($filename, array $count) { file_put_contents( $filename, $this->getKeysLine($count) . $this->getValuesLine($count) ); } /** * @param array $count * @return string */ protected function getKeysLine(array $count) { return implode(',', array_values($this->colmap)) . PHP_EOL; } /** * @param array $count * @throws \InvalidArgumentException * @return string */ protected function getValuesLine(array $count) { $values = []; foreach ($this->colmap as $key => $name) { if (isset($count[$key])) { $values[] = $count[$key]; } else { throw new \InvalidArgumentException('Attempted to print row with missing keys'); } } return '"' . implode('","', $values) . '"' . PHP_EOL; } } phploc-3.0.0/src/Log/Text.php000066400000000000000000000205471264542240500157600ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\PHPLOC\Log; use Symfony\Component\Console\Output\OutputInterface; /** * A ResultPrinter for the TextUI. * * @since Class available since Release 1.0.0 */ class Text { /** * Prints a result set. * * @param OutputInterface $output * @param array $count * @param bool $printTests */ public function printResult(OutputInterface $output, array $count, $printTests) { if ($count['directories'] > 0) { $output->write( sprintf( "Directories %10d\n" . "Files %10d\n\n", $count['directories'], $count['files'] ) ); } $format = <<write( sprintf( $format, $count['loc'], $count['cloc'], $count['loc'] > 0 ? ($count['cloc'] / $count['loc']) * 100 : 0, $count['ncloc'], $count['loc'] > 0 ? ($count['ncloc'] / $count['loc']) * 100 : 0, $count['lloc'], $count['loc'] > 0 ? ($count['lloc'] / $count['loc']) * 100 : 0, $count['llocClasses'], $count['lloc'] > 0 ? ($count['llocClasses'] / $count['lloc']) * 100 : 0, $count['classLlocAvg'], $count['classLlocMin'], $count['classLlocMax'], $count['methodLlocAvg'], $count['methodLlocMin'], $count['methodLlocMax'], $count['llocFunctions'], $count['lloc'] > 0 ? ($count['llocFunctions'] / $count['lloc']) * 100 : 0, $count['llocByNof'], $count['llocGlobal'], $count['lloc'] > 0 ? ($count['llocGlobal'] / $count['lloc']) * 100 : 0, $count['ccnByLloc'], $count['classCcnAvg'], $count['classCcnMin'], $count['classCcnMax'], $count['methodCcnAvg'], $count['methodCcnMin'], $count['methodCcnMax'], $count['globalAccesses'], $count['globalConstantAccesses'], $count['globalAccesses'] > 0 ? ($count['globalConstantAccesses'] / $count['globalAccesses']) * 100 : 0, $count['globalVariableAccesses'], $count['globalAccesses'] > 0 ? ($count['globalVariableAccesses'] / $count['globalAccesses']) * 100 : 0, $count['superGlobalVariableAccesses'], $count['globalAccesses'] > 0 ? ($count['superGlobalVariableAccesses'] / $count['globalAccesses']) * 100 : 0, $count['attributeAccesses'], $count['instanceAttributeAccesses'], $count['attributeAccesses'] > 0 ? ($count['instanceAttributeAccesses'] / $count['attributeAccesses']) * 100 : 0, $count['staticAttributeAccesses'], $count['attributeAccesses'] > 0 ? ($count['staticAttributeAccesses'] / $count['attributeAccesses']) * 100 : 0, $count['methodCalls'], $count['instanceMethodCalls'], $count['methodCalls'] > 0 ? ($count['instanceMethodCalls'] / $count['methodCalls']) * 100 : 0, $count['staticMethodCalls'], $count['methodCalls'] > 0 ? ($count['staticMethodCalls'] / $count['methodCalls']) * 100 : 0, $count['namespaces'], $count['interfaces'], $count['traits'], $count['classes'], $count['abstractClasses'], $count['classes'] > 0 ? ($count['abstractClasses'] / $count['classes']) * 100 : 0, $count['concreteClasses'], $count['classes'] > 0 ? ($count['concreteClasses'] / $count['classes']) * 100 : 0, $count['methods'], $count['nonStaticMethods'], $count['methods'] > 0 ? ($count['nonStaticMethods'] / $count['methods']) * 100 : 0, $count['staticMethods'], $count['methods'] > 0 ? ($count['staticMethods'] / $count['methods']) * 100 : 0, $count['publicMethods'], $count['methods'] > 0 ? ($count['publicMethods'] / $count['methods']) * 100 : 0, $count['nonPublicMethods'], $count['methods'] > 0 ? ($count['nonPublicMethods'] / $count['methods']) * 100 : 0, $count['functions'], $count['namedFunctions'], $count['functions'] > 0 ? ($count['namedFunctions'] / $count['functions']) * 100 : 0, $count['anonymousFunctions'], $count['functions'] > 0 ? ($count['anonymousFunctions'] / $count['functions']) * 100 : 0, $count['constants'], $count['globalConstants'], $count['constants'] > 0 ? ($count['globalConstants'] / $count['constants']) * 100 : 0, $count['classConstants'], $count['constants'] > 0 ? ($count['classConstants'] / $count['constants']) * 100 : 0 ) ); if ($printTests) { $output->write( sprintf( "\nTests\n" . " Classes %10d\n" . " Methods %10d\n", $count['testClasses'], $count['testMethods'] ) ); } } } phploc-3.0.0/src/Log/XML.php000066400000000000000000000024661264542240500154740ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\PHPLOC\Log; /** * An XML ResultPrinter for the TextUI. * * @since Class available since Release 1.1.0 */ class XML { /** * Prints a result set. * * @param string $filename * @param array $count */ public function printResult($filename, array $count) { $document = new \DOMDocument('1.0', 'UTF-8'); $document->formatOutput = true; $root = $document->createElement('phploc'); $document->appendChild($root); if ($count['directories'] > 0) { $root->appendChild( $document->createElement('directories', $count['directories']) ); $root->appendChild( $document->createElement('files', $count['files']) ); } unset($count['directories']); unset($count['files']); foreach ($count as $k => $v) { $root->appendChild( $document->createElement($k, $v) ); } file_put_contents($filename, $document->saveXML()); } } phploc-3.0.0/tests/000077500000000000000000000000001264542240500141455ustar00rootroot00000000000000phploc-3.0.0/tests/AnalyzerTest.php000066400000000000000000000171711264542240500173120ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Tests for the PHPLOC_Analyser class. * * @since Class available since Release 1.3.0 */ class PHPLOC_AnalyserTest extends PHPUnit_Framework_TestCase { /** * @var SebastianBergmann\PHPLOC\Analyser */ protected $analyser; protected function setUp() { $this->resetAnalyser(); } private function resetAnalyser() { $this->analyser = new SebastianBergmann\PHPLOC\Analyser; } public function testWithoutTests() { $this->assertEquals( [ 'files' => 1, 'loc' => 75, 'lloc' => 26, 'llocClasses' => 22, 'llocFunctions' => 1, 'llocGlobal' => 3, 'cloc' => 7, 'ccn' => 2, 'ccnMethods' => 2, 'interfaces' => 1, 'traits' => 0, 'classes' => 2, 'abstractClasses' => 1, 'concreteClasses' => 1, 'functions' => 2, 'namedFunctions' => 1, 'anonymousFunctions' => 1, 'methods' => 4, 'publicMethods' => 2, 'nonPublicMethods' => 2, 'nonStaticMethods' => 3, 'staticMethods' => 1, 'constants' => 2, 'classConstants' => 1, 'globalConstants' => 1, 'testClasses' => 0, 'testMethods' => 0, 'ccnByLloc' => 0.08, 'llocByNof' => 0.5, 'methodCalls' => 6, 'staticMethodCalls' => 4, 'instanceMethodCalls' => 2, 'attributeAccesses' => 6, 'staticAttributeAccesses' => 4, 'instanceAttributeAccesses' => 2, 'globalAccesses' => 4, 'globalVariableAccesses' => 2, 'superGlobalVariableAccesses' => 1, 'globalConstantAccesses' => 1, 'directories' => 0, 'namespaces' => 1, 'ncloc' => 68, 'classCcnMin' => 1, 'classCcnAvg' => 1.65, 'classCcnMax' => 3, 'methodCcnMin' => 1, 'methodCcnAvg' => 1.65, 'methodCcnMax' => 2, 'classLlocMin' => 0, 'classLlocAvg' => 7.3, 'classLlocMax' => 22, 'methodLlocMin' => 4, 'methodLlocAvg' => 5.6, 'methodLlocMax' => 7 ], $this->analyser->countFiles( [__DIR__ . '/_files/source.php'], false ), '', 0.1 ); } public function testWithTests() { $this->assertEquals( [ 'files' => 2, 'loc' => 98, 'lloc' => 26, 'llocClasses' => 22, 'llocFunctions' => 1, 'llocGlobal' => 3, 'cloc' => 11, 'ccn' => 2, 'ccnMethods' => 2, 'interfaces' => 1, 'traits' => 0, 'classes' => 2, 'abstractClasses' => 1, 'concreteClasses' => 1, 'functions' => 2, 'namedFunctions' => 1, 'anonymousFunctions' => 1, 'methods' => 4, 'publicMethods' => 2, 'nonPublicMethods' => 2, 'nonStaticMethods' => 3, 'staticMethods' => 1, 'constants' => 2, 'classConstants' => 1, 'globalConstants' => 1, 'testClasses' => 1, 'testMethods' => 2, 'ccnByLloc' => 0.08, 'llocByNof' => 0.5, 'methodCalls' => 6, 'staticMethodCalls' => 4, 'instanceMethodCalls' => 2, 'attributeAccesses' => 6, 'staticAttributeAccesses' => 4, 'instanceAttributeAccesses' => 2, 'globalAccesses' => 4, 'globalVariableAccesses' => 2, 'superGlobalVariableAccesses' => 1, 'globalConstantAccesses' => 1, 'directories' => 0, 'namespaces' => 1, 'ncloc' => 87, 'classCcnMin' => 1, 'classCcnAvg' => 1.5, 'classCcnMax' => 3, 'methodCcnMin' => 1, 'methodCcnAvg' => 1.66, 'methodCcnMax' => 2, 'classLlocMin' => 0, 'classLlocAvg' => 5.5, 'classLlocMax' => 22, 'methodLlocMin' => 4, 'methodLlocAvg' => 5.6, 'methodLlocMax' => 7 ], $this->analyser->countFiles( [ __DIR__ . '/_files/source.php', __DIR__ . '/_files/tests.php' ], true ), '', 0.1 ); } public function testFilesThatExtendPHPUnitTestCaseAreCountedAsTests() { $result = $this->analyser->countFiles( [ __DIR__ . '/_files/tests.php' ], true ); $this->assertEquals(1, $result['testClasses']); } public function testFilesThatIndirectlyExtendPHPUnitTestCaseAreCountedAsTests() { $result = $this->analyser->countFiles( [ __DIR__ . '/_files/twoTestsThatIndirectlyExtendPHPUnitTestCase.php' ], true ); $this->assertEquals(3, $result['testClasses']); } public function testTraitsAreCountedCorrectly() { $result = $this->analyser->countFiles( [ __DIR__ . '/_files/trait.php' ], false ); $this->assertEquals(1, $result['traits']); } /** * @ticket 64 */ public function testIssue64IsFixed() { $result = $this->analyser->countFiles( [ __DIR__ . '/_files/issue_62.php' ], false ); $this->assertEquals(1, $result['cloc']); } /** * @ticket 112 */ public function testIssue112IsFixed() { $result = $this->analyser->countFiles( array( __DIR__ . '/_files/issue_112.php' ), false ); $this->assertEquals(5, $result['loc']); } /** * @ticket 126 * @dataProvider issue126Provider */ public function testIssue126IsFixed($fileNumber, $cloc) { $file = __DIR__ . '/_files/issue_126/issue_126_' . $fileNumber . '.php'; $result = $this->analyser->countFiles(array($file), false); $assertString = sprintf('Failed asserting that %s matches expected %s in issue_126_%d.php', $result['cloc'], $cloc, $fileNumber ); $this->assertEquals($cloc, $result['cloc'], $assertString); $this->resetAnalyser(); } public function issue126Provider() { // issue_126_X.php => CLOC return array( array(1, 1), array(2, 1), array(3, 1), array(4, 2), array(5, 3), array(6, 3), array(7, 3), ); } } phploc-3.0.0/tests/Log/000077500000000000000000000000001264542240500146665ustar00rootroot00000000000000phploc-3.0.0/tests/Log/CSV/000077500000000000000000000000001264542240500153215ustar00rootroot00000000000000phploc-3.0.0/tests/Log/CSV/HistoryTest.php000066400000000000000000000110551264542240500203350ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ class HistoryTest extends \PHPUnit_Framework_TestCase { /** * @var \SebastianBergmann\PHPLOC\Log\CSV\Single */ private $history; private $sample_data = [ [ 'date' => '2014-06-09T00:00:00', 'commit' => 'foo', 'directories' => 1, 'files' => 2, 'loc' => 3, 'ccnByLloc' => 4, 'cloc' => 5, 'ncloc' => 6, 'lloc' => 7, 'llocGlobal' => 8, 'namespaces' => 9, 'interfaces' => 10, 'traits' => 11, 'classes' => 12, 'abstractClasses' => 13, 'concreteClasses' => 14, 'llocClasses' => 15, 'methods' => 16, 'nonStaticMethods' => 17, 'staticMethods' => 18, 'publicMethods' => 19, 'nonPublicMethods' => 20, 'methodCcnAvg' => 21, 'functions' => 22, 'namedFunctions' => 23, 'anonymousFunctions' => 24, 'llocFunctions' => 25, 'llocByNof' => 26, 'constants' => 27, 'globalConstants' => 28, 'classConstants' => 29, 'attributeAccesses' => 30, 'instanceAttributeAccesses' => 31, 'staticAttributeAccesses' => 32, 'methodCalls' => 33, 'instanceMethodCalls' => 34, 'staticMethodCalls' => 35, 'globalAccesses' => 36, 'globalVariableAccesses' => 37, 'superGlobalVariableAccesses' => 38, 'globalConstantAccesses' => 39, 'testClasses' => 40, 'testMethods' => 41 ], [ 'date' => '2014-07-09T00:00:00', 'commit' => 'bar', 'directories' => 42, 'files' => 43, 'loc' => 44, 'ccnByLloc' => 45, 'cloc' => 46, 'ncloc' => 47, 'lloc' => 48, 'llocGlobal' => 49, 'namespaces' => 50, 'interfaces' => 51, 'traits' => 52, 'classes' => 53, 'abstractClasses' => 54, 'concreteClasses' => 55, 'llocClasses' => 56, 'methods' => 57, 'nonStaticMethods' => 58, 'staticMethods' => 59, 'publicMethods' => 60, 'nonPublicMethods' => 61, 'methodCcnAvg' => 62, 'functions' => 63, 'namedFunctions' => 64, 'anonymousFunctions' => 65, 'llocFunctions' => 66, 'llocByNof' => 67, 'constants' => 68, 'globalConstants' => 69, 'classConstants' => 70, 'attributeAccesses' => 71, 'instanceAttributeAccesses' => 72, 'staticAttributeAccesses' => 73, 'methodCalls' => 74, 'instanceMethodCalls' => 75, 'staticMethodCalls' => 76, 'globalAccesses' => 77, 'globalVariableAccesses' => 78, 'superGlobalVariableAccesses' => 79, 'globalConstantAccesses' => 80, 'testClasses' => 81, 'testMethods' => 82 ] ]; public function setUp() { $this->history = new \SebastianBergmann\PHPLOC\Log\CSV\History('php://output'); } public function testPrintedResultContainsHeadings() { ob_start(); foreach ($this->sample_data as $row) { $this->history->printRow($row); } $output = ob_get_clean(); $this->assertRegExp('#^Date,Commit,Directories,Files.+$#mis', $output, "Printed result does not contain a heading line"); } public function testPrintedResultContainsData() { ob_start(); foreach ($this->sample_data as $row) { $this->history->printRow($row); } $output = ob_get_clean(); $this->assertRegExp('#^2014-06-09T00:00:00,"foo","1".+$#mis', $output, "Printed result does not contain a value line"); } public function testExactlyThreeRowsArePrinted() { ob_start(); foreach ($this->sample_data as $row) { $this->history->printRow($row); } $output = ob_get_clean(); $rows = explode("\n", trim($output)); $this->assertEquals(3, count($rows), "Printed result contained more or less than expected 2 rows"); } } phploc-3.0.0/tests/Log/CSV/SingleTest.php000066400000000000000000000070331264542240500201160ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ class SingleTest extends \PHPUnit_Framework_TestCase { /** * @var \SebastianBergmann\PHPLOC\Log\CSV\Single */ private $single; private $sample_row = [ 'directories' => 1, 'files' => 2, 'loc' => 3, 'ccnByLloc' => 4, 'cloc' => 5, 'ncloc' => 6, 'lloc' => 7, 'llocGlobal' => 8, 'namespaces' => 9, 'interfaces' => 10, 'traits' => 11, 'classes' => 12, 'abstractClasses' => 13, 'concreteClasses' => 14, 'llocClasses' => 15, 'methods' => 16, 'nonStaticMethods' => 17, 'staticMethods' => 18, 'publicMethods' => 19, 'nonPublicMethods' => 20, 'methodCcnAvg' => 21, 'functions' => 22, 'namedFunctions' => 23, 'anonymousFunctions' => 24, 'llocFunctions' => 25, 'llocByNof' => 26, 'constants' => 27, 'globalConstants' => 28, 'classConstants' => 29, 'attributeAccesses' => 30, 'instanceAttributeAccesses' => 31, 'staticAttributeAccesses' => 32, 'methodCalls' => 33, 'instanceMethodCalls' => 34, 'staticMethodCalls' => 35, 'globalAccesses' => 36, 'globalVariableAccesses' => 37, 'superGlobalVariableAccesses' => 38, 'globalConstantAccesses' => 39, 'testClasses' => 40, 'testMethods' => 41 ]; public function setUp() { $this->single = new \SebastianBergmann\PHPLOC\Log\CSV\Single(); } public function testPrintedResultContainsHeadings() { ob_start(); $this->single->printResult('php://output', $this->sample_row); $output = ob_get_clean(); $this->assertRegExp('#Directories,Files.+$#is', $output, "Printed result does not contain a heading line"); } public function testPrintedResultContainsData() { ob_start(); $this->single->printResult('php://output', $this->sample_row); $output = ob_get_clean(); $this->assertRegExp('#"1","2".+$#is', $output, "Printed result does not contain a value line"); } public function testPrintedResultContainsEqualNumHeadingsAndValues() { ob_start(); $this->single->printResult('php://output', $this->sample_row); $output = ob_get_clean(); $rows = explode("\n", $output); $headings = explode(",", $rows[0]); $vals = explode(",", $rows[1]); $this->assertEquals( count($headings), count($vals), "Printed result does not contain same number of headings and values" ); } public function testExactlyTwoRowsArePrinted() { ob_start(); $this->single->printResult('php://output', $this->sample_row); $output = ob_get_clean(); $rows = explode("\n", trim($output)); $this->assertEquals(2, count($rows), "Printed result contained more or less than expected 2 rows"); } /** * @expectedException \InvalidArgumentException */ public function testPrintPartialRow() { $count = $this->sample_row; unset($count['llocByNof']); ob_start(); $this->single->printResult('php://output', $count); ob_end_clean(); $this->fail("No exception was raised for malformed input var"); } } phploc-3.0.0/tests/_files/000077500000000000000000000000001264542240500154065ustar00rootroot00000000000000phploc-3.0.0/tests/_files/issue_112.php000066400000000000000000000001011264542240500176220ustar00rootroot00000000000000m(); $o->$m(); $o->a; $o->$a; } public function aPublicMethod() { $a = true ? true : false; c::m(); c::$m(); c::$a; c::$a; c::aConstant; } protected function aProtectedMethod() { if (true) { } $c::m(); $c::$m(); $c::$a; $c::$a; } private function aPrivateMethod() { $function = function() {}; echo "This is {$great}"; echo "This is ${great}"; } } phploc-3.0.0/tests/_files/tests.php000066400000000000000000000004511264542240500172610ustar00rootroot00000000000000