diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php index fd4c952893..7ec3f5582c 100644 --- a/Tests/bootstrap.php +++ b/Tests/bootstrap.php @@ -45,6 +45,21 @@ ) { require_once $phpcsDir . $ds . 'autoload.php'; require_once $phpcsDir . $ds . 'tests' . $ds . 'bootstrap.php'; // PHPUnit 6.x+ support. + + spl_autoload_register( + function ( $className ) { + // Only try & load our own classes. + if ( stripos( $className, 'WordPressCS' ) !== 0 ) { + return; + } + + $file = realpath( dirname( __DIR__ ) ) . DIRECTORY_SEPARATOR . strtr( str_replace( 'WordPressCS\\', '', $className ), '\\', DIRECTORY_SEPARATOR ) . '.php'; + + if ( file_exists( $file ) ) { + include_once $file; + } + } + ); } else { echo 'Uh oh... can\'t find PHPCS. diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc index aee51ae39a..f1f7ff385e 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc @@ -291,18 +291,18 @@ function function_containing_nested_closure() { }; } -// Tests specifically for the ContextHelper::is_in_function_call(). -function disallow_custom_unslash_before_noncecheck_via_method() { - $var = MyClass::stripslashes_from_strings_only( $_POST['foo'] ); // Bad. - wp_verify_nonce( $var ); - echo $var; -} -function disallow_custom_unslash_before_noncecheck_via_namespaced_function() { - $var = MyNamespace\stripslashes_from_strings_only( $_POST['foo'] ); // Bad. - wp_verify_nonce( $var ); - echo $var; -} + + + + + + + + + + + // Tests specifically for the ContextHelper::is_in_isset_or_empty(). function allow_in_array_key_exists_before_noncecheck() { diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.php b/WordPress/Tests/Security/NonceVerificationUnitTest.php index aa5e832e83..97bf652750 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.php +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.php @@ -59,8 +59,6 @@ public function getErrorList( $testFile = '' ) { 192 => 1, 242 => 1, 259 => 1, - 296 => 1, - 302 => 1, 325 => 1, 329 => 1, 337 => 1, diff --git a/WordPress/Util/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.inc b/WordPress/Util/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.inc new file mode 100644 index 0000000000..36f11ca226 --- /dev/null +++ b/WordPress/Util/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.inc @@ -0,0 +1,57 @@ +my_function( /* test inside function pointer 11 */ $a ); +/* test function call 12 */ $obj?->my_function( /* test inside function pointer 12 */ $a ); + +/* + * Make sure that tokens inside a function call are correctly identified when `$allow_nested` is + * set to true. + * + * The below should be recognized as inside a function call to one of the valid functions. + */ +/* test function call 13 */ my_function( another_function( /* test inside function pointer 13 */ $a ) ); +another_function( /* test function call 14 */ my_function( /* test inside function pointer 14 */ $a ) ); +/* test function call 15 */ my_function( middle_function( inner_function( /* test inside function pointer 15 */ $a ) ) ); diff --git a/WordPress/Util/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.php b/WordPress/Util/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.php new file mode 100644 index 0000000000..0389cfd67b --- /dev/null +++ b/WordPress/Util/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.php @@ -0,0 +1,165 @@ +getTargetToken( $commentString, $tokenType ); + $result = ContextHelper::is_in_function_call( self::$phpcsFile, $stackPtr, array( 'my_function' => true ) ); + $this->assertFalse( $result ); + } + + /** + * Data provider. + * + * @return array + * @see testIsInFunctionCallShouldReturnFalse() + */ + public static function dataIsInFunctionCallShouldReturnFalse() { + return array( + array( '/* test return false 1 */', \T_CONSTANT_ENCAPSED_STRING ), + array( '/* test return false 2 */', \T_VARIABLE ), + array( '/* test return false 3 */', \T_VARIABLE ), + array( '/* test return false 4 */', \T_VARIABLE ), + array( '/* test return false 5 */', \T_VARIABLE ), + array( '/* test return false 6 */', \T_VARIABLE ), + array( '/* test return false 7 */', \T_VARIABLE ), + array( '/* test return false 8 */', \T_VARIABLE ), + ); + } + + /** + * Test is_in_function_call() returns pointer to function name if given token is inside a function call. + * + * @dataProvider dataIsInFunctionCallShouldReturnFunctionPointer + * + * @param string $insideFunctionCommentString The comment which prefaces the target token inside a function in the test file. + * @param int|string $insideFunctionTokenType The token type to search for. + * @param string $functionCallCommentString The comment which prefaces the function call token in the test file. + * + * @return void + */ + public function testIsInFunctionCallShouldReturnFunctionPointer( $insideFunctionCommentString, $insideFunctionTokenType, $functionCallCommentString ) { + $insideFunctionPtr = $this->getTargetToken( $insideFunctionCommentString, $insideFunctionTokenType ); + $functionNamePtr = $this->getTargetToken( $functionCallCommentString, Collections::nameTokens() ); + $result = ContextHelper::is_in_function_call( self::$phpcsFile, $insideFunctionPtr, array( 'my_function' => true ) ); + $this->assertSame( $result, $functionNamePtr ); + } + + /** + * Data provider. + * + * @return array + * @see testIsInFunctionCallShouldReturnFunctionPointer() + */ + public static function dataIsInFunctionCallShouldReturnFunctionPointer() { + return array( + array( '/* test inside function pointer 1 */', \T_VARIABLE, '/* test function call 1 */' ), + array( '/* test inside function pointer 2 */', \T_VARIABLE, '/* test function call 2 */' ), + array( '/* test inside function pointer 3 */', \T_VARIABLE, '/* test function call 3 */' ), + ); + } + + /** + * Test is_in_function_call() returns pointer to function name if given token is inside a + * function call when `$global_functions` is set to false. + * + * @dataProvider dataIsInFunctionCallShouldReturnFunctionPointerWhenGlobalIsFalse + * + * @param string $insideFunctionCommentString The comment which prefaces the target token inside a function in the test file. + * @param int|string $insideFunctionTokenType The token type to search for. + * @param string $functionCallCommentString The comment which prefaces the function call token in the test file. + * + * @return void + */ + public function testIsInFunctionCallShouldReturnFunctionPointerWhenGlobalIsFalse( $insideFunctionCommentString, $insideFunctionTokenType, $functionCallCommentString ) { + $insideFunctionPtr = $this->getTargetToken( $insideFunctionCommentString, $insideFunctionTokenType ); + $functionNamePtr = $this->getTargetToken( $functionCallCommentString, Collections::nameTokens() ); + $result = ContextHelper::is_in_function_call( self::$phpcsFile, $insideFunctionPtr, array( 'my_function' => true ), false ); + $this->assertSame( $result, $functionNamePtr ); + } + + /** + * Data provider. + * + * @return array + * @see testIsInFunctionCallShouldReturnFunctionPointerWhenGlobalIsFalse() + */ + public static function dataIsInFunctionCallShouldReturnFunctionPointerWhenGlobalIsFalse() { + return array( + array( '/* test inside function pointer 4 */', \T_VARIABLE, '/* test function call 4 */' ), + array( '/* test inside function pointer 5 */', \T_VARIABLE, '/* test function call 5 */' ), + array( '/* test inside function pointer 6 */', \T_VARIABLE, '/* test function call 6 */' ), + array( '/* test inside function pointer 7 */', \T_VARIABLE, '/* test function call 7 */' ), + array( '/* test inside function pointer 8 */', \T_VARIABLE, '/* test function call 8 */' ), + array( '/* test inside function pointer 9 */', \T_VARIABLE, '/* test function call 9 */' ), + array( '/* test inside function pointer 10 */', \T_VARIABLE, '/* test function call 10 */' ), + array( '/* test inside function pointer 11 */', \T_VARIABLE, '/* test function call 11 */' ), + array( '/* test inside function pointer 12 */', \T_VARIABLE, '/* test function call 12 */' ), + ); + } + + /** + * Test is_in_function_call() returns pointer to function name if given token is inside a + * function call when `$allow_nested` is set to true. + * + * @dataProvider dataIsInFunctionCallShouldReturnFunctionPointerWhenAllowNestedIsTrue + * + * @param string $insideFunctionCommentString The comment which prefaces the target token inside a function in the test file. + * @param int|string $insideFunctionTokenType The token type to search for. + * @param string $functionCallCommentString The comment which prefaces the function call token in the test file. + * + * @return void + */ + public function testIsInFunctionCallShouldReturnFunctionPointerWhenAllowNestedIsTrue( $insideFunctionCommentString, $insideFunctionTokenType, $functionCallCommentString ) { + $insideFunctionPtr = $this->getTargetToken( $insideFunctionCommentString, $insideFunctionTokenType ); + $functionNamePtr = $this->getTargetToken( $functionCallCommentString, Collections::nameTokens() ); + $result = ContextHelper::is_in_function_call( self::$phpcsFile, $insideFunctionPtr, array( 'my_function' => true ), true, true ); + $this->assertSame( $result, $functionNamePtr ); + } + + /** + * Data provider. + * + * @return array + * @see testIsInFunctionCallShouldReturnFunctionPointerWhenAllowNestedIsTrue() + */ + public static function dataIsInFunctionCallShouldReturnFunctionPointerWhenAllowNestedIsTrue() { + return array( + array( '/* test inside function pointer 13 */', \T_VARIABLE, '/* test function call 13 */' ), + array( '/* test inside function pointer 14 */', \T_VARIABLE, '/* test function call 14 */' ), + array( '/* test inside function pointer 15 */', \T_VARIABLE, '/* test function call 15 */' ), + ); + } +} diff --git a/composer.json b/composer.json index a5afb55f6b..3c1067c0f0 100644 --- a/composer.json +++ b/composer.json @@ -53,10 +53,12 @@ "@php ./vendor/squizlabs/php_codesniffer/bin/phpcbf" ], "run-tests": [ - "@php ./vendor/phpunit/phpunit/phpunit --filter WordPress ./vendor/squizlabs/php_codesniffer/tests/AllTests.php --no-coverage" + "@php ./vendor/phpunit/phpunit/phpunit --filter WordPress ./vendor/squizlabs/php_codesniffer/tests/AllTests.php --no-coverage", + "@php ./vendor/phpunit/phpunit/phpunit WordPress/Util/Tests/ --no-coverage" ], "coverage": [ - "@php ./vendor/phpunit/phpunit/phpunit --filter WordPress ./vendor/squizlabs/php_codesniffer/tests/AllTests.php" + "@php ./vendor/phpunit/phpunit/phpunit --filter WordPress ./vendor/squizlabs/php_codesniffer/tests/AllTests.php", + "@php ./vendor/phpunit/phpunit/phpunit WordPress/Util/Tests/" ], "check-complete": [ "@php ./vendor/phpcsstandards/phpcsdevtools/bin/phpcs-check-feature-completeness -q ./WordPress" diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a7a2b1401f..0f3566b327 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -13,7 +13,10 @@ forceCoversAnnotation="true"> - + + ./WordPress/Util/Tests/ + + ./WordPress/Tests/