Skip to content

Commit

Permalink
Merge branch 'main' into branch-pr
Browse files Browse the repository at this point in the history
Signed-off-by: Andy Fragen <[email protected]>
  • Loading branch information
afragen authored Jan 9, 2025
2 parents 8c6c2f7 + e91ebec commit ca27c22
Show file tree
Hide file tree
Showing 13 changed files with 1,046 additions and 3 deletions.
10 changes: 9 additions & 1 deletion .github/workflows/phpunit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,16 @@ jobs:
php-version: ${{ matrix.php-version }}
tools: phpunit-polyfills:1.1

- name: Install SVN
run: sudo apt install -y subversion

- name: Setup tests
run: bash bin/install-wp-tests.sh wordpress_tests root root 127.0.0.1 latest true

- name: Prime the WordPress install for tests
id: prime-tests
run: XDEBUG_MODE=off phpunit${{ matrix.multisite && ' -c tests/phpunit/multisite.xml' || '' }} --filter gha_install_wp > /dev/null 2>&1

- name: Run tests
run: XDEBUG_MODE=off phpunit${{ matrix.multisite && ' -c tests/phpunit/multisite.xml' || '' }}
if: steps.prime-tests.outcome == 'success'
run: XDEBUG_MODE=off WP_TESTS_SKIP_INSTALL=1 phpunit${{ matrix.multisite && ' -c tests/phpunit/multisite.xml' || '' }}
2 changes: 2 additions & 0 deletions includes/class-admin-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,8 @@ public function register_settings() {
/**
* The Fields API which any CMS should have in its core but something we dont, hence this ugly hack.
*
* @codeCoverageIgnore Test with E2E tests instead.
*
* @param array $args The Field Parameters.
*
* @return void Echos the Field HTML.
Expand Down
2 changes: 1 addition & 1 deletion includes/class-debug.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ private static function verify_filesystem( $wp_filesystem ) {
/**
* Log error in file write fails only if debug is set to true. This is a valid use case.
*/
error_log( 'AspireUpdate - Could not open or write to the file system. Check file system permissions to debug log directory.' );
error_log( 'AspireUpdate - Could not open or write to the file system. Check file system permissions to debug log directory.' ); // @codeCoverageIgnore
// phpcs:enable
}
return false;
Expand Down
18 changes: 17 additions & 1 deletion phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,25 @@

<!-- Exclude test classes from naming conventions. -->
<rule ref="WordPress.Files.FileName.InvalidClassFileName">
<exclude-pattern>/tests/phpunit/tests/*</exclude-pattern>
<exclude-pattern>/tests/phpunit/*</exclude-pattern>
</rule>
<rule ref="WordPress.Files.FileName.NotHyphenatedLowercase">
<exclude-pattern>/tests/phpunit/*</exclude-pattern>
</rule>

<!-- Exclude test files from overriding globals sniff. -->
<rule ref="WordPress.WP.GlobalVariablesOverride.Prohibited">
<exclude-pattern>/tests/phpunit/tests/*</exclude-pattern>
</rule>

<!-- Exclude test files from some filesystem sniffs. -->
<rule ref="WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents">
<exclude-pattern>/tests/phpunit/*</exclude-pattern>
</rule>
<rule ref="WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents">
<exclude-pattern>/tests/phpunit/*</exclude-pattern>
</rule>
<rule ref="WordPress.WP.AlternativeFunctions.unlink_unlink">
<exclude-pattern>/tests/phpunit/*</exclude-pattern>
</rule>
</ruleset>
4 changes: 4 additions & 0 deletions tests/phpunit/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,9 @@ function _manually_load_plugin() {
// Start up the WP testing environment.
require "{$_tests_dir}/includes/bootstrap.php";

// Load unit test mocks and fakes.
require __DIR__ . '/includes/class-ap-fake-filesystem.php';

// Load unit test abstract classes.
require __DIR__ . '/includes/AdminSettings_UnitTestCase.php';
require __DIR__ . '/includes/Debug_UnitTestCase.php';
116 changes: 116 additions & 0 deletions tests/phpunit/includes/Debug_UnitTestCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php
/**
* Abstract base test class for \AspireUpdate\Debug.
*
* All \AspireUpdate\Debug unit tests should inherit from this class.
*/
abstract class Debug_UnitTestCase extends WP_UnitTestCase {
/**
* The path to the log file.
*
* @var string
*/
protected static $log_file;

/**
* Previously created filesystems.
*
* @var array
*/
protected static $filesystems = [];

/**
* The original value of $wp_filesystem before any tests run.
*
* @var WP_Filesystem_Base|null|false False if not already set.
*/
protected static $default_filesystem;

/**
* Gets the log file's path, and deletes if it exists before any tests run.
* Backs up the default filesystem.
*
* @return void
*/
public static function set_up_before_class() {
parent::set_up_before_class();

$get_file_path = new ReflectionMethod(
'AspireUpdate\Debug',
'get_file_path'
);

$get_file_path->setAccessible( true );
self::$log_file = $get_file_path->invoke( null );
$get_file_path->setAccessible( false );

if ( file_exists( self::$log_file ) ) {
unlink( self::$log_file );
}

if ( isset( $GLOBALS['wp_filesystem'] ) ) {
self::$default_filesystem = $GLOBALS['wp_filesystem'];
} else {
self::$default_filesystem = false;
}
}

/**
* Filters the filesystem method before each test runs.
*
* Filters are removed in the tear_down() parent method.
*
* @return void
*/
public function set_up() {
parent::set_up();

add_filter(
'filesystem_method',
static function () {
return 'direct';
}
);
}

/**
* Delete the log file and restores the filesystem after each test runs.
*
* @return void
*/
public function tear_down() {
if ( file_exists( self::$log_file ) ) {
unlink( self::$log_file );
}

if ( false === self::$default_filesystem ) {
unset( $GLOBALS['wp_filesystem'] );
} else {
$GLOBALS['wp_filesystem'] = self::$default_filesystem;
}

parent::tear_down();
}

/**
* Creates a fake filesystem.
*
* @param bool|null $exists Whether paths should exist.
* Default null uses default implemenation.
* @param bool|null $is_readable Whether paths should be readable.
* Default null uses default implemenation.
* @param bool|null $is_writable Whether paths should be writable.
* Default null uses default implemenation.
*/
public function get_fake_filesystem( $exists = null, $is_readable = null, $is_writable = null ) {
$hash = ( null === $exists ? '-1' : (int) $exists ) . ',' .
( null === $is_readable ? '-1' : (int) $is_readable ) . ',' .
( null === $is_writable ? '-1' : (int) $is_writable );

if ( ! isset( self::$filesystems[ $hash ] ) ) {
self::$filesystems[ $hash ] = new AP_FakeFilesystem( $exists, $is_readable, $is_writable );
}

return self::$filesystems[ $hash ];
}
}
82 changes: 82 additions & 0 deletions tests/phpunit/includes/class-ap-fake-filesystem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';

class AP_FakeFilesystem extends WP_Filesystem_Direct {
/**
* Whether paths should exist.
*
* @var bool|null
*/
private $exists;

/**
* Whether paths should be readable.
*
* @var bool|null
*/
private $is_readable;

/**
* Whether paths should be writable.
*
* @var bool|null
*/
private $is_writable;

/**
* Contructor.
*
* @param bool|null $exists Whether paths should exist.
* Default null to use parent implementation.
* @param bool|null $is_readable Whether paths should be readable.
* Default null to use parent implementation.
* @param bool|null $is_writable Whether paths should be writable.
* Default null to use parent implementation.
*/
public function __construct( $exists = null, $is_readable = null, $is_writable = null ) {
$this->exists = $exists;
$this->is_readable = $is_readable;
$this->is_writable = $is_writable;
}

/**
* Checks whether a path exists.
*
* @param string $path The path to check.
* @return bool Whether the path exists.
*/
public function exists( $path ) {
if ( null === $this->exists ) {
return parent::exists( $path );
}
return $this->exists;
}

/**
* Checks whether a path is readable.
*
* @param string $path The path to check.
* @return bool Whether the path is readable.
*/
public function is_readable( $path ) {
if ( null === $this->is_readable ) {
return parent::is_readable( $path );
}
return $this->is_readable;
}

/**
* Checks whether a path is writable.
*
* @param string $path The path to check.
* @return bool Whether the path is writable.
*/
public function is_writable( $path ) {
if ( null === $this->is_writable ) {
return parent::is_writable( $path );
}
return $this->is_writable;
}
}
106 changes: 106 additions & 0 deletions tests/phpunit/tests/Debug/Debug_ClearTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php
/**
* Class Debug_ClearTest
*
* @package AspireUpdate
*/

/**
* Tests for Debug::clear()
*
* @covers \AspireUpdate\Debug::clear
*/
class Debug_ClearTest extends Debug_UnitTestCase {
/**
* Test that a WP_Error object is returned when the filesystem isn't available.
*
* @covers \AspireUpdate\Debug::init_filesystem
* @covers \AspireUpdate\Debug::verify_filesystem
*/
public function test_should_return_wp_error_when_filesystem_is_not_available() {
add_filter( 'filesystem_method', '__return_false' );

$this->assertWPError(
AspireUpdate\Debug::clear(),
'A WP_Error object was not returned.'
);

$this->assertFileDoesNotExist(
self::$log_file,
'The log file was created.'
);
}

/**
* Test that a WP_Error object is returned when the log file doesn't exist.
*
* @covers \AspireUpdate\Debug::init_filesystem
* @covers \AspireUpdate\Debug::verify_filesystem
* @covers \AspireUpdate\Debug::get_file_path
*/
public function test_should_return_wp_error_when_log_file_does_not_exist() {
$this->assertWPError(
AspireUpdate\Debug::clear(),
'A WP_Error object was not returned.'
);

$this->assertFileDoesNotExist(
self::$log_file,
'The log file was created.'
);
}

/**
* Test that a WP_Error object is returned when the log file isn't writable.
*
* @covers \AspireUpdate\Debug::init_filesystem
* @covers \AspireUpdate\Debug::verify_filesystem
* @covers \AspireUpdate\Debug::get_file_path
*/
public function test_should_return_wp_error_when_log_file_is_not_writable() {
global $wp_filesystem;

// Backup and replace the filesystem object.
$wp_filesystem = $this->get_fake_filesystem( true, true, false );

$actual = AspireUpdate\Debug::clear();

$this->assertWPError(
$actual,
'A WP_Error was not returned.'
);

$this->assertFileDoesNotExist(
self::$log_file,
'The log file was created.'
);
}

/**
* Test that the log file is cleared.
*/
public function test_should_clear_log_file() {
file_put_contents(
self::$log_file,
"First line\r\nSecond line\r\nThird line"
);

$this->assertFileExists(
self::$log_file,
'The log file was not created before testing.'
);

AspireUpdate\Debug::clear();

$this->assertFileExists(
self::$log_file,
'The log file was deleted.'
);

$this->assertSame(
'',
file_get_contents( self::$log_file ),
'The log file was not cleared.'
);
}
}
Loading

0 comments on commit ca27c22

Please sign in to comment.