Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update term edit link generation in WP_Terms_List_Table::handle_row_actions() #5198

Closed

Conversation

thelovekesh
Copy link
Member

Restrict edit term link generation if the user lacks the edit_term cap.

Trac ticket: https://core.trac.wordpress.org/ticket/59336


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

…_actions()`

- Restrict edit terms link generation if user lacks `edit_term` cap.
Copy link
Member

@jrfnl jrfnl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a good change.

✔️ Checked: The $edit_link variable is not used in any other place in the function.

❌ Missing: a unit test to proof the bug and safeguard the fix. Please add one.

Coding standards wise, I'd prefer to still keep the creation of the URL separate from the creation of the HTML as it makes the code more readable without the nested function calls.

@thelovekesh
Copy link
Member Author

@jrfnl Since the above patch only eliminates a variable assignment and uses the expression directly, I'm not sure if it actually necessitates a test case. The function add_query_arg(), becomes the cause of the issue when passing the URL as null in it and it should be handled separately IMO.

Should I add a test case to Tests_Functions::test_add_query_arg() to assert deprecations? But in my opinion, this is outside the purview of this PR. Please point me in the right direction.

@jrfnl
Copy link
Member

jrfnl commented Sep 13, 2023

@jrfnl Since the above patch only eliminates a variable assignment and uses the expression directly, I'm not sure if it actually necessitates a test case. The function add_query_arg(), becomes the cause of the issue when passing the URL as null in it and it should be handled separately IMO.

Sorry, but no. The add_query_arg() function is doing things 100% correctly. This function is the one doing it wrong as it is passing data which is not within the accepted data types for the add_query_arg() function.

So, it is this function which needs a test proving the PHP 8.1 issue and safeguarding the fix.

@thelovekesh thelovekesh requested a review from jrfnl September 14, 2023 13:09
Copy link
Member

@jrfnl jrfnl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @thelovekesh, thank you for adding those tests!

The test_handle_row_actions_should_generate_deprecation_notice() test can be removed. The test_handle_row_actions() test is sufficient.

I've checked this in the following manner:

  1. Using PHP 8.1 or higher (in my case PHP 8.3-RC1).
  2. Revert the first commit containing the fix.
  3. In my local phpunit.xml overload file, set convertDeprecationsToExceptions="false".
  4. Ran the test(s).
    This will show the following as part of the output:
    2) Tests_Admin_WpTermsListTable::test_handle_row_actions
    This test printed output:
    Deprecated: strstr(): Passing null to parameter #1 ($haystack) of type string is deprecated in path\to\src\wp-includes\functions.php on line 1147
    
    Deprecated: stripos(): Passing null to parameter #1 ($haystack) of type string is deprecated in path\to\src\wp-includes\functions.php on line 1154
    
    Deprecated: stripos(): Passing null to parameter #1 ($haystack) of type string is deprecated in path\to\src\wp-includes\functions.php on line 1157
    
    Deprecated: str_contains(): Passing null to parameter #1 ($haystack) of type string is deprecated in path\to\src\wp-includes\functions.php on line 1164
    
    Deprecated: str_contains(): Passing null to parameter #1 ($haystack) of type string is deprecated in path\to\src\wp-includes\functions.php on line 1167
    
    This proves the bug you were reporting and also confirms that the test_handle_row_actions() alone is sufficient to proof the bug and safeguard the fix.
  5. Brought back the first commit containing the fix.
  6. Ran the tests again and the test_handle_row_actions() test now passes without notices.

Pro-tip for future patches for these type of issues: have the tests in a separate commit (like you already did 👍🏻 ) and let that be the first commit.
Then in the second commit, add the patch fixing the issue.

That way a reviewer can just check out the first commit, run the tests, see the problem, check out the head of the patch branch and confirm that the issue is fixed.

* @return mixed Return value of the method call.
* @throws ReflectionException If the object could not be reflected upon.
*/
private function call_private_method( $object, $method_name, $args = array() ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private function call_private_method( $object, $method_name, $args = array() ) {
private function call_inaccessible_method( $object, $method_name, $args = array() ) {

Reason: the function you are calling is protected, not private, so the suggested new name is more appropriate.

*
* @covers WP_Terms_List_Table::handle_row_actions()
*/
public function test_handle_row_actions_should_generate_deprecation_notice() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This complete test can be removed as it is unnecessary.

Comment on lines 81 to 89
set_error_handler(
static function ( $errno, $errstr ) {
throw new ErrorException( $errstr, $errno );
},
E_ALL
);

$this->expectException( ErrorException::class );
$this->expectExceptionMessageMatches( '/^strstr\(\): Passing null to parameter #1 \(\$haystack\) of type string is deprecated/' );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a side-note (as the test should be removed): why are you setting a custom error handler here ?

WP is using PHPUnit 6 - 9 with the PHPUnit Polyfills, so this could/should be $this->expectDeprecation() + $this->expectDeprecationMessage().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the custom error handler while keeping in mind that PHPUnit 10 has removed these fixtures. But I think my concern is invalid as PHPUnit polyfills are in play here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it's not about the PHPUnit Polyfills (as they make tests forward-compatible, not backward-compatible), it's about the WP Test suite not (yet) supporting PHPUnit 10.

While that's the case, tests should be written for the supported versions of the dependency (PHPUnit 6-9), not for a future version which is not yet supported.

This will make it easier for when the WP Test suite will be made compatible with PHPUnit 10, as in that case, all code which needs to be updated can easily be found via code searches and the same solution (probably extracted away in one of the base TestCase classes), can be used everywhere.

Having one-off "solutions" like this in the codebase would make that more difficult.

Comment on lines 97 to 99
$this->assertStringNotContainsString( admin_url( 'term.php' ), $edit_link );

restore_error_handler();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In PHPUnit 6-9, tests stop as soon as the expected deprecation/exception is caught, so this code will never be executed, which also means that the error handler is never restored back (!!).

In other words, this test is buggy and may negatively influence other tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a good point, and I honestly had no idea about that. In such a situation, should a custom error handler be restored within tearDown()?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either that, or from within the custom error handler itself. For WP that logic will be sorted out when the test suite will be made compatible with PHPUnit 10 though, so is not something for this PR.

tests/phpunit/tests/admin/wpTermsListTable.php Outdated Show resolved Hide resolved
/**
* @covers WP_Terms_List_Table::handle_row_actions()
*/
public function test_handle_row_actions() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a must, but a nice to have/best practice recommendations:

  1. Split this test in two, one to test with $author_id, another to test with $admin_id.
    I would suggest a data provider, but in this case that wouldn't be a good solution as the assertions are different for the two situations being tested, so in this case, splitting the test into two separate tests each testing one specific situation is the better solution.
  2. Add the $message parameter to each assertion.
    When there are multiple assertions in a test, it can sometimes be confusing to see which assertion failed. Using the $message parameter you can pass a "failure message" to each assertion to make it more clear cut to see in the command line output, what the expectation was which wasn't met.
    Ref: https://docs.phpunit.de/en/9.6/assertions.html#assertstringcontainsstring

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 2c11912

thelovekesh and others added 2 commits September 15, 2023 18:38
Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com>
Copy link
Member

@jrfnl jrfnl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making those updates @thelovekesh !

Aside from this earlier remark of mine, all looks good and my earlier remark is not a blocker, so I'm approving this patch.

Coding standards wise, I'd prefer to still keep the creation of the URL separate from the creation of the HTML as it makes the code more readable without the nested function calls.

@audrasjb
Copy link
Contributor

Committed in https://core.trac.wordpress.org/changeset/56631

@audrasjb audrasjb closed this Sep 20, 2023
@thelovekesh thelovekesh deleted the fix/edit-term-link-generation branch September 20, 2023 08:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants