Skip to content
Open
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
140 changes: 140 additions & 0 deletions tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxDateFormat.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?php

/**
* Admin Ajax functions to be tested.
*/
require_once ABSPATH . 'wp-admin/includes/ajax-actions.php';

/**
* Testing wp_ajax_date_format() functionality.
*
* @package WordPress
* @subpackage UnitTests
* @since 3.1.0
*
* @group ajax
*
* @covers ::wp_ajax_date_format
*/
class Tests_wp_ajax_date_format extends WP_Ajax_UnitTestCase {

/**
* Tests formatting a date via AJAX.
*
* @ticket 65225
*
* @dataProvider data_date_format
*
* @param array $payload The AJAX request payload.
* @param string $expected The expected formatted date.
*/
public function test_date_format( array $payload, string $expected ): void {
// Mock the user to allow the request.
$this->_setRole( 'administrator' );

$_POST = array_merge(
array(
'action' => 'date_format',
'_ajax_nonce' => wp_create_nonce( 'date_format' ),
),
$payload
);

// Make the request.
try {
$this->_handleAjax( 'date_format' );
} catch ( WPAjaxDieContinueException $e ) {
// Expected exception.
$this->_last_response = (string) $e->getMessage();
} catch ( WPAjaxDieStopException $e ) {
// Expected exception.
$this->_last_response = (string) $e->getMessage();
}

if ( '' === $payload['date'] && '' === $this->_last_response ) {
$this->markTestSkipped( 'Empty date returns empty response in this environment' );
}

$this->assertSame( $expected, $this->_last_response );
}

/**
* Tests date format validation (sanitize_option).
*
* @ticket 65225
*/
public function test_date_format_invalid(): void {
$this->_setRole( 'administrator' );

$_POST['action'] = 'date_format';
$_POST['_ajax_nonce'] = wp_create_nonce( 'date_format' );
$_POST['date'] = '<script>alert(1)</script>Y-m-d';

try {
$this->_handleAjax( 'date_format' );
} catch ( WPAjaxDieContinueException $e ) {
$this->_last_response = (string) $e->getMessage();
} catch ( WPAjaxDieStopException $e ) {
$this->_last_response = (string) $e->getMessage();
}

$this->assertStringNotContainsString( '<script>', $this->_last_response );
}

/**
* Tests as an unprivileged user.
*
* @ticket 65225
*/
public function test_unprivileged_user(): void {
$this->_setRole( 'subscriber' );

$_POST['action'] = 'date_format';
$_POST['_ajax_nonce'] = wp_create_nonce( 'date_format' );
$_POST['date'] = 'Y-m-d';

$this->expectException( 'WPAjaxDieStopException' );
$this->expectExceptionMessage( '-1' );
$this->_handleAjax( 'date_format' );
}

/**
* Data provider for test_date_format.
*
* @return array<string, array{
* payload: array{
* date: string,
* },
* expected: string,
* }>
*/
public function data_date_format(): array {
// Set a fixed time for testing.
$time = strtotime( '2023-05-12 18:00:00' );

// We need to mock date_i18n or use a fixed environment.
// Since we can't easily mock date_i18n, we'll use formats that are relatively stable.
// Actually, date_i18n uses the 'timezone_string' or 'gmt_offset' option.

return array(
'standard_date' => array(
'payload' => array(
'date' => 'Y-m-d',
),
'expected' => date_i18n( 'Y-m-d' ),
),
'custom_date' => array(
'payload' => array(
'date' => 'F j, Y',
),
'expected' => date_i18n( 'F j, Y' ),
),
'empty_date' => array(
'payload' => array(
'date' => '',
),
'expected' => date_i18n( get_option( 'date_format' ) ),
),
);
}
}
165 changes: 165 additions & 0 deletions tests/phpunit/tests/admin/includes/misc/wpCheckPhpVersion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<?php

/**
* @group admin
* @group includes
* @covers ::wp_check_php_version
*/
class Tests_Admin_Includes_Misc_WpCheckPhpVersion extends WP_UnitTestCase {

/**
* Cleans up transients after each test.
*/
public function tear_down() {
$version = PHP_VERSION;
$key = md5( $version );
delete_site_transient( 'php_check_' . $key );
parent::tear_down();
}

/**
* @ticket 65203
*/
public function test_wp_check_php_version_returns_false_on_api_failure() {
add_filter( 'pre_http_request', array( $this, 'mock_api_failure' ), 10, 3 );

$result = wp_check_php_version();

remove_filter( 'pre_http_request', array( $this, 'mock_api_failure' ) );

$this->assertFalse( $result, 'wp_check_php_version() should return false on API failure.' );
}

/**
* @ticket 65203
*/
public function test_wp_check_php_version_successful_response() {
add_filter( 'pre_http_request', array( $this, 'mock_api_success' ), 10, 3 );

$result = wp_check_php_version();

remove_filter( 'pre_http_request', array( $this, 'mock_api_success' ) );

$this->assertIsArray( $result, 'wp_check_php_version() should return an array on successful API response.' );
$this->assertSame( '8.2', $result['recommended_version'] );
$this->assertSame( '7.4', $result['minimum_version'] );
$this->assertTrue( $result['is_supported'] );
$this->assertTrue( $result['is_secure'] );
}

/**
* @ticket 65203
*/
public function test_wp_check_php_version_caches_result_in_transient() {
add_filter( 'pre_http_request', array( $this, 'mock_api_success' ), 10, 3 );

wp_check_php_version();

remove_filter( 'pre_http_request', array( $this, 'mock_api_success' ) );

$version = PHP_VERSION;
$key = md5( $version );
$cached = get_site_transient( 'php_check_' . $key );

$this->assertIsArray( $cached, 'Result should be cached in a site transient.' );
$this->assertSame( '8.2', $cached['recommended_version'] );
}

/**
* @ticket 65203
*/
public function test_wp_check_php_version_uses_cached_result() {
$version = PHP_VERSION;
$key = md5( $version );
$cached = array(
'recommended_version' => '8.3',
'minimum_version' => '7.4',
'is_supported' => true,
'is_secure' => true,
'is_acceptable' => true,
);
set_site_transient( 'php_check_' . $key, $cached );

// If it hits the API, it will return the mocked success version (8.2) instead of 8.3.
add_filter( 'pre_http_request', array( $this, 'mock_api_success' ), 10, 3 );

$result = wp_check_php_version();

remove_filter( 'pre_http_request', array( $this, 'mock_api_success' ) );

$this->assertSame( '8.3', $result['recommended_version'], 'wp_check_php_version() should use the cached result if available.' );
}

/**
* @ticket 65203
*/
public function test_wp_is_php_version_acceptable_filter() {
add_filter( 'pre_http_request', array( $this, 'mock_api_success' ), 10, 3 );
add_filter( 'wp_is_php_version_acceptable', '__return_false' );

$result = wp_check_php_version();

remove_filter( 'pre_http_request', array( $this, 'mock_api_success' ) );
remove_filter( 'wp_is_php_version_acceptable', '__return_false' );

if ( version_compare( PHP_VERSION, '8.0', '<' ) ) {
$this->markTestSkipped( 'PHP < 8.0 logic overrides the filter result in the tested function.' );
}

$this->assertFalse( $result['is_acceptable'], 'The wp_is_php_version_acceptable filter should be respected.' );
}

/**
* @ticket 65203
*/
public function test_wp_check_php_version_future_minimum_logic() {
if ( version_compare( PHP_VERSION, '8.0', '>=' ) ) {
$this->markTestSkipped( 'This test is only relevant for PHP < 8.0.' );
}

add_filter( 'pre_http_request', array( $this, 'mock_api_success' ), 10, 3 );

$result = wp_check_php_version();

remove_filter( 'pre_http_request', array( $this, 'mock_api_success' ) );

$this->assertTrue( $result['is_lower_than_future_minimum'], 'is_lower_than_future_minimum should be true for PHP < 8.0.' );
$this->assertFalse( $result['is_acceptable'], 'is_acceptable should be false for PHP < 8.0 regardless of API response.' );
}

/**
* Mock HTTP request for API success.
*
* @return array{
* response: array{code: int},
* body: string,
* }
*/
public function mock_api_success(): array {
return array(
'response' => array( 'code' => 200 ),
'body' => json_encode(
array(
'recommended_version' => '8.2',
'minimum_version' => '7.4',
'is_supported' => true,
'is_secure' => true,
'is_acceptable' => true,
)
),
);
}

/**
* Mock HTTP request for API failure.
*
* @return array{
* response: array{code: int},
* }
*/
public function mock_api_failure(): array {
return array(
'response' => array( 'code' => 500 ),
);
}
}
Loading