├── LICENSE ├── PHPUnitStandard ├── Sniffs │ └── Testing │ │ ├── AllowedFunctionOverrideSniff.php │ │ ├── ClassNameSniff.php │ │ ├── ExtraneousClassSniff.php │ │ ├── FileNameSuffixSniff.php │ │ ├── NoInterfacesSniff.php │ │ ├── NoOutputFunctionsSniff.php │ │ ├── NoOutputStatementsSniff.php │ │ ├── NoPrivateMethodsSniff.php │ │ ├── NoReflectionSniff.php │ │ ├── ProvenTestCaseSniff.php │ │ ├── TestOrProviderFunctionsOnlySniff.php │ │ ├── TestOrProviderIsPublicSniff.php │ │ ├── UnusedProviderSniff.php │ │ └── ValidFunctionNameSniff.php └── ruleset.xml ├── README.md └── package.xml /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Etsy 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /PHPUnitStandard/Sniffs/Testing/AllowedFunctionOverrideSniff.php: -------------------------------------------------------------------------------- 1 | 8 | array( 9 | 'setUp', 10 | 'tearDown', 11 | 'closeConnection', 12 | 'getConnection', 13 | 'getDatabaseTester', 14 | 'getDataSet', 15 | 'getSetUpOperation', 16 | 'getTearDownOperation', 17 | 'newDatabaseTester', 18 | 'createDefaultDBConnection', 19 | 'createFlatXMLDataSet', 20 | 'createXMLDataSet', 21 | 'createMySQLXMLDataSet', 22 | 'getOperations', 23 | ), 24 | 'PHPUnit_Extensions_MultipleDatabase_TestCase' => 25 | array( 26 | 'setUp', 27 | 'tearDown', 28 | 'getDatabaseConfigs', 29 | ), 30 | 'PHPUnit_Extensions_OutputTestCase' => 31 | array( 32 | 'setUp', 33 | 'tearDown', 34 | 'runTest', 35 | ), 36 | 'PHPUnit_Extensions_PhptTestCase' => 37 | array( 38 | 'setUp', 39 | 'tearDown' 40 | ), 41 | 'PHPUnit_Extensions_RepeatedTestCase' => 42 | array( 43 | 'setUp', 44 | 'tearDown' 45 | ), 46 | 'PHPUnit_Framework_TestCase' => 47 | array( 48 | 'setUp', 49 | 'tearDown' 50 | ), 51 | ); 52 | 53 | /** 54 | * Returns the token types that this sniff is interested in. 55 | * 56 | * @return array(int) 57 | */ 58 | public function register() { 59 | return array( 60 | T_FUNCTION, 61 | ); 62 | } 63 | 64 | /** 65 | * Processes the tokens that this sniff is interested in. 66 | * 67 | * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. 68 | * @param int $stackPtr The position in the stack where 69 | * the token was found. 70 | * 71 | * @return void 72 | */ 73 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { 74 | $functionName = $phpcsFile->getDeclarationName($stackPtr); 75 | $classStackPtr = $phpcsFile->findPrevious(T_CLASS, $stackPtr); 76 | $className = $phpcsFile->findExtendedClassName($classStackPtr); 77 | $properties = $phpcsFile->getMethodProperties($stackPtr); 78 | 79 | if (!in_array($className, array_keys($this->functionWhitelist))) { 80 | return; 81 | } 82 | 83 | $allowedFunctions = $this->functionWhitelist[$className]; 84 | 85 | $isProtected = $properties['scope'] === 'protected'; 86 | $isWhitelisted = in_array($functionName, $allowedFunctions); 87 | 88 | if ($isProtected && !$isWhitelisted) { 89 | $phpcsFile->addError( 90 | 'Unexpected protected function encountered. Not a whitelisted override: %s', 91 | $stackPtr, 92 | 'Found', 93 | array($functionName) 94 | ); 95 | } else if (!$isProtected && $isWhitelisted) { 96 | $phpcsFile->addWarning( 97 | 'Expected function to be protected: %s', 98 | $stackPtr, 99 | 'Found', 100 | array($functionName) 101 | ); 102 | } 103 | } 104 | } 105 | 106 | -------------------------------------------------------------------------------- /PHPUnitStandard/Sniffs/Testing/ClassNameSniff.php: -------------------------------------------------------------------------------- 1 | getFileName(); 30 | if(!preg_match("@.*/tests/phpunit/(.*).php@", $filename, $matches)) { 31 | $phpcsFile->addWarning( 32 | 'File path does not match expected convention.', 33 | $stackPtr 34 | ); 35 | return; 36 | } 37 | 38 | $expected = str_replace("/", "_", $matches[1]); 39 | 40 | $found = array(); 41 | while ($stackPtr = $phpcsFile->findNext(T_CLASS, ++$stackPtr)) { 42 | $className = $phpcsFile->getDeclarationName($stackPtr); 43 | if ($className == $expected) { 44 | return; // SUCCESS 45 | } 46 | $found[] = $className; 47 | } 48 | $classNames = '[NONE]'; 49 | if (!empty($found)) { 50 | $classNames = implode(', ', $found); 51 | } 52 | $phpcsFile->addError( 53 | 'File must contain a class named: %s; found %s', 54 | $origStackPtr, 55 | 'Found', 56 | array($expected, $classNames) 57 | ); 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /PHPUnitStandard/Sniffs/Testing/ExtraneousClassSniff.php: -------------------------------------------------------------------------------- 1 | getFileName(); 28 | if(!preg_match("@.*/tests/phpunit/(.*).php@", $filename, $matches)) { 29 | $phpcsFile->addWarning( 30 | 'Filepath does not match expected convention', 31 | $stackPtr 32 | ); 33 | return; 34 | } 35 | $expected = str_replace("/", "_", $matches[1]); 36 | 37 | $declarationName = $phpcsFile->getDeclarationName($stackPtr); 38 | if ($declarationName != $expected) { 39 | $phpcsFile->addError( 40 | 'Unexpected extraneous class found: %s. Expected: %s', 41 | $stackPtr, 42 | 'Found', 43 | array($declarationName, $expected) 44 | ); 45 | } 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /PHPUnitStandard/Sniffs/Testing/FileNameSuffixSniff.php: -------------------------------------------------------------------------------- 1 | getFileName(); 28 | if (!preg_match("@.*$this->suffix@", $fileName)) { 29 | $phpcsFile->addError( 30 | "Test file must end with $this->suffix", 31 | $stackPtr 32 | ); 33 | } 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /PHPUnitStandard/Sniffs/Testing/NoInterfacesSniff.php: -------------------------------------------------------------------------------- 1 | getDeclarationName($stackPtr); 28 | $phpcsFile->addError( 29 | 'No interfaces allowed in tests; found %s', 30 | $stackPtr, 31 | 'Found', 32 | array($interfaceName) 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /PHPUnitStandard/Sniffs/Testing/NoOutputFunctionsSniff.php: -------------------------------------------------------------------------------- 1 | NULL, 6 | 'print_r' => NULL, 7 | 'var_dump' => NULL, 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /PHPUnitStandard/Sniffs/Testing/NoOutputStatementsSniff.php: -------------------------------------------------------------------------------- 1 | addError( 12 | 'The use of the "echo" and "print" keywords is forbidden in tests', 13 | $stackPtr, 14 | 'NotAllowed', 15 | array() 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /PHPUnitStandard/Sniffs/Testing/NoPrivateMethodsSniff.php: -------------------------------------------------------------------------------- 1 | getMethodProperties($stackPtr); 26 | if ($properties['scope'] === 'private') { 27 | $phpcsFile->addError( 28 | 'Private methods are prohibited; found %s', 29 | $stackPtr, 30 | 'Found', 31 | array($phpcsFile->getDeclarationName($stackPtr)) 32 | ); 33 | } 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /PHPUnitStandard/Sniffs/Testing/NoReflectionSniff.php: -------------------------------------------------------------------------------- 1 | getTokens(); 12 | $className = $phpcsFile->findNext( 13 | T_WHITESPACE, ($stackPtr + 1), NULL, TRUE 14 | ); 15 | 16 | if ($tokens[$className]['code'] === T_STRING && 17 | strpos($tokens[$className]['content'], 'Reflection') === 0) { 18 | $phpcsFile->addError( 19 | 'Reflection API usage found', 20 | $stackPtr, 21 | 'NotAllowed', 22 | array() 23 | ); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /PHPUnitStandard/Sniffs/Testing/ProvenTestCaseSniff.php: -------------------------------------------------------------------------------- 1 | getDeclarationName($stackPtr); 37 | $extendedClassName = $phpcsFile->findExtendedClassName($stackPtr); 38 | if (!($extendedClassName 39 | && in_array($extendedClassName, $this->classNameWhitelist)) 40 | ) { 41 | $phpcsFile->addError( 42 | 'Must extend a proven PHPUnit_Framework_TestCase class; found %s.', 43 | $stackPtr, 44 | 'Found', 45 | array($extendedClassName) 46 | ); 47 | } 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /PHPUnitStandard/Sniffs/Testing/TestOrProviderFunctionsOnlySniff.php: -------------------------------------------------------------------------------- 1 | findPrevious(T_CLASS, $stackPtr); 28 | $className = $phpcsFile->getDeclarationName($classStackPtr); 29 | $properties = $phpcsFile->getMethodProperties($stackPtr); 30 | $functionName = $phpcsFile->getDeclarationName($stackPtr); 31 | if (!in_array($properties['scope'], array('private', 'protected'))) { 32 | if (preg_match('@(test|provide)[A-Z_].*@', $functionName)) { 33 | return; 34 | } 35 | $phpcsFile->addError( 36 | 'Found a public method that is not a test or a provider: %s', 37 | $stackPtr, 38 | 'Found', 39 | array($functionName) 40 | ); 41 | } 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /PHPUnitStandard/Sniffs/Testing/TestOrProviderIsPublicSniff.php: -------------------------------------------------------------------------------- 1 | findPrevious(T_CLASS, $stackPtr); 28 | $className = $phpcsFile->getDeclarationName($classStackPtr); 29 | $properties = $phpcsFile->getMethodProperties($stackPtr); 30 | $functionName = $phpcsFile->getDeclarationName($stackPtr); 31 | if (in_array($properties['scope'], array('private', 'protected'))) { 32 | if (!preg_match('@(test|provider)[A-Z_].*@', $functionName)) { 33 | return; 34 | } 35 | $phpcsFile->addWarning( 36 | 'Found non-public test or provider function: %s', 37 | $stackPtr, 38 | 'Found', 39 | array($functionName) 40 | ); 41 | } 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /PHPUnitStandard/Sniffs/Testing/UnusedProviderSniff.php: -------------------------------------------------------------------------------- 1 | findPrevious(T_CLASS, $stackPtr); 28 | $className = $phpcsFile->getDeclarationName($classStackPtr); 29 | 30 | $functionName = $phpcsFile->getDeclarationName($stackPtr); 31 | if (!preg_match('@provide[A-Z_].*@', $functionName)) { 32 | return; 33 | } 34 | 35 | $tokens = $phpcsFile->getTokens(); 36 | $commentStackPtr = 1; 37 | while ($commentStackPtr = 38 | $phpcsFile->findNext(T_DOC_COMMENT, ++$commentStackPtr) 39 | ) { 40 | $commentLine = $tokens[$commentStackPtr]['content']; 41 | if (preg_match("/\*\s+@dataProvider\s+$functionName/", $commentLine)) { 42 | return; 43 | } 44 | } 45 | $phpcsFile->addError( 46 | 'Unused provider method: %s', 47 | $stackPtr, 48 | 'Found', 49 | array($functionName) 50 | ); 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /PHPUnitStandard/Sniffs/Testing/ValidFunctionNameSniff.php: -------------------------------------------------------------------------------- 1 | getDeclarationName($stackPtr); 16 | if ($methodName === null) { 17 | return; // Ignore closures 18 | } 19 | $className = $phpcsFile->getDeclarationName($currScope); 20 | $errorData = array($className . '::' . $methodName); 21 | 22 | if (preg_match(';^(test|provider)(.*);', $methodName, $matches) !== 0) { 23 | if (empty($matches[2])) { 24 | $phpcsFile->addError( 25 | 'Method name cannot just be "%s"', 26 | $stackPtr, 27 | 'TestOrProviderOnly', 28 | array($matches[1]) 29 | ); 30 | return; 31 | } 32 | $parts = explode('_', $matches[2]); 33 | 34 | if (count($parts) > 2) { 35 | $phpcsFile->addError( 36 | 'Method name "%s" cannot have more than one dividing underscore.', 37 | $stackPtr, 38 | 'TooManyParts', 39 | $errorData 40 | ); 41 | } 42 | 43 | if (preg_match(';_$;', $methodName) !== 0) { 44 | $phpcsFile->addError( 45 | 'Method name "%s" cannot end with an underscore.', 46 | $stackPtr, 47 | 'UnderscoreEnding', 48 | $errorData 49 | ); 50 | } 51 | 52 | if (!empty($parts[0]) 53 | && PHP_CodeSniffer::isCamelCaps($parts[0], true, true, false) === false) { 54 | $phpcsFile->addError( 55 | 'First part "%s" is not camel caps format with or without "%s".', 56 | $stackPtr, 57 | 'NotCamelCaps', 58 | array( 59 | $parts[0], 60 | $matches[1] 61 | ) 62 | ); 63 | 64 | } 65 | 66 | if (count($parts) > 1 67 | && !empty($parts[1]) 68 | && PHP_CodeSniffer::isCamelCaps($parts[1], false, true, false) === false) { 69 | $phpcsFile->addError( 70 | 'Second part "%s" is not camel caps format.', 71 | $stackPtr, 72 | 'NotCamelCaps', 73 | array($parts[1]) 74 | ); 75 | } 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /PHPUnitStandard/ruleset.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | The Etsy coding standard for testing. 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | See PEAR channel instructions at: http://elblinkin.github.com/Pirum/ 2 | 3 | Note: My apologies, but the sniffs might have a few rough edges around them. Will be cleaning up and adding documentation soon. -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | PHPUnitStandard 7 | pear.elblinkin.info 8 | PHP CodeSniffer Standard for PHPUnit tests. 9 | 10 | PHP CodeSniffer Standard for PHPUnit tests. 11 | 12 | 13 | Laura Beth Lincoln Denker 14 | elblinkin 15 | github@elblinkin.info 16 | yes 17 | 18 | 2012-02-13 19 | 20 | 0.2.0 21 | 0.2.0 22 | 23 | 24 | beta 25 | beta 26 | 27 | MIT 28 | - 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 5.2.17 58 | 59 | 60 | 1.9.1 61 | 62 | 63 | PHP_CodeSniffer 64 | pear 65 | 1.3.0 66 | 67 | 68 | 69 | 70 | 71 | --------------------------------------------------------------------------------