Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
<?php
/**
* Formidable_Sniffs_PHPUnit_PreferAssertStringContainsSniff
*
* Detects $this->assertTrue(str_contains(...)) and converts to $this->assertStringContainsString(...).
* Note: str_contains($haystack, $needle) becomes assertStringContainsString($needle, $haystack).
*
* @package Formidable\Sniffs
*/

namespace Formidable\Sniffs\PHPUnit;

use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;

/**
* Converts assertTrue(str_contains()) and assertNotFalse(strpos()) to assertStringContainsString().
*
* Bad:
* $this->assertTrue( str_contains( $haystack, $needle ) );
* $this->assertNotFalse( strpos( $haystack, $needle ) );
*
* Good:
* $this->assertStringContainsString( $needle, $haystack );
*/
class PreferAssertStringContainsSniff implements Sniff {

/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register() {
return array( T_STRING );
}

/**
* Processes this test, when one of its tokens is encountered.
*
* @param File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token in the stack passed in $tokens.
*
* @return void
*/
public function process( File $phpcsFile, $stackPtr ) {
$tokens = $phpcsFile->getTokens();
$token = $tokens[ $stackPtr ];

// Check for assertTrue, assertFalse, assertNotFalse.
$methodName = strtolower( $token['content'] );

$validMethods = array( 'asserttrue', 'assertfalse', 'assertnotfalse' );

if ( ! in_array( $methodName, $validMethods, true ) ) {
return;
}

// Check that this is a method call ($this-> or self:: or static::).
$prevToken = $phpcsFile->findPrevious( T_WHITESPACE, $stackPtr - 1, null, true );

if ( false === $prevToken ) {
return;
}

if ( $tokens[ $prevToken ]['code'] !== T_OBJECT_OPERATOR && $tokens[ $prevToken ]['code'] !== T_DOUBLE_COLON ) {
return;
}

// Find the opening parenthesis.
$openParen = $phpcsFile->findNext( T_WHITESPACE, $stackPtr + 1, null, true );

if ( false === $openParen || $tokens[ $openParen ]['code'] !== T_OPEN_PARENTHESIS ) {
return;
}

// Find the first argument (skip whitespace).
$firstArg = $phpcsFile->findNext( T_WHITESPACE, $openParen + 1, null, true );

if ( false === $firstArg ) {
return;
}

// Check if first argument is str_contains or strpos function call.
if ( $tokens[ $firstArg ]['code'] !== T_STRING ) {
return;
}

$functionName = strtolower( $tokens[ $firstArg ]['content'] );

if ( 'str_contains' !== $functionName && 'strpos' !== $functionName ) {
return;
}

// Find the opening parenthesis of str_contains.
$funcOpenParen = $phpcsFile->findNext( T_WHITESPACE, $firstArg + 1, null, true );

if ( false === $funcOpenParen || $tokens[ $funcOpenParen ]['code'] !== T_OPEN_PARENTHESIS ) {
return;
}

// Find the matching closing parenthesis of str_contains.
if ( ! isset( $tokens[ $funcOpenParen ]['parenthesis_closer'] ) ) {
return;
}
$funcCloseParen = $tokens[ $funcOpenParen ]['parenthesis_closer'];

// Find the closing parenthesis of assertTrue/assertFalse.
if ( ! isset( $tokens[ $openParen ]['parenthesis_closer'] ) ) {
return;
}
$assertCloseParen = $tokens[ $openParen ]['parenthesis_closer'];

// Check that str_contains is the only argument (no && or || after it).
$nextAfterFunc = $phpcsFile->findNext( T_WHITESPACE, $funcCloseParen + 1, $assertCloseParen, true );

if ( false !== $nextAfterFunc ) {
// There's something else after the str_contains call - skip this.
return;
}

// Parse the two arguments of str_contains.
$args = $this->parseArguments( $phpcsFile, $funcOpenParen, $funcCloseParen );

if ( count( $args ) !== 2 ) {
return;
}

// Determine the new method name.
// assertTrue(str_contains()) -> assertStringContainsString
// assertFalse(str_contains()) -> assertStringNotContainsString
// assertNotFalse(strpos()) -> assertStringContainsString
// assertFalse(strpos()) -> assertStringNotContainsString
if ( 'asserttrue' === $methodName || 'assertnotfalse' === $methodName ) {
$newMethodName = 'assertStringContainsString';
} else {
$newMethodName = 'assertStringNotContainsString';
}

$fix = $phpcsFile->addFixableError(
'Use %s() instead of %s(%s()).',
$stackPtr,
'Found',
array( $newMethodName, $token['content'], $functionName )
);

if ( true === $fix ) {
$this->applyFix( $phpcsFile, $stackPtr, $openParen, $assertCloseParen, $newMethodName, $args );
}
}

/**
* Parse the arguments of a function call.
*
* @param File $phpcsFile The file being scanned.
* @param int $funcOpenParen The opening parenthesis position.
* @param int $funcCloseParen The closing parenthesis position.
*
* @return array Array of argument strings.
*/
private function parseArguments( File $phpcsFile, $funcOpenParen, $funcCloseParen ) {
$tokens = $phpcsFile->getTokens();
$args = array();
$start = $funcOpenParen + 1;
$depth = 0;

$currentArg = '';

for ( $i = $start; $i < $funcCloseParen; $i++ ) {
$tokenCode = $tokens[ $i ]['code'];

// Track nested parentheses.
if ( $tokenCode === T_OPEN_PARENTHESIS || $tokenCode === T_OPEN_SQUARE_BRACKET ) {
$depth++;
$currentArg .= $tokens[ $i ]['content'];
} elseif ( $tokenCode === T_CLOSE_PARENTHESIS || $tokenCode === T_CLOSE_SQUARE_BRACKET ) {
$depth--;
$currentArg .= $tokens[ $i ]['content'];
} elseif ( $tokenCode === T_COMMA && 0 === $depth ) {
// End of argument.
$args[] = trim( $currentArg );
$currentArg = '';
} else {
$currentArg .= $tokens[ $i ]['content'];
}
}

// Add the last argument.
$trimmed = trim( $currentArg );

if ( '' !== $trimmed ) {
$args[] = $trimmed;
}

return $args;
}

/**
* Apply the fix to convert assertTrue(str_contains($haystack, $needle)) to assertStringContainsString($needle, $haystack).
*
* @param File $phpcsFile The file being scanned.
* @param int $methodNamePtr The assertTrue/assertFalse token position.
* @param int $openParen The opening parenthesis of assertTrue.
* @param int $assertCloseParen The closing parenthesis of assertTrue.
* @param string $newMethodName The new method name.
* @param array $args The parsed arguments (haystack, needle).
*
* @return void
*/
private function applyFix( File $phpcsFile, $methodNamePtr, $openParen, $assertCloseParen, $newMethodName, $args ) {
$fixer = $phpcsFile->fixer;

$fixer->beginChangeset();

// Replace the method name.
$fixer->replaceToken( $methodNamePtr, $newMethodName );

// Replace everything between the parentheses with swapped arguments.
// str_contains($haystack, $needle) -> assertStringContainsString($needle, $haystack)
$haystack = $args[0];
$needle = $args[1];

// Remove all tokens between open and close paren.
for ( $i = $openParen + 1; $i < $assertCloseParen; $i++ ) {
$fixer->replaceToken( $i, '' );
}

// Insert the new content after the opening paren.
$fixer->addContent( $openParen, ' ' . $needle . ', ' . $haystack . ' ' );

$fixer->endChangeset();
}
}
1 change: 1 addition & 0 deletions phpcs-sniffs/Formidable/ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<!-- PHPUnit -->
<rule ref="Formidable.PHPUnit.PreferAssertIsArray" />
<rule ref="Formidable.PHPUnit.PreferAssertArrayHasKey" />
<rule ref="Formidable.PHPUnit.PreferAssertStringContains" />

<!-- Commenting -->
<rule ref="Formidable.Commenting.FixIncorrectReturnType" />
Expand Down
6 changes: 3 additions & 3 deletions tests/phpunit/database/test_FrmMigrate.php
Original file line number Diff line number Diff line change
Expand Up @@ -315,11 +315,11 @@ private function assert_collation() {
$collation = $frmdb->collation();

if ( ! empty( $wpdb->charset ) ) {
$this->assertTrue( str_contains( $collation, 'DEFAULT CHARACTER SET' ) );
$this->assertStringContainsString( 'DEFAULT CHARACTER SET', $collation );
}

if ( ! empty( $wpdb->collate ) ) {
$this->assertTrue( str_contains( $collation, 'COLLATE' ) );
$this->assertStringContainsString( 'COLLATE', $collation );
}
}

Expand Down Expand Up @@ -367,7 +367,7 @@ public function test_migrate_from_12_to_current() {
$this->assertEquals( 1, count( $form_actions ), 'Old form settings are not converted to email action.' );

foreach ( $form_actions as $action ) {
$this->assertTrue( str_contains( $action->post_content['email_to'], 'emailto@test.com' ) );
$this->assertStringContainsString( 'emailto@test.com', $action->post_content['email_to'] );
}
}

Expand Down
4 changes: 2 additions & 2 deletions tests/phpunit/emails/test_FrmEmail.php
Original file line number Diff line number Diff line change
Expand Up @@ -678,9 +678,9 @@ public function test_message_user_info() {
$actual = $this->get_private_property( $email, 'message' );

if ( $setting['compare'] === 'Contains' ) {
$this->assertNotFalse( strpos( $actual, 'Referrer:' ) );
$this->assertStringContainsString( 'Referrer:', $actual );
} else {
$this->assertFalse( strpos( $actual, 'Referrer:' ) );
$this->assertStringNotContainsString( 'Referrer:', $actual );
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions tests/phpunit/fields/test_FrmFieldName.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public function test_get_processed_sub_fields() {
$processed_sub_fields = $this->run_private_method( array( $name_field, 'get_processed_sub_fields' ) );

$this->assertEquals( array( 'first', 'middle', 'last' ), array_keys( $processed_sub_fields ) );
$this->assertNotFalse( strpos( $processed_sub_fields['first']['wrapper_classes'], 'frm4' ) );
$this->assertNotFalse( strpos( $processed_sub_fields['middle']['wrapper_classes'], 'frm4' ) );
$this->assertNotFalse( strpos( $processed_sub_fields['last']['wrapper_classes'], 'frm4' ) );
$this->assertStringContainsString( 'frm4', $processed_sub_fields['first']['wrapper_classes'] );
$this->assertStringContainsString( 'frm4', $processed_sub_fields['middle']['wrapper_classes'] );
$this->assertStringContainsString( 'frm4', $processed_sub_fields['last']['wrapper_classes'] );
}
}
6 changes: 3 additions & 3 deletions tests/phpunit/fields/test_FrmFieldType.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ public function test_html_min_number() {
'id' => $form_id,
)
);
$this->assertNotFalse( strpos( $form, ' min="10"' ) );
$this->assertNotFalse( strpos( $form, ' max="999"' ) );
$this->assertNotFalse( strpos( $form, ' step="any"' ) );
$this->assertStringContainsString( ' min="10"', $form );
$this->assertStringContainsString( ' max="999"', $form );
$this->assertStringContainsString( ' step="any"', $form );
}

/**
Expand Down
4 changes: 2 additions & 2 deletions tests/phpunit/misc/test_FrmSimpleBlocksController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public function test_maybe_remove_fade_on_load_for_block_preview() {
$_SERVER['CONTENT_TYPE'] = 'application/json';

if ( is_callable( 'wp_is_json_request' ) ) {
$this->assertFalse( strpos( $this->maybe_remove_fade_on_load_for_block_preview( $form ), 'frm_logic_form' ) );
$this->assertStringNotContainsString( 'frm_logic_form', $this->maybe_remove_fade_on_load_for_block_preview( $form ) );
}

unset( $_SERVER['HTTP_ACCEPT'], $_SERVER['CONTENT_TYPE'] );
$this->assertTrue( str_contains( $this->maybe_remove_fade_on_load_for_block_preview( $form ), 'frm_logic_form' ) );
$this->assertStringContainsString( 'frm_logic_form', $this->maybe_remove_fade_on_load_for_block_preview( $form ) );
}

private function maybe_remove_fade_on_load_for_block_preview( $form ) {
Expand Down
2 changes: 1 addition & 1 deletion tests/phpunit/styles/test_FrmStylesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public function test_save() {
FrmStylesController::save();
$returned = ob_get_clean();

$this->assertNotFalse( strpos( $returned, 'Your styling settings have been saved.' ) );
$this->assertStringContainsString( 'Your styling settings have been saved.', $returned );
$frm_style = new FrmStyle( $style->ID );
$updated_style = $frm_style->get_one();
$this->assertEquals( $style->post_title . ' Updated', $updated_style->post_title );
Expand Down
4 changes: 2 additions & 2 deletions tests/phpunit/styles/test_FrmStylesHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ class test_FrmStylesHelper extends FrmUnitTest {
public function test_get_upload_base() {
$base = FrmStylesHelper::get_upload_base();
$this->assertTrue( isset( $base['baseurl'] ) );
$this->assertTrue( str_contains( $base['baseurl'], 'http://' ) );
$this->assertStringContainsString( 'http://', $base['baseurl'] );

$_SERVER['HTTPS'] = 'on';
$base = FrmStylesHelper::get_upload_base();
$this->assertTrue( str_contains( $base['baseurl'], 'https://' ) );
$this->assertStringContainsString( 'https://', $base['baseurl'] );
}

/**
Expand Down