diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index 081e4b7..66ac36d 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -61,9 +61,25 @@
- /tests/phpunit/tests/*
+ /tests/phpunit/*
+ /tests/phpunit/*
+
+
+
+
/tests/phpunit/tests/*
+
+
+
+ /tests/phpunit/*
+
+
+ /tests/phpunit/*
+
+
+ /tests/phpunit/*
+
diff --git a/tests/phpunit/bootstrap.php b/tests/phpunit/bootstrap.php
index 3899953..186c80a 100644
--- a/tests/phpunit/bootstrap.php
+++ b/tests/phpunit/bootstrap.php
@@ -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';
diff --git a/tests/phpunit/includes/Debug_UnitTestCase.php b/tests/phpunit/includes/Debug_UnitTestCase.php
new file mode 100644
index 0000000..0058fd0
--- /dev/null
+++ b/tests/phpunit/includes/Debug_UnitTestCase.php
@@ -0,0 +1,116 @@
+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 ];
+ }
+}
diff --git a/tests/phpunit/includes/class-ap-fake-filesystem.php b/tests/phpunit/includes/class-ap-fake-filesystem.php
new file mode 100644
index 0000000..d2de759
--- /dev/null
+++ b/tests/phpunit/includes/class-ap-fake-filesystem.php
@@ -0,0 +1,82 @@
+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;
+ }
+}