diff --git a/config/schema/flysystem.schema.yml b/config/schema/flysystem.schema.yml
new file mode 100644
index 0000000000000000000000000000000000000000..52c28407b827a0710a4523ac9d5748fd984d2271
--- /dev/null
+++ b/config/schema/flysystem.schema.yml
@@ -0,0 +1,32 @@
+flysystem.flysystem_adapter_config.*:
+  type: config_entity
+  label: flysystem_adapter_config
+  mapping:
+    id:
+      type: string
+      label: ID
+    label:
+      type: label
+      label: Label
+    uuid:
+      type: string
+    description:
+      type: string
+      label: 'Description'
+    status:
+      type: boolean
+      label: 'Status'
+    sub_adapter:
+      type: string
+      label: 'Adapter Plugin ID'
+    sub_adapter_config:
+      type: plugin.plugin_configuration.flysystem_adapter_config.[%parent.backend]
+    langcode:
+      type: string
+      label: 'Language code'
+    dependencies:
+      type: config_dependencies
+      label: 'Dependencies'
+
+plugin.plugin_configuration.flysystem_adapter_config.*:
+  type: mapping
diff --git a/flysystem.info.yml b/flysystem.info.yml
index 7696651a77efe5d26fde6cdd2f593a73e353a053..5db4e1f56c05ac342794d7b704b141f8c9bf794c 100644
--- a/flysystem.info.yml
+++ b/flysystem.info.yml
@@ -1,5 +1,5 @@
 name: Flysystem
+type: module
 description: 'Provides access to various filesystem backends using Flysystem.'
 package: Flysystem
-type: module
-core_version_requirement: ^9.5 || ^10.0
+core_version_requirement: ^10.3
diff --git a/flysystem.links.action.yml b/flysystem.links.action.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0b396c0c6761ab2fbf0caf68c9f3a2f42546dd0e
--- /dev/null
+++ b/flysystem.links.action.yml
@@ -0,0 +1,5 @@
+entity.flysystem_adapter_config.add_form:
+  route_name: 'entity.flysystem_adapter_config.add_form'
+  title: 'Configure a Flysystem Adapter'
+  appears_on:
+    - entity.flysystem_adapter_config.collection
diff --git a/flysystem.links.menu.yml b/flysystem.links.menu.yml
index 38140dbe3231fffe94104800a79ba2debce2baf6..8491e60a1d4525055a8604c7cf6698f321733299 100644
--- a/flysystem.links.menu.yml
+++ b/flysystem.links.menu.yml
@@ -1,5 +1,5 @@
-flysystem.config:
-  title: 'Flysystem'
-  description: 'Configure settings related to Flysystem.'
-  parent: system.file_system_settings
-  route_name: flysystem.config
+entity.flysystem_adapter_config.overview:
+  title: Configured Flysystem Adapters
+  parent: system.admin_config_media
+  description: 'List of configured Flysystem Adapters.'
+  route_name: entity.flysystem_adapter_config.collection
diff --git a/flysystem.permissions.yml b/flysystem.permissions.yml
index fd3ff5a48f18b96f09271dce27678bf290146c1a..a734df252009d97820c128c9817507ff134b3cc3 100644
--- a/flysystem.permissions.yml
+++ b/flysystem.permissions.yml
@@ -1,4 +1,4 @@
-administer flysystem:
-  title: 'Administer Flysystem'
-  description: 'Sync Flysystem filesystems.'
-  restrict access: 'TRUE'
+administer flysystem_adapter_config:
+  title: 'Manage configuration of Flysystem Adapters'
+  descriiption:  'Manage configuration of League/Flysystem Filesystem Adapters'
+  restricted: TRUE
\ No newline at end of file
diff --git a/flysystem.routing.yml b/flysystem.routing.yml
index 0eb3d82306f4d9ea5b751c9dd5bb3801e41bde94..0bb0d4350045855099b7c47215cfe5f889859cfc 100644
--- a/flysystem.routing.yml
+++ b/flysystem.routing.yml
@@ -1,35 +1,31 @@
-flysystem.files:
-  path: '/_flysystem/{scheme}'
+entity.flysystem_adapter_config.collection:
+  path: '/admin/config/media/flysystem-adapter-config'
   defaults:
-    _controller: 'Drupal\system\FileDownloadController::download'
-    _disable_route_normalizer: 'TRUE'
+    _entity_list: 'flysystem_adapter_config'
+    _title: 'Configured Flysystem Adapters'
   requirements:
-    # Permissions are handled through Drupal file create / update permissions
-    _access: 'TRUE'
-    scheme: '^[a-zA-Z0-9+.-]+$'
-  options:
-    _maintenance_access: 'TRUE'
+    _permission: 'administer flysystem_adapter_config'
 
-flysystem.serve:
-  path: '/_flysystem/{scheme}/{filepath}'
+entity.flysystem_adapter_config.add_form:
+  path: '/admin/config/media/flysystem_adapter_config/add'
   defaults:
-    _controller: 'Drupal\system\FileDownloadController::download'
-    _disable_route_normalizer: 'TRUE'
+    _entity_form: 'flysystem_adapter_config.add'
+    _title: 'Configure a Flysystem Adapter'
   requirements:
-  # Permissions are handled through Drupal access content permissions
-    _access: 'TRUE'
-    scheme: '^[a-zA-Z0-9+.-]+$'
-    filepath: .+
-  options:
-    _maintenance_access: 'TRUE'
+    _permission: 'administer flysystem_adapter_config'
 
-flysystem.config:
-  path: '/admin/config/media/file-system/flysystem'
+entity.flysystem_adapter_config.edit_form:
+  path: '/admin/config/media/flysystem-adapter-config/{flysystem_adapter_config}'
   defaults:
-    _form: 'Drupal\flysystem\Form\ConfigForm'
-    _title: Flysystem
+    _entity_form: 'flysystem_adapter_config.edit'
+    _title: 'Modify configuration for a Flysystem Adapter'
   requirements:
-    _permission: 'administer flysystem'
+    _permission: 'administer flysystem_adapter_config'
 
-route_callbacks:
-  - 'Drupal\flysystem\Routing\FlysystemRoutes::routes'
+entity.flysystem_adapter_config.delete_form:
+  path: '/admin/config/media/flysystem-adapter-config/{flysystem_adapter_config}/delete'
+  defaults:
+    _entity_form: 'flysystem_adapter_config.delete'
+    _title: 'Delete a configured Flysystem Adapter'
+  requirements:
+    _permission: 'administer flysystem_adapter_config'
diff --git a/flysystem.services.yml b/flysystem.services.yml
index b86019827f00c089ccc2dedb58c5276441caee18..8cb0bc5c75685499320dd8cbe4d897eb92a46595 100644
--- a/flysystem.services.yml
+++ b/flysystem.services.yml
@@ -6,6 +6,7 @@ services:
     decorates: file_system
     decoration_priority: 5
     arguments: ['@flysystem.filesystem.inner', '@stream_wrapper_manager', '@settings']
+
   cache.flysystem:
     class: Drupal\Core\Cache\CacheBackendInterface
     tags:
@@ -17,17 +18,6 @@ services:
     parent: logger.channel_base
     arguments: ['flysystem']
 
-  # @todo Remove plugin manager, implement Adapters instead.
-  # Should there be an adapter, or adapter manager service?
-  #plugin.manager.flysystem:
-  #  class: Drupal\flysystem\Plugin\FlysystemPluginManager
-  #  arguments: ['@container.namespaces', '@cache.discovery', '@module_handler']
-
-  # @todo Rename to a Stream wrapper instead of a factory
-  #flysystem_factory:
-  #  class: Drupal\flysystem\FlysystemStreamWrapperManager
-  #  arguments: ['@plugin.manager.flysystem', '@stream_wrapper_manager', '@cache.flysystem', '@event_dispatcher', '@settings']
-
   path_processor.flysystem:
     class: Drupal\flysystem\PathProcessor\FlysystemPathProcessor
     tags:
@@ -39,6 +29,6 @@ services:
     tags:
       - { name: event_subscriber }
 
-  flysystem.asset.css.dumper:
-    class: Drupal\flysystem\Asset\AssetDumper
-    arguments: ['@file_system', '@config.factory']
+  plugin.manager.flysystem_adapter:
+    class: Drupal\flysystem\FlysystemAdapterPluginManager
+    parent: default_plugin_manager
\ No newline at end of file
diff --git a/modules/config/schema/flysystem_local.adapter.schema.yml b/modules/config/schema/flysystem_local.adapter.schema.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6d9aeccc4602b5e9136646c6d74500953c297f65
--- /dev/null
+++ b/modules/config/schema/flysystem_local.adapter.schema.yml
@@ -0,0 +1,31 @@
+plugin.plugin_configuration.flysystem_adapter_config.flysystem_local:
+  type: mapping
+  label: 'Flysystem Local Filesystem settings'
+  mapping:
+    schema:
+      type: 'string'
+      label: 'File management schema'
+    root_directory:
+      type: 'string'
+      label: 'File Storage directory, relative to Drupal root'
+    permissions:
+      file:
+        public:
+          type: integer
+          label: 'Public file permissions'
+        private:
+          type: integer
+          label: 'Private file permissions'
+      dir:
+        public:
+          type: integer
+          label: 'Public directory permissions'
+        private:
+          type: integer
+          label: 'Private directory permissions'
+    write_flags:
+      type: integer
+      label: 'Write flags'
+    link_handling:
+      type: integer
+      label: 'Links handling (disallow or skip)'
diff --git a/modules/flysystem_local/flysystem_local.info.yml b/modules/flysystem_local/flysystem_local.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..11e0c753b7f5cc373388acba74fb4e1f0260ef75
--- /dev/null
+++ b/modules/flysystem_local/flysystem_local.info.yml
@@ -0,0 +1,5 @@
+name: 'Flysystem Local Filesytem Adapter'
+type: module
+description: 'Flysystem Local Filesystem Adapter.'
+package: 'Flysystem'
+core_version_requirement: ^10
diff --git a/modules/flysystem_local/src/Plugin/FlysystemAdapter/LocalAdapter.php b/modules/flysystem_local/src/Plugin/FlysystemAdapter/LocalAdapter.php
new file mode 100644
index 0000000000000000000000000000000000000000..7c37904d1fcd3591bcf7eda29aa234eae49dcec9
--- /dev/null
+++ b/modules/flysystem_local/src/Plugin/FlysystemAdapter/LocalAdapter.php
@@ -0,0 +1,129 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\flysystem_local\Plugin\FlysystemAdapter;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\flysystem\FlysystemSubAdapterInterface;
+use Drupal\flysystem\Plugin\FlysystemAdapterPluginBase;
+use League\Flysystem\Local\LocalFilesystemAdapter;
+
+/**
+ * Plugin implementation of the flysystem_adapter.
+ *
+ * @FlysystemAdapter(
+ *   id = "local_adapter",
+ *   label = @Translation("Local Adapter"),
+ *   description = @Translation("Flysystem Local Adapter.")
+ * )
+ */
+final class LocalAdapter extends FlysystemAdapterPluginBase implements FlysystemSubAdapterInterface {
+
+  /**
+   * The flysystem_subadapter ID.
+   */
+  protected string $id;
+
+  /**
+   * The flysystem_subadapter label.
+   */
+  protected string $label;
+
+  /**
+   * The flysystem_subadapter description.
+   */
+  protected string $description;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    return !empty($this->description) ? $this->description : '';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildSubConfigurationForm(array $form, FormStateInterface $form_state, $flysystem_adapter_config) {
+    $form['schema'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Schema'),
+      '#maxlength' => 255,
+      '#description' => $this->t('The schema used to identify files managed by this adapter.'),
+      // @todo determine how to retrieve saved values once form is saved.
+      '#default_value' => $flysystem_adapter_config->getSubAdapterConfigItem('schema'),
+      '#required' => TRUE,
+    ];
+    $form['root_directory'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('File Storage Location'),
+      '#maxlength' => 255,
+      '#description' => $this->t('File Storage directory, relative to Drupal root.'),
+      // @todo determine how to retrieve saved values once form is saved.
+      '#default_value' => $flysystem_adapter_config->getSubAdapterConfigItem('root_directory'),
+      '#required' => TRUE,
+    ];
+    $form['permissions']['file']['public'] = [
+      '#type' => 'number',
+      '#title' => $this->t('Public file permissions'),
+      '#description' => $this->t('Default permissions for public files.'),
+      // @todo determine how to retrieve saved values once form is saved.
+      '#default_value' => $flysystem_adapter_config->getSubAdapterConfigItem(['permissions', 'file', 'public']) ?? '0755',
+    ];
+    $form['permissions']['file']['private'] = [
+      '#type' => 'number',
+      '#title' => $this->t('Private file permissions'),
+      '#description' => $this->t('Default permissions for private files.'),
+      // @todo determine how to retrieve saved values once form is saved.
+      '#default_value' => $flysystem_adapter_config->getSubAdapterConfigItem(['permissions', 'file', 'private']) ?? '0755',
+    ];
+    $form['permissions']['dir']['public'] = [
+      '#type' => 'number',
+      '#title' => $this->t('Public directory permissions'),
+      '#description' => $this->t('Default permissions for public directories.'),
+      // @todo determine how to retrieve saved values once form is saved.
+      '#default_value' => $flysystem_adapter_config->getSubAdapterConfigItem(['permissions', 'dir', 'public']) ?? '0755',
+    ];
+    $form['permissions']['dir']['private'] = [
+      '#type' => 'number',
+      '#title' => $this->t('Private directory permissions'),
+      '#description' => $this->t('Default permissions for private directories.'),
+      // @todo determine how to retrieve saved values once form is saved.
+      '#default_value' => $flysystem_adapter_config->getSubAdapterConfigItem(['permissions', 'dir', 'private']) ?? '0755',
+    ];
+    $form['write_flags'] = [
+      '#type' => 'hidden',
+      '#title' => $this->t('Write flags'),
+      // @todo convert to proper translated entity.
+      '#description' => $this->t('Lock types for file resources, reference <a href="https://www.php.net/manual/en/function.flock.php#:~:text=operation-,operation,-is%20one%20of">PHP file locking operations</a> for more information.'),
+      // @todo determine how to retrieve saved values once form is saved.
+      '#default_value' => (strlen($flysystem_adapter_config->getSubAdapterConfigItem('write_flag')) == 0) ? LOCK_EX : NULL,
+    ];
+    $form['link_handling'] = [
+      '#type' => 'hidden',
+      '#title' => $this->t('Link handler flags'),
+      // @todo convert to proper translated entity.
+      '#description' => $this->t('How to handle links, reference <a href="https://flysystem.thephpleague.com/docs/adapter/local/">Local File Adatper, advanced usage</a> for more information.'),
+      // @todo determine how to retrieve saved values once form is saved.
+      '#default_value' => (strlen($flysystem_adapter_config->getSubAdapterConfigItem('link_handling')) == 0) ? LocalFilesystemAdapter::DISALLOW_LINKS : NULL,
+    ];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
+
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
+
+  }
+
+}
diff --git a/src/Adapter/CacheItem.php b/src/Adapter/CacheItem.php
deleted file mode 100644
index 8c1e22e4907913964513ea8ddb7e078799f348e6..0000000000000000000000000000000000000000
--- a/src/Adapter/CacheItem.php
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-
-namespace Drupal\flysystem\Adapter;
-
-/**
- * A filesystem item stored in the Drupal cache.
- */
-class CacheItem {
-
-  /**
-   * The array of metadata for the item.
-   *
-   * @var array
-   */
-  protected $metadata = [];
-
-  /**
-   * Returns the metadata for the item.
-   *
-   * @return array
-   *   The array of metadata for the item.
-   */
-  public function getMetadata() {
-    return $this->metadata;
-  }
-
-  /**
-   * Updates the metadata for the item.
-   *
-   * @param array $metadata
-   *   The array of metadata for the item.
-   */
-  public function updateMetadata(array $metadata) {
-    static $keys = [
-      'fileSize' => TRUE,
-      'mimeType' => TRUE,
-      'visibility' => TRUE,
-      'lastModified' => TRUE,
-      'type' => TRUE,
-    ];
-
-    $this->metadata = array_intersect_key($metadata, $keys) + $this->metadata;
-  }
-
-}
diff --git a/src/Adapter/CacheItemBackend.php b/src/Adapter/CacheItemBackend.php
deleted file mode 100644
index 265bed7da22f97cd6685f233e4037e46fc1b26ba..0000000000000000000000000000000000000000
--- a/src/Adapter/CacheItemBackend.php
+++ /dev/null
@@ -1,135 +0,0 @@
-<?php
-
-namespace Drupal\flysystem\Adapter;
-
-use Drupal\Component\Utility\Crypt;
-use Drupal\Core\Cache\CacheBackendInterface;
-
-/**
- * Storage backend for cache items.
- *
- * This class is separated out from CacheItems so we can easily test loading,
- * saving, and deleting separately from the logic to reach back to a child
- * Flysystem adapter.
- */
-class CacheItemBackend {
-
-  /**
-   * The Drupal cache backend to store data in.
-   *
-   * @var \Drupal\Core\Cache\CacheBackendInterface
-   */
-  protected $cacheBackend;
-
-  /**
-   * The scheme this cache is managing.
-   *
-   * @var string
-   */
-  protected $scheme;
-
-  /**
-   * Constructs a new CacheItemBackend.
-   *
-   * @param string $scheme
-   *   The scheme being managed by the cache.
-   * @param \Drupal\Core\Cache\CacheBackendInterface $cacheBackend
-   *   The Drupal cache backend to store items in.
-   */
-  public function __construct($scheme, CacheBackendInterface $cacheBackend) {
-    $this->scheme = $scheme;
-    $this->cacheBackend = $cacheBackend;
-  }
-
-  /**
-   * Returns whether the cache item exists.
-   *
-   * @param string $path
-   *   The path of the cache item.
-   *
-   * @return bool
-   *   True if the item exists, false if not.
-   */
-  public function has($path) {
-    $cacheKey = $this->getCacheKey($path);
-
-    if (isset($this->cacheItems[$cacheKey])) {
-      return TRUE;
-    }
-
-    return (bool) $this->cacheBackend->get($cacheKey);
-  }
-
-  /**
-   * Loads a cache item for a given path.
-   *
-   * @param string $path
-   *   The path of the item to load.
-   *
-   * @return \Drupal\flysystem\Adapter\CacheItem
-   *   The cache item, or a new cache item if one isn't in the cache.
-   */
-  public function load($path) {
-    $key = $this->getCacheKey($path);
-
-    if ($cached = $this->cacheBackend->get($key)) {
-      /** @var \Drupal\flysystem\Adapter\CacheItem $item */
-      $item = $cached->data;
-    }
-    else {
-      $item = new CacheItem();
-    }
-
-    return $item;
-  }
-
-  /**
-   * Sets a cache item in the backend.
-   *
-   * @param string $path
-   *   The file path.
-   * @param \Drupal\flysystem\Adapter\CacheItem $item
-   *   The item to set.
-   */
-  public function set($path, CacheItem $item) {
-    $this->cacheBackend->set($this->getCacheKey($path), $item);
-  }
-
-  /**
-   * Deletes an item by the path.
-   *
-   * @param string $path
-   *   The path of the item to delete.
-   */
-  public function delete($path) {
-    $this->deleteMultiple([$path]);
-  }
-
-  /**
-   * Deletes multiple paths.
-   *
-   * @param array $paths
-   *   The array of paths to delete.
-   */
-  public function deleteMultiple(array $paths) {
-    $keys = [];
-    foreach ($paths as $path) {
-      $keys[] = $this->getCacheKey($path);
-    }
-    $this->cacheBackend->deleteMultiple($keys);
-  }
-
-  /**
-   * Gets the cache key for a cache item.
-   *
-   * @param string $path
-   *   The path of the cache item.
-   *
-   * @return string
-   *   A hashed key suitable for use in a cache.
-   */
-  protected function getCacheKey($path) {
-    return Crypt::hashBase64($this->scheme . '://' . $path);
-  }
-
-}
diff --git a/src/Adapter/DrupalCacheAdapter.php b/src/Adapter/DrupalCacheAdapter.php
deleted file mode 100644
index c42803078fba852d71a905989ea8ce2c567870fb..0000000000000000000000000000000000000000
--- a/src/Adapter/DrupalCacheAdapter.php
+++ /dev/null
@@ -1,288 +0,0 @@
-<?php
-
-namespace Drupal\flysystem\Adapter;
-
-use League\Flysystem\Config;
-use League\Flysystem\FileAttributes;
-use League\Flysystem\FilesystemAdapter;
-
-/**
- * A Flysystem adapter implementing caching with Drupal's Cache API.
- */
-class DrupalCacheAdapter implements FilesystemAdapter {
-
-  /**
-   * The Flysystem adapter to cache data for.
-   *
-   * @var \League\Flysystem\FilesystemAdapter
-   */
-  protected FilesystemAdapter $adapter;
-
-  /**
-   * The cache backend to store data in.
-   *
-   * @var \Drupal\flysystem\Adapter\CacheItemBackend
-   */
-  protected CacheItemBackend $cacheItemBackend;
-
-  /**
-   * The scheme of the stream wrapper used for this adapter.
-   *
-   * @var string
-   */
-  protected string $scheme;
-
-  /**
-   * Constructs a new caching Flysystem adapter.
-   *
-   * @param string $scheme
-   *   The scheme of the stream wrapper used for this adapter.
-   * @param \League\Flysystem\FilesystemAdapter $adapter
-   *   The flysystem adapter to cache data for.
-   * @param \Drupal\flysystem\Adapter\CacheItemBackend $cacheItemBackend
-   *   The cache backend to store data in.
-   */
-  public function __construct(string $scheme, FilesystemAdapter $adapter, CacheItemBackend $cacheItemBackend) {
-    $this->scheme = $scheme;
-    $this->adapter = $adapter;
-    $this->cacheItemBackend = $cacheItemBackend;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function write($path, $contents, Config $config): void {
-    $this->adapter->write($path, $contents, $config);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function writeStream($path, $contents, Config $config): void {
-    $this->adapter->writeStream($path, $contents, $config);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function copy($source, $destination, $config): void {
-    $this->adapter->copy($source, $destination, $config);
-
-    $item = $this->cacheItemBackend->load($source);
-    $newitem = clone $item;
-    $this->cacheItemBackend->set($destination, $newitem);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function delete($path): void {
-    $this->adapter->delete($path);
-
-    $this->cacheItemBackend->delete($path);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setVisibility($path, $visibility): void {
-    $this->adapter->setVisibility($path, $visibility);
-
-    $this->updateMetadata($path, ['visibility' => $visibility]);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function read($path): string {
-    return $this->adapter->read($path);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function readStream($path) {
-    return $this->adapter->readStream($path);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function listContents($path = '', $deep = FALSE): iterable {
-    // Don't cache directory listings to avoid having to keep track of
-    // incomplete cache entries.
-    // @todo This could be a good place for a microcache?
-    return $this->adapter->listContents($path, $deep);
-  }
-
-  /**
-   * Something something.
-   *
-   * @param string $path
-   *   The file path.
-   *
-   * @return array
-   *   The metadata.
-   */
-  public function getMetadata(string $path): array {
-    $item = $this->cacheItemBackend->load($path);
-
-    if ($metadata = $item->getMetadata()) {
-      return $metadata;
-    }
-
-    $filesize = $this->adapter->fileSize($path);
-    $lastmodified = $this->adapter->lastModified($path);
-    $mimetype = $this->adapter->mimeType($path);
-    $visibility = $this->adapter->visibility($path);
-
-    // $metadata = $this->adapter->getMetadata($path);
-    $item->updateMetadata([
-      'fileSize' => $filesize,
-      'lastModified' => $lastmodified,
-      'mimeType' => $mimetype,
-      'visibility' => $visibility,
-    ]);
-    $this->cacheItemBackend->set($path, $item);
-
-    return $metadata;
-  }
-
-  /**
-   * Fetches a specific key from metadata.
-   *
-   * @param string $path
-   *   The path to load metadata for.
-   * @param string $key
-   *   The key in metadata, such as 'mimetype', to load metadata for.
-   *
-   * @return string|bool
-   *   The array of metadata.
-   */
-  protected function fetchMetadataKey(string $path, string $key): string|bool {
-    $item = $this->cacheItemBackend->load($path);
-
-    if (($metadata = $item->getMetadata()) && isset($metadata[$key])) {
-      return $metadata[$key];
-    }
-
-    $metadata = $this->adapter->$key($path);
-    $updatedMetadata = $this->updateMetadata($path, [$key => $metadata->$key()]);
-    return $updatedMetadata[$key] ?? FALSE;
-  }
-
-  /**
-   * Updates the metadata for a given path.
-   *
-   * @param string $path
-   *   The path of file file or directory.
-   * @param array|false $metadata
-   *   The metadata to update.
-   *
-   * @return array|false
-   *   Returns the value passed in as metadata.
-   */
-  protected function updateMetadata(string $path, array|false $metadata): array|false {
-    if (!empty($metadata)) {
-      $item = $this->cacheItemBackend->load($path);
-      $item->updateMetadata($metadata);
-      $this->cacheItemBackend->set($path, $item);
-    }
-
-    return $metadata;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function fileExists(string $path): bool {
-    if ($this->cacheItemBackend->has($path)) {
-      return TRUE;
-    }
-
-    // Always check the upstream adapter for new files.
-    // @todo This could be a good place for a microcache?
-    return $this->adapter->fileExists($path);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function directoryExists(string $path): bool {
-    if ($this->cacheItemBackend->has($path)) {
-      return TRUE;
-    }
-
-    // Always check the upstream adapter for new directoies.
-    // @todo This could be a good place for a microcache?
-    return $this->adapter->directoryExists($path);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function deleteDirectory(string $path): void {
-    // Before the delete we need to know what files are in the directory.
-    $contents = $this->adapter->listContents($path, TRUE);
-
-    $this->adapter->deleteDirectory($path);
-
-    $paths = array_column($contents, 'path');
-    $this->cacheItemBackend->deleteMultiple($paths);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function createDirectory(string $path, Config $config): void {
-    $this->adapter->createDirectory($path, $config);
-
-    // Warm the metadata cache.
-    $item = new CacheItem();
-    $this->cacheItemBackend->set($path, $item);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function visibility(string $path): FileAttributes {
-    $visibility = $this->fetchMetadataKey($path, 'visibility');
-    return new FileAttributes($path, NULL, $visibility);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function mimeType(string $path): FileAttributes {
-    $mimeType = $this->fetchMetadataKey($path, 'mimeType');
-    return new FileAttributes($path, NULL, NULL, NULL, $mimeType);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function lastModified(string $path): FileAttributes {
-    return $this->adapter->lastModified($path);
-    // Return new FileAttributes($path, NULL, NULL, $lastModified);.
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function fileSize(string $path): FileAttributes {
-    return $this->adapter->fileSize($path);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function move(string $source, string $destination, Config $config): void {
-    $this->adapter->move($source, $destination, $config);
-
-    $item = $this->cacheItemBackend->load($source);
-    $newitem = clone $item;
-    $this->cacheItemBackend->set($destination, $newitem);
-    $this->cacheItemBackend->delete($source);
-  }
-
-}
diff --git a/src/Adapter/FlysystemAdapterInterface.php b/src/Adapter/FlysystemAdapterInterface.php
deleted file mode 100644
index 16d19e9dca492fec4d05cb2b44326dead7fa0e60..0000000000000000000000000000000000000000
--- a/src/Adapter/FlysystemAdapterInterface.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-
-namespace Drupal\flysystem\Adapter;
-
-/**
- * Interface definition for Flysystem adapters.
- */
-interface FlysystemAdapterInterface {
-
-  /**
-   * Returns the Flysystem adapter.
-   *
-   * Plugins should not keep references to the adapter. If a plugin needs to
-   * perform filesystem operations, it should either use a scheme:// or have the
-   * \Drupal\flysystem\FlysystemStreamWrapperManager injected.
-   *
-   * @return \League\Flysystem\FilesystemAdapter
-   *   The Flysytem adapter.
-   */
-  public function getAdapter();
-
-  /**
-   * Returns a web accessible URL for the resource.
-   *
-   * This function should return a URL that can be embedded in a web page
-   * and accessed from a browser. For example, the external URL of
-   * "youtube://xIpLd0WQKCY" might be
-   * "http://www.youtube.com/watch?v=xIpLd0WQKCY".
-   *
-   * @param string $uri
-   *   The URI to provide a URL for.
-   *
-   * @return string
-   *   Returns a string containing a web accessible URL for the resource.
-   */
-  public function getExternalUrl($uri);
-
-  /**
-   * Checks the sanity of the filesystem.
-   *
-   * If this is a local filesystem, .htaccess file should be in place.
-   *
-   * @return array
-   *   A list of error messages.
-   */
-  public function ensure($force = FALSE);
-
-}
diff --git a/src/Adapter/FlysystemAdapterManager.php b/src/Adapter/FlysystemAdapterManager.php
deleted file mode 100644
index 184e7eb7d71553a459f74c416c1d391339ba9f9e..0000000000000000000000000000000000000000
--- a/src/Adapter/FlysystemAdapterManager.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-
-namespace Drupal\flysystem\Adapter;
-
-use Drupal\Component\Plugin\FallbackPluginManagerInterface;
-use Drupal\Core\Cache\CacheBackendInterface;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\Plugin\DefaultPluginManager;
-
-/**
- * Manages Flysystem plugins.
- */
-class FlysystemAdapterManager extends DefaultPluginManager implements FallbackPluginManagerInterface {
-
-  /**
-   * Constructs a Flysystem object.
-   *
-   * @param \Traversable $namespaces
-   *   An object that implements \Traversable which contains the root paths
-   *   keyed by the corresponding namespace to look for plugin implementations.
-   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
-   *   Cache backend instance to use.
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler to invoke the alter hook with.
-   *
-   * @todo Determine if a derivative of this is needed, if not remove.
-   */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Flysystem', $namespaces, $module_handler, 'Drupal\flysystem\Plugin\FlysystemPluginInterface', 'Drupal\flysystem\Annotation\Adapter');
-    $this->setCacheBackend($cache_backend, 'flysystem_plugins');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFallbackPluginId($plugin_id, array $configuration = []) {
-    return 'missing';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function alterDefinitions(&$definitions) {
-    // Remove definitions that are missing necessary extensions.
-    foreach ($definitions as $id => $definition) {
-      foreach ($definition['extensions'] as $extension) {
-        if (extension_loaded($extension)) {
-          continue;
-        }
-
-        unset($definitions[$id]);
-        break;
-      }
-    }
-
-    parent::alterDefinitions($definitions);
-  }
-
-}
diff --git a/src/Adapter/FlysystemUrlTrait.php b/src/Adapter/FlysystemUrlTrait.php
deleted file mode 100644
index a164251d4167f8bbd0ef6d9b2579fceceb8ef396..0000000000000000000000000000000000000000
--- a/src/Adapter/FlysystemUrlTrait.php
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-
-namespace Drupal\flysystem\Adapter;
-
-use Drupal\Core\Url;
-use League\Flysystem\WhitespacePathNormalizer;
-
-/**
- * Helper trait for generating URLs from adapter plugins.
- *
- * @todo Review and determine if needed, if not remove.
- * @see flysystem.serve route.
- */
-trait FlysystemUrlTrait {
-
-  /**
-   * @var \League\Flysystem\WhitespacePathNormalizer
-   */
-  protected WhitespacePathNormalizer $pathNormalizer;
-
-  /**
-   *
-   */
-  protected function getPathNormalizer() {
-    if (!isset($this->pathNormalizer)) {
-      $this->pathNormalizer = new WhitespacePathNormalizer();
-    }
-    return $this->pathNormalizer;
-  }
-
-  /**
-   * Returns a web accessible URL for the resource.
-   *
-   * This function should return a URL that can be embedded in a web page
-   * and accessed from a browser. For example, the external URL of
-   * "youtube://xIpLd0WQKCY" might be
-   * "http://www.youtube.com/watch?v=xIpLd0WQKCY".
-   *
-   * @param string $uri
-   *   The URI to provide a URL for.
-   *
-   * @return string
-   *   Returns a string containing a web accessible URL for the resource.
-   */
-  public function getExternalUrl($uri) {
-    $path = str_replace('\\', '/', $this->getTarget($uri));
-
-    $arguments = [
-      'scheme' => $this->getScheme($uri),
-      'filepath' => $path,
-    ];
-    // @todo Review, see flysystem.routing.yml, route flysystem.serve
-    return Url::fromRoute('flysystem.serve', $arguments, ['absolute' => TRUE])->toString();
-  }
-
-  /**
-   * Returns the target file path of a URI.
-   *
-   * @param string $uri
-   *   The URI.
-   *
-   * @return string
-   *   The file path of the URI.
-   */
-  protected function getTarget($uri) {
-    return $this->getPathNormalizer()->normalizePath(substr($uri, strpos($uri, '://') + 3));
-  }
-
-  /**
-   * Returns the scheme from the internal URI.
-   *
-   * @param string $uri
-   *   The URI.
-   *
-   * @return string
-   *   The scheme.
-   */
-  protected function getScheme($uri) {
-    return substr($uri, 0, strpos($uri, '://'));
-  }
-
-}
diff --git a/src/Adapter/ImageStyleGenerationTrait.php b/src/Adapter/ImageStyleGenerationTrait.php
deleted file mode 100644
index 5d6eb429bb5a615ad7b360e61f35f9af851c8df0..0000000000000000000000000000000000000000
--- a/src/Adapter/ImageStyleGenerationTrait.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-
-namespace Drupal\flysystem\Adapter;
-
-use Drupal\Component\Utility\Crypt;
-use Drupal\image\Entity\ImageStyle;
-
-/**
- * Helper trait for generating URLs from adapter plugins.
- *
- * @todo Review and determine if this is needed, if not delete.
- */
-trait ImageStyleGenerationTrait {
-
-  /**
-   * Generates an image style for a file target.
-   *
-   * @param string $target
-   *   The file target.
-   *
-   * @return bool
-   *   True on success, false on failure.
-   */
-  protected function generateImageStyle($target) {
-    if (strpos($target, 'styles/') !== 0 || substr_count($target, '/') < 3) {
-      return FALSE;
-    }
-
-    [, $style, $scheme, $file] = explode('/', $target, 4);
-
-    if (!$image_style = ImageStyle::load($style)) {
-      return FALSE;
-    }
-
-    $image_uri = $scheme . '://' . $file;
-
-    $derivative_uri = $image_style->buildUri($image_uri);
-
-    if (!file_exists($image_uri)) {
-      $path_info = pathinfo($image_uri);
-      $converted_image_uri = $path_info['dirname'] . '/' . $path_info['filename'];
-
-      if (!file_exists($converted_image_uri)) {
-        return FALSE;
-      }
-      else {
-        // The converted file does exist, use it as the source.
-        $image_uri = $converted_image_uri;
-      }
-    }
-
-    $lock_name = 'image_style_deliver:' . $image_style->id() . ':' . Crypt::hashBase64($image_uri);
-
-    if (!file_exists($derivative_uri)) {
-      $lock_acquired = \Drupal::lock()->acquire($lock_name);
-      if (!$lock_acquired) {
-        return FALSE;
-      }
-    }
-
-    $success = file_exists($derivative_uri) || $image_style->createDerivative($image_uri, $derivative_uri);
-
-    if (!empty($lock_acquired)) {
-      \Drupal::lock()->release($lock_name);
-    }
-
-    return $success;
-  }
-
-}
diff --git a/src/Adapter/Local.php b/src/Adapter/Local.php
deleted file mode 100644
index d8ec959b0ace7d219569137d9e45444e613bf95d..0000000000000000000000000000000000000000
--- a/src/Adapter/Local.php
+++ /dev/null
@@ -1,189 +0,0 @@
-<?php
-
-namespace Drupal\flysystem\Adapter;
-
-use Drupal\Component\FileSecurity\FileSecurity;
-use Drupal\Component\Utility\UrlHelper;
-use Drupal\Core\File\FileSystem;
-use Drupal\Core\Logger\RfcLogLevel;
-use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
-use League\Flysystem\Local\LocalFilesystemAdapter;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Adapter for the "Local" Flysystem adapter.
- *
- * @Adapter(id = "local")
- */
-class Local implements FlysystemAdapterInterface, ContainerFactoryPluginInterface {
-
-  use FlysystemUrlTrait {
-    getExternalUrl as getDownloadlUrl;
-  }
-
-  /**
-   * The permissions to create directories with.
-   *
-   * @var int
-   */
-  protected $directoryPerm;
-
-  /**
-   * Whether the root is in the public path.
-   *
-   * @var bool
-   */
-  protected $isPublic;
-
-  /**
-   * The root of the local adapter.
-   *
-   * @var string
-   */
-  protected $root;
-
-  /**
-   * Whether the root exists and is readable.
-   *
-   * @var bool
-   */
-  protected $rootExists;
-
-  /**
-   * Constructs a Local object.
-   *
-   * @param string $root
-   *   The root of the adapter's filesystem.
-   * @param bool $is_public
-   *   (optional) Whether this is a public file system. Defaults to false.
-   * @param int $directory_permission
-   *   (optional) The permissions to create directories with.
-   */
-  public function __construct($root, $is_public = FALSE, $directory_permission = FileSystem::CHMOD_DIRECTORY) {
-    $this->isPublic = $is_public;
-    $this->root = $root;
-    $this->directoryPerm = $directory_permission;
-    $this->rootExists = $this->ensureDirectory();
-  }
-
-  /**
-   * {@inheritdoc}
-   *
-   * @todo Remove if it is decided that we're not using ContainerFactoryPluginInterface;
-   */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
-    return new static(
-      $configuration['root'],
-      !empty($configuration['public']),
-      $container->get('settings')->get('file_chmod_directory', FileSystem::CHMOD_DIRECTORY)
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getAdapter() {
-    return $this->rootExists ? new LocalFilesystemAdapter($this->root) : new MissingAdapter();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getExternalUrl($uri) {
-    if ($this->isPublic === FALSE) {
-      return $this->getDownloadlUrl($uri);
-    }
-
-    $path = str_replace('\\', '/', $this->root . '/' . $this->getTarget($uri));
-
-    return $GLOBALS['base_url'] . '/' . UrlHelper::encodePath($path);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function ensure($force = FALSE) {
-    if (!$this->rootExists) {
-      return [
-        [
-          'severity' => RfcLogLevel::ERROR,
-          'message' => 'The %root directory either does not exist or is not readable and attempts to create it have failed.',
-          'context' => ['%root' => $this->root],
-        ],
-      ];
-    }
-
-    if (!$this->writeHtaccess($force)) {
-      return [
-        [
-          'severity' => RfcLogLevel::ERROR,
-          'message' => 'See <a href="@url">@url</a> for information about the recommended .htaccess file which should be added to the %directory directory to help protect against arbitrary code execution.',
-          'context' => [
-            '%directory' => $this->root,
-            '@url' => 'https://www.drupal.org/SA-CORE-2013-003',
-          ],
-        ],
-      ];
-    }
-
-    return [
-      [
-        'severity' => RfcLogLevel::INFO,
-        'message' => 'The directory %root exists and is readable.',
-        'context' => ['%root' => $this->root],
-      ],
-    ];
-  }
-
-  /**
-   * Checks that the directory exists and is readable.
-   *
-   * This will attempt to create the directory if it doesn't exist.
-   *
-   * @return bool
-   *   True on success, false on failure.
-   */
-  protected function ensureDirectory() {
-    // Go for the success case first.
-    if (is_dir($this->root) && is_readable($this->root)) {
-      return TRUE;
-    }
-
-    if (!file_exists($this->root)) {
-      mkdir($this->root, $this->directoryPerm, TRUE);
-    }
-
-    if (is_dir($this->root) && chmod($this->root, $this->directoryPerm)) {
-      clearstatcache(TRUE, $this->root);
-      $this->writeHtaccess(TRUE);
-      return TRUE;
-    }
-
-    return FALSE;
-  }
-
-  /**
-   * Writes an .htaccess file.
-   *
-   * @param bool $force
-   *   Whether to overwrite an existing file.
-   *
-   * @return bool
-   *   True on success, false on failure.
-   */
-  protected function writeHtaccess($force) {
-    $htaccess_path = $this->root . '/.htaccess';
-
-    if (file_exists($htaccess_path) && !$force) {
-      // Short circuit if the .htaccess file already exists.
-      return TRUE;
-    }
-
-    // Make file writable so that we can overwrite it.
-    if (file_exists($htaccess_path)) {
-      chmod($htaccess_path, 0666);
-    }
-    return @file_put_contents($htaccess_path, FileSecurity::htaccessLines(!$this->isPublic)) && chmod($htaccess_path, 0444);
-  }
-
-}
diff --git a/src/Adapter/Missing.php b/src/Adapter/Missing.php
deleted file mode 100644
index bb07cb3706a7e7087e65c7cf643e63482eabc536..0000000000000000000000000000000000000000
--- a/src/Adapter/Missing.php
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-
-namespace Drupal\flysystem\Flysystem\Adapter;
-
-use Drupal\Core\Logger\RfcLogLevel;
-use Drupal\flysystem\Adapter\FlysystemAdapterInterface;
-use Drupal\flysystem\Adapter\MissingAdapter;
-
-/**
- * Drupal plugin for the "NullAdapter" Flysystem adapter.
- *
- * @Adapter(id = "missing")
- */
-class Missing implements FlysystemAdapterInterface {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getAdapter() {
-    return new MissingAdapter();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getExternalUrl($uri) {
-    return '';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function ensure($force = FALSE) {
-    return [
-      [
-        'severity' => RfcLogLevel::ERROR,
-        'message' => 'The Flysystem driver is missing.',
-        'context' => [],
-      ],
-    ];
-  }
-
-}
diff --git a/src/Adapter/MissingAdapter.php b/src/Adapter/MissingAdapter.php
deleted file mode 100644
index 0e06a1e11ca491dd2da6d861ce196157dda51f2d..0000000000000000000000000000000000000000
--- a/src/Adapter/MissingAdapter.php
+++ /dev/null
@@ -1,141 +0,0 @@
-<?php
-
-namespace Drupal\flysystem\Adapter;
-
-use League\Flysystem\Config;
-use League\Flysystem\FileAttributes;
-use League\Flysystem\FilesystemAdapter;
-use League\Flysystem\InvalidVisibilityProvided;
-use League\Flysystem\UnableToCopyFile;
-use League\Flysystem\UnableToCreateDirectory;
-use League\Flysystem\UnableToDeleteDirectory;
-use League\Flysystem\UnableToDeleteFile;
-use League\Flysystem\UnableToMoveFile;
-use League\Flysystem\UnableToReadFile;
-use League\Flysystem\UnableToWriteFile;
-
-/**
- * The Flysystem MissingAdapter definition for integration with Drupal.
- */
-class MissingAdapter implements FilesystemAdapter {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function fileExists(string $path): bool {
-    return FALSE;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function directoryExists(string $path): bool {
-    return FALSE;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function write(string $path, string $contents, Config $config): void {
-    throw new UnableToWriteFile();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function writeStream(string $path, $contents, Config $config): void {
-    throw new UnableToWriteFile();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function read(string $path): string {
-    return '';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function readStream(string $path) {
-    throw new UnableToReadFile();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function delete(string $path): void {
-    throw new UnableToDeleteFile();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function deleteDirectory(string $dirname): void {
-    throw new UnableToDeleteDirectory();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function createDirectory(string $dirname, Config $config): void {
-    throw new UnableToCreateDirectory();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setVisibility(string $path, string $visibility): void {
-    throw new InvalidVisibilityProvided();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function visibility(string $path): FileAttributes {
-    return new FileAttributes('');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function mimeType(string $path): FileAttributes {
-    return new FileAttributes('');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function lastModified(string $path): FileAttributes {
-    return new FileAttributes('');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function fileSize(string $path): FileAttributes {
-    return new FileAttributes('');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function listContents(string $directory = '', $deep = FALSE): iterable {
-    return [];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function move(string $source, string $destination, Config $config): void {
-    throw new UnableToMoveFile();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function copy(string $source, string $destination, Config $config): void {
-    throw new UnableToCopyFile();
-  }
-
-}
diff --git a/src/Annotation/Adapter.php b/src/Annotation/Adapter.php
new file mode 100644
index 0000000000000000000000000000000000000000..15f609df2b9ddca57ffd64d38b0852ce281f46a4
--- /dev/null
+++ b/src/Annotation/Adapter.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Drupal\flysystem\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines a Flysystem adapter plguin.
+ *
+ * Plugin Namespace: Flysystem.
+ *
+ * For a working example, see \Drupal\flysystem\Flysystem\Local.
+ *
+ * @see plugin_api
+ *
+ * @Annotation
+ */
+class Adapter extends Plugin {
+
+  /**
+   * The plugin ID.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * A list of extension dependencies.
+   *
+   * @var string[]
+   */
+  public $extensions = [];
+
+}
diff --git a/src/Annotation/FlysystemAdapter.php b/src/Annotation/FlysystemAdapter.php
new file mode 100644
index 0000000000000000000000000000000000000000..dce4d7aaa0ca600e7112170658256ac0edabdc2b
--- /dev/null
+++ b/src/Annotation/FlysystemAdapter.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\flysystem\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines flysystem_adapter annotation object.
+ *
+ * @Annotation
+ */
+final class FlysystemAdapter extends Plugin {
+
+  /**
+   * The plugin ID.
+   */
+  public string $id;
+
+  /**
+   * The human-readable name of the plugin.
+   *
+   * @ingroup plugin_translatable
+   */
+  public string $title;
+
+  /**
+   * The description of the plugin.
+   *
+   * @ingroup plugin_translatable
+   */
+  public string $description;
+
+}
diff --git a/src/Entity/FlysystemAdapterConfig.php b/src/Entity/FlysystemAdapterConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..0e6c111c7f6363ac34011c215716146f54c14ff0
--- /dev/null
+++ b/src/Entity/FlysystemAdapterConfig.php
@@ -0,0 +1,278 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\flysystem\Entity;
+
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Config\Config;
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\flysystem\FlysystemAdapterConfigInterface;
+use Drupal\flysystem\FlysystemException;
+
+/**
+ * Defines the flysystem_adapter_config entity type.
+ *
+ * @ConfigEntityType(
+ *   id = "flysystem_adapter_config",
+ *   label = @Translation("Configured Flysystem Adapter"),
+ *   label_collection = @Translation("Configured Flysystem Adapters"),
+ *   label_singular = @Translation("configured Flysystem Adapter"),
+ *   label_plural = @Translation("configured Flysystem Adapters"),
+ *   label_count = @PluralTranslation(
+ *     singular = "@count configured Flysystem Adapter",
+ *     plural = "@count configured Flysystem Adapters",
+ *   ),
+ *   handlers = {
+ *     "list_builder" = "Drupal\flysystem\FlysystemAdapterConfigListBuilder",
+ *     "form" = {
+ *       "add" = "Drupal\flysystem\Form\FlysystemAdapterConfigForm",
+ *       "edit" = "Drupal\flysystem\Form\FlysystemAdapterConfigForm",
+ *       "delete" = "Drupal\Core\Entity\EntityDeleteForm",
+ *     },
+ *   },
+ *   config_prefix = "flysystem_adapter_config",
+ *   admin_permission = "administer flysystem_adapter_config",
+ *   links = {
+ *     "collection" = "/admin/config/media/flysystem-adapter-config",
+ *     "add-form" = "/admin/config/media/flysystem-adapter-config/add",
+ *     "edit-form" = "/admin/config/media/flysystem-adapter-config/{flysystem_adapter_config}",
+ *     "delete-form" = "/admin/config/media/flysystem-adapter-config/{flysystem_adapter_config}/delete",
+ *   },
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label",
+ *     "uuid" = "uuid",
+ *   },
+ *   config_export = {
+ *     "id",
+ *     "label",
+ *     "description",
+ *     "sub_adapter",
+ *     "sub_adapter_config",
+ *   },
+ * )
+ */
+final class FlysystemAdapterConfig extends ConfigEntityBase implements FlysystemAdapterConfigInterface {
+
+  /**
+   * The flysystem_adapter_config ID.
+   */
+  protected string $id;
+
+  /**
+   * The flysystem_adapter_config label.
+   */
+  protected string $label;
+
+  /**
+   * The flysystem_adapter_config description.
+   */
+  protected string $description;
+
+  /**
+   * The ID of the subAdapter plugin.
+   *
+   * @var string
+   */
+  protected $sub_adapter;
+
+  /**
+   * The adapter plugin configuration.
+   *
+   * @var array
+   */
+  protected $sub_adapter_config = [];
+
+  /**
+   * The adapter plugin instance.
+   *
+   * @var \Drupal\flysystem\FlysystemAdapterInterface|null
+   */
+  protected $subAdapterPlugin;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    return !empty($this->description) ? $this->description : '';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasValidSubAdapter() {
+    $subadapter_plugin_definition = \Drupal::service('plugin.manager.flysystem_adapter')->getDefinition($this->getSubAdapterId(), FALSE);
+    return !empty($subadapter_plugin_definition);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSubAdapterId() {
+    return $this->sub_adapter;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSubAdapterValue($key) {
+    if (is_array($key)) {
+      return NestedArray::getValue($key, $this->sub_adapter_config);
+    }
+    return $this->sub_adapter_config[$key] ?? '';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSubAdapter() {
+    if (!$this->subAdapterPlugin) {
+      $subadapter_plugin_manager = \Drupal::service('plugin.manager.flysystem_adapter');
+      $config = $this->sub_adapter_config;
+      $config['#flysystem_adapter_config'] = $this;
+      if (!($this->subAdapterPlugin = $subadapter_plugin_manager->createInstance($this->getSubAdapterId(), $config))) {
+        $sub_adapter_id = $this->getSubAdapterId();
+        throw new FlysystemException("The adapter with ID '$sub_adapter_id' could not be retrieved.");
+      }
+    }
+    return $this->subAdapterPlugin;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSubAdapterConfig() {
+    return $this->sub_adapter_config;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSubAdapterConfigItem($key) {
+    if (is_array($key)) {
+      return NestedArray::getValue($this->sub_adapter_config, $key);
+    }
+    // var_dump($key); die;
+    // var_dump($this->sub_adapter_config[$key]); die;
+    // var_dump($key); die;.
+    return $this->sub_adapter_config[$key] ?? '';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setSubAdapterConfig(array $sub_adapter_config) {
+    $this->sub_adapter_config = $sub_adapter_config;
+    // In case the subadapter plugin is already loaded, make sure the
+    // configuration stays in sync.
+    if ($this->subAdapterPlugin
+        && $this->getSubAdapter()->getConfiguration() !== $sub_adapter_config) {
+      $this->getSubAdapter()->setConfiguration($sub_adapter_config);
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preSave(EntityStorageInterface $storage) {
+    parent::preSave($storage);
+
+    // The rest of the code only applies to updates.
+    if (!isset($this->original)) {
+      return;
+    }
+    // Retrieve active config overrides for this adapter config entity.
+    $overrides = $this->getConfigOverrides($this);
+
+    // If there are overrides for the sub_adapter or its configuration, attempt
+    // to apply them for the preUpdate() call.
+    if (isset($overrides['sub_adapter']) || isset($overrides['sub_adapter_config'])) {
+      $sub_adapter_config = $this->getSubAdapterConfig();
+      if (isset($overrides['sub_adapter_config'])) {
+        $sub_adapter_config = $overrides['sub_adapter_config'];
+      }
+      $sub_adapter_id = $this->getSubAdapterId();
+      if (isset($overrides['sub_adapter'])) {
+        $sub_adapter_id = $overrides['sub_adapter'];
+      }
+      $subadapter_plugin_manager = \Drupal::service('plugin.manager.flysystem_adapter');
+      $sub_adapter_config['#flysystem_adapter_config'] = $this;
+      if (!($subadapter_plugin_manager->createInstance($sub_adapter_id, $sub_adapter_config))) {
+        throw new FlysystemException("The adapter with ID '$sub_adapter_id' could not be retrieved.");
+      }
+    }
+  }
+
+  /**
+   * Implements the magic __clone() method.
+   *
+   * Prevents the adapter plugin instance from being cloned.
+   */
+  public function __clone() {
+    $this->subAdapterPlugin = NULL;
+  }
+
+  /**
+   * Retrieves all overridden property values for the given config entity.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The config entity to check for overrides.
+   *
+   * @return array
+   *   An associative array mapping property names to their overridden values.
+   */
+  private function getConfigOverrides(EntityInterface $entity) {
+    $entity_type = $entity->getEntityType();
+    if (!($entity_type instanceof ConfigEntityTypeInterface)) {
+      return [];
+    }
+
+    $config_key = $entity_type->getConfigPrefix() . '.' . $entity->id();
+    $config = \Drupal::config($config_key);
+    if (!$config->hasOverrides()) {
+      return [];
+    }
+
+    return $this->collectOverrides($config, $config->get());
+  }
+
+  /**
+   * Collects overrides from a config object.
+   *
+   * @param \Drupal\Core\Config\Config $config
+   *   The config object.
+   * @param array $values
+   *   The array of values for the given $prefix.
+   * @param array $overrides
+   *   (optional) The overrides collected so far. Internal use only.
+   * @param string $prefix
+   *   (optional) The config key prefix for the current call level.  Internal
+   *   use only.
+   *
+   * @return array
+   *   An associative array mapping property names to their overridden values.
+   */
+  private function collectOverrides(Config $config, array $values, array $overrides = [], $prefix = '') {
+    foreach ($values as $key => $value) {
+      $key = "$prefix$key";
+      if (!$config->hasOverrides($key)) {
+        continue;
+      }
+      if (is_array($value)) {
+        NestedArray::setValue($overrides, explode('.', $key), []);
+        $overrides = $this->collectOverrides($config, $value, $overrides, "$key.");
+      }
+      else {
+        NestedArray::setValue($overrides, explode('.', $key), $value);
+      }
+    }
+
+    return $overrides;
+  }
+
+}
diff --git a/src/FlysystemAdapterConfigInterface.php b/src/FlysystemAdapterConfigInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..782d24f1967087691c369b9cb30e8dd57c0f9c42
--- /dev/null
+++ b/src/FlysystemAdapterConfigInterface.php
@@ -0,0 +1,68 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\flysystem;
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+
+/**
+ * Provides an interface defining a flysystem_adapter_config entity type.
+ */
+interface FlysystemAdapterConfigInterface extends ConfigEntityInterface {
+
+  /**
+   * Determines whether Flysystem adapter is valid.
+   *
+   * @return bool
+   *   TRUE if valid, FALSE otherwise.
+   */
+  public function hasValidSubAdapter();
+
+  /**
+   * Retrieves the Flysystem adapter.
+   *
+   * @return \Drupal\flysystem\FlysystemAdapterInterface
+   *   This adapter config entity's Flysystem adapter.
+   *
+   * @throws \Drupal\flysystem\FlysystemException
+   *   Thrown if the adapter plugin could not be retrieved.
+   */
+  public function getSubAdapter();
+
+  /**
+   * Retrieves plugin ID of the Flysystem (sub)adapter of this config entity.
+   *
+   * @return string
+   *   The plugin ID of the subadapter.
+   */
+  public function getSubAdapterId();
+
+  /**
+   * Return the configuration of this config entity's Flysystem (sub)adapter.
+   *
+   * @return array
+   *   An associative array with the subadapter configuration.
+   */
+  public function getSubAdapterConfig();
+
+  /**
+   * Get adapter config description.
+   *
+   * @return string
+   *   Adapter config description.
+   */
+  public function getDescription();
+
+  /**
+   * Returns value from subadapter config array.
+   *
+   * @param mixed $key
+   *   Array key or keys for which value is to be retrieved.
+   *
+   * @return mixed
+   *   Value to return from array key/keys.
+   */
+  public function getSubAdapterValue($key);
+
+}
diff --git a/src/FlysystemAdapterConfigListBuilder.php b/src/FlysystemAdapterConfigListBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..d5903c8035432c67ff99970ca4b2e9e06608a9c7
--- /dev/null
+++ b/src/FlysystemAdapterConfigListBuilder.php
@@ -0,0 +1,36 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\flysystem;
+
+use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Provides a listing of flysystem_adapter_configs.
+ */
+final class FlysystemAdapterConfigListBuilder extends ConfigEntityListBuilder {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildHeader(): array {
+    $header['label'] = $this->t('Label');
+    $header['id'] = $this->t('Machine name');
+    $header['status'] = $this->t('Status');
+    return $header + parent::buildHeader();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildRow(EntityInterface $entity): array {
+    /** @var \Drupal\flysystem\FlysystemAdapterConfigInterface $entity */
+    $row['label'] = $entity->label();
+    $row['id'] = $entity->id();
+    $row['status'] = $entity->status() ? $this->t('Enabled') : $this->t('Disabled');
+    return $row + parent::buildRow($entity);
+  }
+
+}
diff --git a/src/FlysystemAdapterInterface.php b/src/FlysystemAdapterInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..2e0a02a1016e47539a82504782342e3ce27a46ab
--- /dev/null
+++ b/src/FlysystemAdapterInterface.php
@@ -0,0 +1,55 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\flysystem;
+
+use Drupal\Component\Plugin\ConfigurableInterface;
+use Drupal\Component\Plugin\DependentPluginInterface;
+use Drupal\Component\Plugin\DerivativeInspectionInterface;
+use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+
+/**
+ * Interface for flysystem_adapter plugins.
+ */
+interface FlysystemAdapterInterface extends PluginInspectionInterface, DerivativeInspectionInterface, ConfigurableInterface, DependentPluginInterface, ContainerFactoryPluginInterface {
+
+  /**
+   * Returns the translated plugin label.
+   */
+  public function label(): string;
+
+  /**
+   * Retrieves plugin ID of the Flysystem (sub)adapter of this config entity.
+   *
+   * @return string
+   *   The plugin ID of the subadapter.
+   */
+  public function getSubAdapterId();
+
+  /**
+   * Return the configuration of this config entity's Flysystem (sub)adapter.
+   *
+   * @return array
+   *   An associative array with the subadapter configuration.
+   */
+  public function getSubAdapterConfig();
+
+  /**
+   * Builds the Sub Configuration Form components for Form array.
+   *
+   * @param array $form
+   *   Form array.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   Drupal Form State object.
+   * @param \Drupal\flysystem\FlysystemAdapterConfigInterface $flysystem_adapter_config
+   *   Flysystem Adapter Configuration entity.
+   *
+   * @return array
+   *   Form array with subform items added.
+   */
+  public function buildSubConfigurationForm(array $form, FormStateInterface $form_state, FlysystemAdapterConfigInterface $flysystem_adapter_config);
+
+}
diff --git a/src/FlysystemAdapterPluginManager.php b/src/FlysystemAdapterPluginManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..7b032a3ec18e49f3e69e24904b80dc3e1777c339
--- /dev/null
+++ b/src/FlysystemAdapterPluginManager.php
@@ -0,0 +1,26 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\flysystem;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\flysystem\Annotation\FlysystemAdapter;
+
+/**
+ * FlysystemAdapter plugin manager.
+ */
+final class FlysystemAdapterPluginManager extends DefaultPluginManager {
+
+  /**
+   * Constructs the object.
+   */
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Plugin/FlysystemAdapter', $namespaces, $module_handler, FlysystemSubAdapterInterface::class, FlysystemAdapter::class);
+    $this->alterInfo('flysystem_adapter_info');
+    $this->setCacheBackend($cache_backend, 'flysystem_adapter_plugins');
+  }
+
+}
diff --git a/src/FlysystemBridge.php b/src/FlysystemBridge.php
index a1d87d5819d3ff8e5bf123775f9937e6af5642b2..5c955003ec0855eb0c1e74a8490f5677ff001b2f 100644
--- a/src/FlysystemBridge.php
+++ b/src/FlysystemBridge.php
@@ -5,6 +5,7 @@ namespace Drupal\flysystem;
 use Drupal\Core\StreamWrapper\StreamWrapperInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use League\Flysystem\Filesystem;
+use League\Flysystem\FilesystemOperator;
 
 /**
  * FlysystemStreamWrapper implementation for Drupal compatibility.
@@ -133,7 +134,7 @@ class FlysystemBridge extends Filesystem {
    * @param string $scheme
    *   The scheme.
    *
-   * @return \Drupal\flysystem\Flysystem\Interface\FilesystemInterface
+   * @return \League\Flysystem\FilesystemOperator
    *   The filesystem for the scheme.
    */
   protected function getFilesystemForScheme($scheme) {
diff --git a/src/FlysystemDrupalFileSystem.php b/src/FlysystemDrupalFileSystem.php
index df1ded0b507286b80abc732c69bb17c8616100b0..1aaf6da550d76a1dc0bf194782982147883d7476 100644
--- a/src/FlysystemDrupalFileSystem.php
+++ b/src/FlysystemDrupalFileSystem.php
@@ -14,9 +14,11 @@ use Drupal\Core\StreamWrapper\StreamWrapperInterface;
 use Drupal\Core\StreamWrapper\StreamWrapperManager;
 use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
 use League\Flysystem\FilesystemAdapter;
+use League\Flysystem\InvalidInvisibilityProvided;
+use League\Flysystem\Config;
 
 /**
- *
+ * Decorator for Drupal]\Core\File\FileSystem.
  */
 class FlysystemDrupalFileSystem extends FileSystem {
 
@@ -94,8 +96,9 @@ class FlysystemDrupalFileSystem extends FileSystem {
           }
           elseif ($wrapper->fileExists($uri)) {
             $drupalMode = $this->settings->get('file_chmod_file', static::CHMOD_FILE);
+            $wrapper->setVisibility($uri, $drupalMode);
+            return TRUE;
           }
-          return $wrapper->setVisibility($uri, $drupalMode);
         }
         catch (\Exception $e) {
           // @todo write exception handler for possible exceptions thrown
@@ -119,7 +122,10 @@ class FlysystemDrupalFileSystem extends FileSystem {
         // @todo figure out how to utilize directory permissions, see notes on
         // Flysystem VisibilityConverter.
         // @see \League\Flysystem\Filesystem::createDirectory()
-        $wrapper->createDirectory($uri);
+        // @see \League\FlysystemConfig
+        $options[Config::OPTION_DIRECTORY_VISIBILITY] = $mode;
+        $config = new Config($options);
+        $wrapper->createDirectory($uri, $config);
         return TRUE;
       }
       catch (\Exception $e) {
@@ -167,7 +173,9 @@ class FlysystemDrupalFileSystem extends FileSystem {
         // @todo figure out how to utilize directory permissions, see notes on
         // Flysystem VisibilityConverter.
         // @see \League\Flysystem\Filesystem::copy().
-        $wrapper->copy($source, $destination);
+        $options[Config::OPTION_VISIBILITY] = NULL;
+        $config = new Config($options);        
+        $wrapper->copy($source, $destination, $config);
         return $destination;
       }
       catch (\Exception $e) {
@@ -184,7 +192,7 @@ class FlysystemDrupalFileSystem extends FileSystem {
    * @todo finish writing, see inline todo comments.
    */
   public function delete($path) {
-    /** @var \Drupal\Core\StreamWrapper\StreamWrapperManager $wrappe */
+    /** @var \Drupal\Core\StreamWrapper\StreamWrapperManager $wrapper */
     $wrapper = $this->streamWrapperManager->getViaUri($path);
     if ($wrapper instanceof FilesystemAdapter) {
       if ($wrapper->fileExists($path) || $wrapper->directoryExists($path)) {
@@ -223,9 +231,9 @@ class FlysystemDrupalFileSystem extends FileSystem {
       }
 
       if ($wrapper->directoryExists($path)) {
-        $dir = $wrapper->listContents($path);
+        $dir = $wrapper->listContents($path, TRUE);
         foreach ($dir as $entry) {
-          $entry_path = $path . '/' . $entry;
+          $entry_path = $path . '/' . $entry->path();
           $this->deleteRecursive($entry_path, $callback);
         }
         return $this->rmdir($path);
@@ -249,7 +257,9 @@ class FlysystemDrupalFileSystem extends FileSystem {
         // Flysystem VisibilityConverter.
         // @see \League\Flysystem\Filesystem::move().
         // What do we do with the $replace flag?
-        $wrapper->move($source, $destination);
+        $options[Config::OPTION_VISIBILITY] = NULL;
+        $config = new Config($options);        
+        $wrapper->move($source, $destination, $config);
         return $destination;
       }
       catch (\Exception $e) {
@@ -285,7 +295,9 @@ class FlysystemDrupalFileSystem extends FileSystem {
         // Flysystem VisibilityConverter.
         // @see \League\Flysystem\Filesystem::move().
         // Do we need to use the $replace flag here in the FlysystemAdapter?
-        $wrapper->move($temp_name, $destination);
+        $options[Config::OPTION_VISIBILITY] = NULL;
+        $config = new Config($options);        
+        $wrapper->move($temp_name, $destination, $config);
         return $destination;
       }
       catch (\Exception $e) {
@@ -349,7 +361,7 @@ class FlysystemDrupalFileSystem extends FileSystem {
     $wrapper = $this->streamWrapperManager->getViaScheme(StreamWrapperManager::getScheme($destination));
     if ($wrapper instanceof FilesystemAdapter) {
       try {
-        if ($wrapper->fileExist($destination)) {
+        if ($wrapper->fileExists($destination)) {
           switch ($replace) {
             case FileSystemInterface::EXISTS_REPLACE:
               // Do nothing here, we want to overwrite the existing file.
diff --git a/src/FlysystemException.php b/src/FlysystemException.php
new file mode 100644
index 0000000000000000000000000000000000000000..f9ad08f62bc2600b31cadde31c476e6d6e273cb9
--- /dev/null
+++ b/src/FlysystemException.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace Drupal\flysystem;
+
+/**
+ * Represents an exception that occurred in some part of Flysystem.
+ */
+class FlysystemException extends \Exception {}
diff --git a/src/FlysystemStreamWrapper.php b/src/FlysystemStreamWrapper.php
index 509971d021970990d8ae58b5bec731533ff88507..8aae7edd3e9713f9a6dac967fd21e75b2599e833 100644
--- a/src/FlysystemStreamWrapper.php
+++ b/src/FlysystemStreamWrapper.php
@@ -6,15 +6,15 @@ use Drupal\Core\Site\Settings;
 use Drupal\Core\StreamWrapper\LocalStream;
 use Drupal\flysystem\Adapter\FlysystemUrlTrait;
 use League\Flysystem\FilesystemAdapter;
+use League\Flysystem\UnableToCheckExistence;
+use League\Flysystem\InvalidInvisibilityProvided;
 
 /**
  * FlysystemStreamWrapper implementation for Drupal compatibility.
  */
-abstract class FlysystemStreamWrapper extends LocalStream {
+abstract class FlysystemStreamWrapper extends LocalStream implements FilesystemAdapter {
 
-  use FlysystemUrlTrait {
-    getExternalUrl as getDownloadlUrl;
-  }
+  use FlysystemUrlTrait;
 
   /**
    * The site settings.
@@ -43,4 +43,26 @@ abstract class FlysystemStreamWrapper extends LocalStream {
     $this->adapter = $adapter;
   }
 
+  /**
+   * Determine if file exists.
+   * 
+   * @param string $path
+   *   Path to file.
+   *
+   * @return bool
+   *   TRUE if file exists, FALSE if not.
+   * 
+   * @throws UnableToCheckExistence
+   */
+  public function fileExists(string $path): bool {
+    
+    try {
+      return $this->adapter->fileExists($path);
+    }
+    catch (\Exception $e) {
+      // @todo Write exception handler.
+      throw new UnableToCheckExistence();
+    }
+    
+  }
 }
diff --git a/src/FlysystemStreamWrapperManager.php b/src/FlysystemStreamWrapperManager.php
index 2a5001d1cd53147bca6151648a51373751a45b35..dca73223b02fc27494a8c7dd5c91749edfec49c7 100644
--- a/src/FlysystemStreamWrapperManager.php
+++ b/src/FlysystemStreamWrapperManager.php
@@ -9,6 +9,7 @@ use Drupal\Core\StreamWrapper\StreamWrapperManager;
 use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
 use Drupal\flysystem\Adapter\CacheItemBackend;
 use Drupal\flysystem\Adapter\DrupalCacheAdapter;
+use Drupal\flysystem\Adapter\FlysystemAdapterInterface;
 use Drupal\flysystem\Event\EnsureEvent;
 use Drupal\flysystem\Event\FlysystemEvents;
 use League\Flysystem\Filesystem;
@@ -69,7 +70,7 @@ class FlysystemStreamWrapperManager extends StreamWrapperManager {
   /**
    * Created plugins.
    *
-   * @var \Drupal\flysystem\Plugin\FlysystemPluginInterface[]
+   * @var \Drupal\flysystem\Adapter\FlysystemAdapterInterface[]
    */
   protected $plugins = [];
 
@@ -134,7 +135,7 @@ class FlysystemStreamWrapperManager extends StreamWrapperManager {
    * @param string $scheme
    *   The scheme.
    *
-   * @return \Drupal\flysystem\Plugin\FlysystemPluginInterface
+   * @return \Drupal\flysystem\Adapter\FlysystemAdapterInterface
    *   The plugin.
    */
   public function getPlugin($scheme) {
@@ -171,7 +172,7 @@ class FlysystemStreamWrapperManager extends StreamWrapperManager {
   }
 
   /**
-   * Calls FlysystemPluginInterface::ensure() on each plugin.
+   * Calls FlysystemAdapterInterface::ensure() on each plugin.
    *
    * @param bool $force
    *   (optional) Wheter to force the insurance. Defaults to false.
diff --git a/src/FlysystemSubAdapterInterface.php b/src/FlysystemSubAdapterInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..a9410b8c99b1b13f62d98b208e3d4f5dca97465c
--- /dev/null
+++ b/src/FlysystemSubAdapterInterface.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\flysystem;
+
+use Drupal\Component\Plugin\ConfigurableInterface;
+use Drupal\Component\Plugin\DependentPluginInterface;
+use Drupal\Component\Plugin\DerivativeInspectionInterface;
+use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Plugin\PluginFormInterface;
+
+/**
+ * Interface for flysystem_adapter plugins.
+ */
+interface FlysystemSubAdapterInterface extends PluginFormInterface, PluginInspectionInterface, DerivativeInspectionInterface, ConfigurableInterface, DependentPluginInterface, ContainerFactoryPluginInterface {
+
+  /**
+   * Returns the translated plugin label.
+   */
+  public function label(): string;
+
+  /**
+   * Returns the subAdaper description.
+   *
+   * @return string
+   *   SubAdapter description.
+   */
+  public function getDescription();
+
+}
diff --git a/src/Form/ConfigForm.php b/src/Form/ConfigForm.php
index e2c98ed1568ecefa4384636723824b86cd8058a1..06095a7f8fceb661a00ebee7cd4db5133d0d221d 100644
--- a/src/Form/ConfigForm.php
+++ b/src/Form/ConfigForm.php
@@ -230,16 +230,20 @@ class ConfigForm extends FormBase {
    * @param string $scheme
    *   The scheme.
    *
-   * @return mixed
+   * @return array|FALSE
    *   A list of files, or FALSE.
    */
   protected function getFileList($scheme) {
     $filesystem = $this->factory->getFilesystem($scheme);
+    $directoryContents = $filesystem->listContents('', TRUE);
 
-    $files = array_filter($filesystem->listContents('', TRUE), function ($meta) {
+    $files = array_filter($directoryContents->toArray(), function ($meta) {
       return $meta['type'] === 'file';
     });
-
+    // @todo solve phpstan issue:
+    // Parameter #1 $callback of function array_map expects
+    // (callable(League\Flysystem\StorageAttributes): mixed)|null, 
+    // Closure(array): mixed given. 
     return array_map(function (array $meta) {
       return $meta['path'];
     }, $files);
diff --git a/src/Form/FlysystemAdapterConfigForm.php b/src/Form/FlysystemAdapterConfigForm.php
new file mode 100644
index 0000000000000000000000000000000000000000..9da09f65f73320db26d6316a6f20b729aca5818c
--- /dev/null
+++ b/src/Form/FlysystemAdapterConfigForm.php
@@ -0,0 +1,309 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\flysystem\Form;
+
+use Drupal\Component\Plugin\Exception\PluginException;
+use Drupal\Component\Render\MarkupInterface;
+use Drupal\Component\Utility\Html;
+use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Messenger\MessengerInterface;
+use Drupal\Core\Plugin\PluginFormInterface;
+use Drupal\Core\Render\Markup;
+use Drupal\flysystem\Entity\FlysystemAdapterConfig;
+use Drupal\flysystem\FlysystemAdapterConfigInterface;
+use Drupal\flysystem\FlysystemAdapterPluginManager;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Flysystem_adapter_config form.
+ */
+final class FlysystemAdapterConfigForm extends EntityForm {
+  /**
+   * The adapter plugin manager.
+   *
+   * @var \Drupal\flysystem\FlysystemAdapterPluginManager
+   */
+  protected $subAdapterPluginManager;
+
+  /**
+   * The messenger.
+   *
+   * @var \Drupal\Core\Messenger\MessengerInterface
+   */
+  protected $messenger;
+
+  /**
+   * Constructs a FlysystemAdapterConfigForm object.
+   *
+   * @param \Drupal\flysystem\FlysystemAdapterPluginManager $subadapter_plugin_manager
+   *   The adapter plugin manager.
+   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
+   *   The messenger.
+   */
+  public function __construct(FlysystemAdapterPluginManager $subadapter_plugin_manager, MessengerInterface $messenger) {
+    $this->subAdapterPluginManager = $subadapter_plugin_manager;
+    $this->messenger = $messenger;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    $subadapter_plugin_manager = $container->get('plugin.manager.flysystem_adapter');
+    $messenger = $container->get('messenger');
+
+    return new static($subadapter_plugin_manager, $messenger);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function form(array $form, FormStateInterface $form_state): array {
+    // If the form is being rebuilt, rebuild the entity with the current form
+    // values.
+    if ($form_state->isRebuilding()) {
+      $this->entity = $this->buildEntity($form, $form_state);
+    }
+
+    $form = parent::form($form, $form_state);
+
+    /** @var \Drupal\flysystem\FlysystemAdapterConfigInterface $flysystem_adapter_config */
+    $flysystem_adapter_config = $this->getEntity();
+    // Set the page title according to whether we are creating or editing the
+    // adapter.
+    if ($flysystem_adapter_config->isNew()) {
+      $form['#title'] = $this->t('Configure a new Flysystem Adapter');
+    }
+    else {
+      $form['#title'] = $this->t('Edit Flysystem Adapter %label', ['%label' => $flysystem_adapter_config->label()]);
+    }
+
+    $this->buildEntityConfigForm($form, $form_state, $flysystem_adapter_config);
+
+    // Skip adding the adapter config form if we cleared the adapter form due to
+    // an error.
+    if ($form) {
+      $this->buildSubAdapterConfigForm($form, $form_state, $flysystem_adapter_config);
+    }
+
+    return $form;
+  }
+
+  /**
+   * Builds the form for the basic adapter configuration properties.
+   *
+   * @param array $form
+   *   The current form array.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current form state.
+   * @param \Drupal\flysystem\FlysystemAdapterConfigInterface $flysystem_adapter_config
+   *   The server that is being created or edited.
+   */
+  protected function buildEntityConfigForm(array &$form, FormStateInterface $form_state, FlysystemAdapterConfigInterface $flysystem_adapter_config) {
+    // var_dump($flysystem_adapter_config); die;.
+    $form['label'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Label'),
+      '#maxlength' => 255,
+      '#default_value' => $flysystem_adapter_config->label(),
+      '#required' => TRUE,
+    ];
+
+    $form['id'] = [
+      '#type' => 'machine_name',
+      '#default_value' => $flysystem_adapter_config->id(),
+      '#machine_name' => [
+        'exists' => [FlysystemAdapterConfig::class, 'load'],
+      ],
+      '#disabled' => !$flysystem_adapter_config->isNew(),
+    ];
+
+    $form['status'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Enabled'),
+      '#default_value' => $flysystem_adapter_config->status(),
+    ];
+
+    $form['description'] = [
+      '#type' => 'textarea',
+      '#title' => $this->t('Description'),
+      '#default_value' => $flysystem_adapter_config->getDescription(),
+    ];
+
+    $sub_adapters = $this->subAdapterPluginManager->getDefinitions();
+    $options = [];
+    $descriptions = [];
+    foreach ($sub_adapters as $subadapter_id => $definition) {
+      $config = $subadapter_id === $flysystem_adapter_config->getSubAdapterId() ? $flysystem_adapter_config->getSubAdapterConfig() : [];
+      $config['#flysystem_adapter_config'] = $flysystem_adapter_config;
+      try {
+        /** @var \Drupal\flysystem\FlysystemSubAdapterInterface $sub_adapter */
+        $sub_adapter = $this->subAdapterPluginManager
+          ->createInstance($subadapter_id, $config);
+      }
+      catch (PluginException) {
+        // @todo add graceful error handling.
+        continue;
+      }
+      $options[$subadapter_id] = $this->escapeHtml($sub_adapter->label());
+      $descriptions[$subadapter_id]['#description'] = $this->escapeHtml($sub_adapter->getDescription());
+
+    }
+    asort($options, SORT_NATURAL | SORT_FLAG_CASE);
+    if ($options) {
+      if (count($options) == 1) {
+        $flysystem_adapter_config->set('sub_adapter', key($options));
+      }
+      $form['sub_adapter'] = [
+        '#type' => 'radios',
+        '#title' => $this->t('Flysystem Adapters'),
+        '#description' => $this->t('Choose a Flysystem Adapter type to configure.'),
+        '#options' => $options,
+        '#default_value' => $flysystem_adapter_config->getSubAdapterId(),
+        '#required' => TRUE,
+        '#disabled' => !$flysystem_adapter_config->isNew(),
+        '#ajax' => [
+          'callback' => [get_class($this), 'buildAjaxBackendConfigForm'],
+          'wrapper' => 'flysystem-adapter-config-form',
+          'method' => 'replace',
+          'effect' => 'fade',
+        ],
+      ];
+      $form['sub_adapter'] += $descriptions;
+    }
+    /*
+    else {
+    // @todo update with link to documentation on D.O.
+    $url = 'https://www.drupal.org/docs/8/modules/search-api/getting-started/server-backends-and-features';
+    $args[':url'] = Url::fromUri($url)->toString();
+    $error = $this->t('There are no Flysystem Adapters available to configure. \
+    Install a <a href=":url">module that provides a Flysystem Adapter</a> \
+    to proceed.', $args);
+    $this->messenger->addError($error);
+    $form = [];
+    }
+     */
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function actions(array $form, FormStateInterface $form_state) {
+    if ($form === []) {
+      return [];
+    }
+
+    return parent::actions($form, $form_state);
+  }
+
+  /**
+   * Builds the adapter-specific configuration form.
+   *
+   * @param array $form
+   *   The current form array.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current form state.
+   * @param \Drupal\flysystem\FlysystemAdapterConfigInterface $flysystem_adapter_config
+   *   The adapter that is being created or edited.
+   */
+  public function buildSubAdapterConfigForm(array &$form, FormStateInterface $form_state, FlysystemAdapterConfigInterface $flysystem_adapter_config) {
+    // var_dump($flysystem_adapter_config); die(__METHOD__ . ":" . __LINE__);
+    // var_dump($form_state->getValues()); die(__METHOD__ . ":" . __LINE__);.
+    $form['sub_adapter_config'] = [];
+    if ($flysystem_adapter_config->hasValidSubAdapter()) {
+      // var_dump($flysystem_adapter_config); die(__METHOD__ . ":" . __LINE__);.
+      $sub_adapter_plugin = $flysystem_adapter_config->getSubAdapter();
+
+      $form_state->set('sub_adapter', $sub_adapter_plugin->getPluginId());
+      $form_state->set(['sub_adapter_config', 'schema'], $flysystem_adapter_config->getSubAdapterValue('schema'));
+
+      if ($sub_adapter_plugin instanceof PluginFormInterface) {
+        if ($form_state->isRebuilding()) {
+          $this->messenger->addWarning($this->t('Configure the selected Flysystem Adapter.'));
+        }
+
+        // Attach the subadapter plugin configuration form.
+        $form['sub_adapter_config'] = $sub_adapter_plugin->buildSubConfigurationForm($form['sub_adapter_config'], $form_state, $flysystem_adapter_config);
+        // var_dump($form['sub_adapter_config']['schema']); die;
+        // Modify the backend plugin configuration container element.
+        $form['sub_adapter_config']['#type'] = 'details';
+        $form['sub_adapter_config']['#title'] = $this->t('Configure %plugin configuration', ['%plugin' => $sub_adapter_plugin->label()]);
+        $form['sub_adapter_config']['#open'] = TRUE;
+      }
+    }
+    // Only notify the user of a missing backend plugin if we're editing an
+    // existing server.
+    elseif (!$flysystem_adapter_config->isNew()) {
+      $this->messenger->addError($this->t('The Flysystem adapter plugin is missing or invalid.'));
+      return;
+    }
+    $form['sub_adapter_config'] += [
+      '#type' => 'container',
+    ];
+    $form['sub_adapter_config']['#attributes']['id'] = 'flysystem-adapter-config-form';
+    $form['sub_adapter_config']['#tree'] = TRUE;
+  }
+
+  /**
+   * Handles switching the selected adapter plugin.
+   *
+   * @param array $form
+   *   The current form array.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current form state.
+   *
+   * @return array
+   *   The part of the form to return as AJAX.
+   */
+  public static function buildAjaxAdapterConfigForm(array $form, FormStateInterface $form_state) {
+    // The work is already done in form(), where we rebuild the entity according
+    // to the current form values and then create the backend configuration form
+    // based on that. So we just need to return the relevant part of the form
+    // here.
+    return $form['sub_adapter_config'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state): int {
+    $result = parent::save($form, $form_state);
+    $this->messenger->addStatus($this->t('The Flysystem adapter was successfully saved.'));
+    $message_args = ['%label' => $this->entity->label()];
+    $message = '';
+    switch ($result) {
+      case \SAVED_NEW:
+        $message = $this->t('Created new example %label.', $message_args);
+        break;
+
+      case \SAVED_UPDATED:
+        $message = $this->t('Updated example %label.', $message_args);
+        break;
+    }
+    $this->messenger()->addStatus($message);
+    $form_state->setRedirectUrl($this->entity->toUrl('collection'));
+    return $result;
+  }
+
+  /**
+   * Escapes HTML special characters in plain text, if necessary.
+   *
+   * @param string|\Drupal\Component\Render\MarkupInterface $text
+   *   The text to escape.
+   *
+   * @return \Drupal\Component\Render\MarkupInterface
+   *   If a markup object was passed as $text, it is returned as-is. Otherwise,
+   *   the text is escaped and returned
+   */
+  private function escapeHtml($text) {
+    if ($text instanceof MarkupInterface) {
+      return $text;
+    }
+
+    return Markup::create(Html::escape((string) $text));
+  }
+
+}
diff --git a/src/Plugin/FlysystemAdapterPluginBase.php b/src/Plugin/FlysystemAdapterPluginBase.php
new file mode 100644
index 0000000000000000000000000000000000000000..38060fd3d065bf13a8917b8eb9368188d97524f0
--- /dev/null
+++ b/src/Plugin/FlysystemAdapterPluginBase.php
@@ -0,0 +1,106 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\flysystem\Plugin;
+
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\PluginDependencyTrait;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Base class for flysystem_adapter plugins.
+ */
+abstract class FlysystemAdapterPluginBase extends PluginBase {
+
+  use PluginDependencyTrait {
+    getPluginDependencies as traitGetPluginDependencies;
+    calculatePluginDependencies as traitCalculatePluginDependencies;
+  }
+  use StringTranslationTrait;
+
+  /**
+   * The adapter plugin configuration.
+   *
+   * @var array
+   */
+  protected $sub_adapter_config = [];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
+    $configuration += $this->defaultConfiguration();
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    $plugin = new static($configuration, $plugin_id, $plugin_definition);
+
+    /** @var \Drupal\Core\StringTranslation\TranslationInterface $translation */
+    $translation = $container->get('string_translation');
+    $plugin->setStringTranslation($translation);
+
+    return $plugin;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSubAdapterValue($key) {
+    if (is_array($key)) {
+      return NestedArray::getValue($key, $this->sub_adapter_config);
+    }
+    return $this->sub_adapter_config[$key] ?? '';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function calculateDependencies() {
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfiguration() {
+    return $this->configuration;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setConfiguration(array $configuration) {
+    $this->configuration = $configuration + $this->defaultConfiguration();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function label(): string {
+    // Cast the label to a string since it is a TranslatableMarkup object.
+    return (string) $this->pluginDefinition['label'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    return $form;
+  }
+
+}
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
deleted file mode 100644
index 079563db8d09fb362212ee3cccf48c42e9d90255..0000000000000000000000000000000000000000
--- a/tests/bootstrap.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-/**
- * @file
- * Searches for the core bootstrap file.
- */
-
-$dir = __DIR__;
-
-// Match against previous dir for Windows.
-$previous_dir = '';
-
-while ($dir = dirname($dir)) {
-  // We've reached the root.
-  if ($dir === $previous_dir) {
-    break;
-  }
-
-  $previous_dir = $dir;
-
-  if (is_file($dir . '/core/tests/bootstrap.php')) {
-    require_once $dir . '/core/tests/bootstrap.php';
-    return;
-  }
-}
-
-throw new RuntimeException('Unable to load core bootstrap.php.');
diff --git a/tests/src/Functional/ModuleInstallUninstallWebTest.php b/tests/src/Functional/ModuleInstallUninstallWebTest.php
deleted file mode 100644
index 8cb2d41cd2421355dd483d8c19005c6a16917f8f..0000000000000000000000000000000000000000
--- a/tests/src/Functional/ModuleInstallUninstallWebTest.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Functional;
-
-use Drupal\Tests\BrowserTestBase;
-
-/**
- * Tests module installation and uninstallation.
- *
- * @group flysystem
- */
-class ModuleInstallUninstallWebTest extends BrowserTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected $defaultTheme = 'stark';
-
-  /**
-   * {@inheritdoc}
-   */
-  protected static $modules = ['flysystem'];
-
-  /**
-   * Tests installation and uninstallation.
-   */
-  public function testInstallationAndUninstallation() {
-    $module_handler = \Drupal::moduleHandler();
-    $this->assertTrue($module_handler->moduleExists(reset(static::$modules)));
-
-    /** @var \Drupal\Core\Extension\ModuleInstallerInterface $module_installer */
-    $module_installer = \Drupal::service('module_installer');
-
-    $module_installer->uninstall(static::$modules);
-    $this->assertFalse($module_handler->moduleExists(reset(static::$modules)));
-  }
-
-}
diff --git a/tests/src/Kernel/CollectionOptimizerTest.php b/tests/src/Kernel/CollectionOptimizerTest.php
deleted file mode 100644
index 9fb14f7ed0bb56e0e3979c0364bf52412033f090..0000000000000000000000000000000000000000
--- a/tests/src/Kernel/CollectionOptimizerTest.php
+++ /dev/null
@@ -1,184 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Kernel;
-
-use Drupal\Core\Asset\AssetCollectionGrouperInterface;
-use Drupal\Core\Asset\CssOptimizer;
-use Drupal\Core\Asset\JsOptimizer;
-use Drupal\Core\State\StateInterface;
-use Drupal\flysystem\Asset\AssetDumper;
-use Drupal\flysystem\Asset\CssCollectionOptimizer;
-use Drupal\flysystem\Asset\JsCollectionOptimizer;
-use Drupal\KernelTests\KernelTestBase;
-use org\bovigo\vfs\vfsStream;
-
-/**
- * @covers \Drupal\flysystem\Asset\JsCollectionOptimizer
- * @covers \Drupal\flysystem\Asset\CssCollectionOptimizer
- *
- * @group flysystem
- */
-class CollectionOptimizerTest extends KernelTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected static $modules = ['file'];
-
-  /**
-   * The file URL generator.
-   *
-   * @var \Drupal\Core\File\FileUrlGeneratorInterface
-   */
-  protected $fileUrlGenerator;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setUp(): void {
-    parent::setUp();
-    $this->fileUrlGenerator = $this->container->get('file_url_generator');
-    $this->cleanUp();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function tearDown(): void {
-    $this->cleanUp();
-    parent::tearDown();
-  }
-
-  /**
-   * @covers \Drupal\flysystem\Asset\JsCollectionOptimizer
-   */
-  public function testJsCollectionOptimizer() {
-    vfsStream::setup('js');
-
-    $this->setSetting('flysystem', [
-      'vfs' => [
-        'serve_js' => TRUE,
-        'driver' => 'local',
-      ],
-    ]);
-
-    foreach ($this->jsFilesUnderTest() as $js_file => $expired) {
-      file_put_contents($js_file, 'dummy');
-      if ($expired === TRUE) {
-        // 2592000 is the default value of stale_file_threshold
-        touch($js_file, \Drupal::time()->getRequestTime() - 2592001);
-        continue;
-      }
-      touch($js_file, \Drupal::time()->getRequestTime() - 2591999);
-    }
-
-    $grouper = $this->prophesize(AssetCollectionGrouperInterface::class);
-    $dumper = $this->prophesize(AssetDumper::class);
-    $state = $this->prophesize(StateInterface::class);
-
-    $optimizer = new JsCollectionOptimizer($grouper->reveal(), new JsOptimizer(), $dumper->reveal(), $state->reveal(), $this->container->get('file_system'));
-    $optimizer->deleteAll();
-
-    foreach ($this->jsFilesUnderTest() as $js_file => $expired) {
-      if ($expired === TRUE) {
-        $this->assertFileDoesNotExist($js_file);
-        continue;
-      }
-      $this->assertFileExists($js_file);
-    }
-
-  }
-
-  /**
-   * @covers \Drupal\flysystem\Asset\CssCollectionOptimizer
-   */
-  public function testCssCollectionOptimizer() {
-    vfsStream::setup('css');
-
-    $this->setSetting('flysystem', [
-      'vfs' => [
-        'serve_css' => TRUE,
-        'driver' => 'local',
-      ],
-    ]);
-
-    foreach ($this->cssFilesUnderTest() as $css_file => $expired) {
-      file_put_contents($css_file, 'dummy');
-      if ($expired === TRUE) {
-        // 2592000 is the default value of stale_file_threshold
-        touch($css_file, \Drupal::time()->getRequestTime() - 2592001);
-        continue;
-      }
-      touch($css_file, \Drupal::time()->getRequestTime() - 2591999);
-    }
-
-    $grouper = $this->prophesize(AssetCollectionGrouperInterface::class);
-    $dumper = $this->prophesize(AssetDumper::class);
-    $state = $this->prophesize(StateInterface::class);
-
-    $optimizer = new CssCollectionOptimizer($grouper->reveal(), new CssOptimizer($this->fileUrlGenerator), $dumper->reveal(), $state->reveal(), $this->container->get('file_system'));
-    $optimizer->deleteAll();
-
-    foreach ($this->cssFilesUnderTest() as $css_file => $expired) {
-      if ($expired === TRUE) {
-        $this->assertFileDoesNotExist($css_file);
-        continue;
-      }
-      $this->assertFileExists($css_file);
-    }
-
-  }
-
-  /**
-   * CSS files involve in testing CssCollectionOptimizer.
-   *
-   * @return array
-   *   Keyed by the file URI, and its value is the flag of expiration. TRUE to
-   *   valid, FALSE to expired.
-   */
-  private function cssFilesUnderTest() {
-    return [
-      'vfs://css/foo_expired.css' => TRUE,
-      'vfs://css/bar_expired.css' => TRUE,
-      'vfs://css/baz_expired.css' => TRUE,
-      'vfs://css/foo.css' => FALSE,
-      'vfs://css/bar.css' => FALSE,
-      'vfs://css/baz.css' => FALSE,
-    ];
-  }
-
-  /**
-   * JS files involve in testing JsCollectionOptimizer.
-   *
-   * @return array
-   *   Keyed by the file URI, and its value is the flag of expiration. TRUE to
-   *   expired, FALSE to non-expired.
-   */
-  private function jsFilesUnderTest() {
-    return [
-      'vfs://js/foo_expired.js' => TRUE,
-      'vfs://js/bar_expired.js' => TRUE,
-      'vfs://js/baz_expired.js' => TRUE,
-      'vfs://js/foo.js' => FALSE,
-      'vfs://js/bar.js' => FALSE,
-      'vfs://js/zoo.js' => FALSE,
-    ];
-  }
-
-  /**
-   * A helper method for removing files before and after running tests.
-   */
-  private function cleanUp() {
-    foreach ($this->jsFilesUnderTest() as $js_file => $flag) {
-      if (file_exists($js_file)) {
-        unlink($js_file);
-      }
-    }
-    foreach ($this->cssFilesUnderTest() as $css_file => $flag) {
-      if (file_exists($css_file)) {
-        unlink($css_file);
-      }
-    }
-  }
-
-}
diff --git a/tests/src/Unit/Asset/SchemeExtensionTraitTest.php b/tests/src/Unit/Asset/SchemeExtensionTraitTest.php
deleted file mode 100644
index a9a01a9c781c4b39031c3552789fea3789d08b83..0000000000000000000000000000000000000000
--- a/tests/src/Unit/Asset/SchemeExtensionTraitTest.php
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\Asset;
-
-use Drupal\Core\Site\Settings;
-use Drupal\flysystem\Asset\SchemeExtensionTrait;
-use Drupal\Tests\UnitTestCase;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\Asset\SchemeExtensionTrait
- * @group flysystem
- */
-class SchemeExtensionTraitTest extends UnitTestCase {
-
-  /**
-   * @covers ::getSchemeForExtension
-   */
-  public function test() {
-
-    new Settings([
-      'flysystem' => [
-        'local' => ['serve_js' => TRUE, 'driver' => 'asdf'],
-        'ftp' => ['serve_css' => TRUE],
-      ],
-    ]);
-
-    $trait = $this->getMockForTrait(SchemeExtensionTrait::class);
-    $this->assertSame('local', $trait->getSchemeForExtension('js'));
-    $this->assertSame('public', $trait->getSchemeForExtension('css'));
-    $this->assertSame('public', $trait->getSchemeForExtension('jpg'));
-  }
-
-}
diff --git a/tests/src/Unit/Event/EnsureEventTest.php b/tests/src/Unit/Event/EnsureEventTest.php
deleted file mode 100644
index 8960845826e74c4d8b593dd47786cfcc4b52d3b5..0000000000000000000000000000000000000000
--- a/tests/src/Unit/Event/EnsureEventTest.php
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\Event;
-
-use Drupal\flysystem\Event\EnsureEvent;
-use Drupal\Tests\UnitTestCase;
-
-/**
- * Tests EnsureEvent.
- *
- * @coversDefaultClass \Drupal\flysystem\Event\EnsureEvent
- * @covers \Drupal\flysystem\Event\EnsureEvent
- * @group flysystem
- */
-class EnsureEventTest extends UnitTestCase {
-
-  /**
-   * Tests the basic setters/getters of EnsureEvent.
-   */
-  public function test() {
-    $event = new EnsureEvent('scheme', 10, 'message', ['1234']);
-
-    $this->assertSame('scheme', $event->getScheme());
-    $this->assertSame(10, $event->getSeverity());
-    $this->assertSame('message', $event->getMessage());
-    $this->assertSame(['1234'], $event->getContext());
-  }
-
-}
diff --git a/tests/src/Unit/EventSubscriber/EnsureSubscriberTest.php b/tests/src/Unit/EventSubscriber/EnsureSubscriberTest.php
deleted file mode 100644
index 2b2effd16308697fdb885ee089fd29e3dda2ea1a..0000000000000000000000000000000000000000
--- a/tests/src/Unit/EventSubscriber/EnsureSubscriberTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\EventSubscriber;
-
-use Drupal\flysystem\Event\EnsureEvent;
-use Drupal\flysystem\Event\FlysystemEvents;
-use Drupal\flysystem\EventSubscriber\EnsureSubscriber;
-use Drupal\Tests\UnitTestCase;
-use Psr\Log\LoggerInterface;
-use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\EventSubscriber\EnsureSubscriber
- * @covers \Drupal\flysystem\EventSubscriber\EnsureSubscriber
- *
- * @group flysystem
- */
-class EnsureSubscriberTest extends UnitTestCase {
-
-  /**
-   * Tests that the event subscriber logs ensure() calls.
-   */
-  public function testLoggingHappens() {
-    $logger = $this->prophesize(LoggerInterface::class);
-    $dispatcher = $this->createMock(EventDispatcherInterface::class);
-    $logger->log('severity', 'message', ['context'])->shouldBeCalled();
-
-    $event = new EnsureEvent('scheme', 'severity', 'message', ['context']);
-
-    $subscriber = new EnsureSubscriber($logger->reveal());
-
-    $subscriber->onEnsure($event, FlysystemEvents::ENSURE, $dispatcher);
-  }
-
-  /**
-   * Tests that the ENSURE event is registered.
-   */
-  public function testSubscribedEvents() {
-    $result = EnsureSubscriber::getSubscribedEvents();
-
-    $this->assertTrue(isset($result[FlysystemEvents::ENSURE]));
-  }
-
-}
diff --git a/tests/src/Unit/Flysystem/Adapter/CacheItemBackendTest.php b/tests/src/Unit/Flysystem/Adapter/CacheItemBackendTest.php
deleted file mode 100644
index 6c235672598bdf7220121a36bf813dc5dc138f99..0000000000000000000000000000000000000000
--- a/tests/src/Unit/Flysystem/Adapter/CacheItemBackendTest.php
+++ /dev/null
@@ -1,100 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\Flysystem\Adapter;
-
-use Drupal\Core\Cache\MemoryBackend;
-use Drupal\flysystem\Flysystem\Adapter\CacheItem;
-use Drupal\flysystem\Flysystem\Adapter\CacheItemBackend;
-use Drupal\Tests\UnitTestCase;
-
-/**
- * Tests \Drupal\flysystem\Flysystem\Adapter\CacheItemBackend.
- *
- * @group flysystem
- *
- * @coversDefaultClass \Drupal\flysystem\Flysystem\Adapter\CacheItemBackend
- * @covers \Drupal\flysystem\Flysystem\Adapter\CacheItemBackend
- */
-class CacheItemBackendTest extends UnitTestCase {
-
-  /**
-   * The cache backend used in the CacheItemBackend.
-   *
-   * @var \Drupal\Core\Cache\CacheBackendInterface
-   */
-  protected $cacheBackend;
-
-  /**
-   * The cache item backend to test.
-   *
-   * @var \Drupal\flysystem\Flysystem\Adapter\CacheItemBackend
-   */
-  protected $cacheItemBackend;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setUp(): void {
-    parent::setUp();
-    $this->cacheBackend = new MemoryBackend('foo');
-    $this->cacheItemBackend = new CacheItemBackend('test-scheme', $this->cacheBackend);
-  }
-
-  /**
-   * Tests whether a cache item exists.
-   */
-  public function testHas() {
-    $this->assertFalse($this->cacheItemBackend->has('test.txt'));
-  }
-
-  /**
-   * Tests loading a cache item from the cache.
-   */
-  public function testSetIsLoaded() {
-    $cache_item = new CacheItem();
-    $cache_item->updateMetadata(['mimetype' => 'test_mimetype']);
-    $this->cacheItemBackend->set('test_path', $cache_item);
-
-    $metadata = $this->cacheItemBackend->load('test_path')->getMetadata();
-    $this->assertSame('test_mimetype', $metadata['mimetype']);
-  }
-
-  /**
-   * Tests when loading a cache item creates a new item.
-   */
-  public function testLoadMiss() {
-    $item = $this->cacheItemBackend->load('test_path');
-    $this->assertInstanceOf(CacheItem::class, $item);
-  }
-
-  /**
-   * Tests deleting by a path.
-   */
-  public function testDelete() {
-    $cache_item = new CacheItem();
-    $cache_item->updateMetadata(['mimetype' => 'test_mimetype']);
-
-    $this->cacheItemBackend->set('test_path', $cache_item);
-    $this->cacheItemBackend->delete('test_path');
-
-    $metadata = $this->cacheItemBackend->load('test_path')->getMetadata();
-    $this->assertTrue(empty($metadata['mimetype']));
-  }
-
-  /**
-   * Tests deleting multiple items at once.
-   */
-  public function testDeleteMultiple() {
-    $cache_item_one = new CacheItem();
-    $cache_item_two = new CacheItem();
-
-    $this->cacheItemBackend->set('one', $cache_item_one);
-    $this->cacheItemBackend->set('two', $cache_item_two);
-
-    $this->cacheItemBackend->deleteMultiple(['one', 'two']);
-
-    $this->assertNotSame($cache_item_one, $this->cacheItemBackend->load('one'));
-    $this->assertNotSame($cache_item_two, $this->cacheItemBackend->load('two'));
-  }
-
-}
diff --git a/tests/src/Unit/Flysystem/Adapter/CacheItemTest.php b/tests/src/Unit/Flysystem/Adapter/CacheItemTest.php
deleted file mode 100644
index 70a91bf3ef7a26402c67048f0b7eaa7b42c1ca39..0000000000000000000000000000000000000000
--- a/tests/src/Unit/Flysystem/Adapter/CacheItemTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\Flysystem\Adapter;
-
-use Drupal\flysystem\Flysystem\Adapter\CacheItem;
-use Drupal\Tests\UnitTestCase;
-
-/**
- * Tests \Drupal\flysystem\Flysystem\Adapter\CacheItem.
- *
- * @group flysystem
- *
- * @coversDefaultClass \Drupal\flysystem\Flysystem\Adapter\CacheItem
- * @covers \Drupal\flysystem\Flysystem\Adapter\CacheItem
- */
-class CacheItemTest extends UnitTestCase {
-
-  /**
-   * Tests metadata updating and getting.
-   */
-  public function test() {
-    $cache_item = new CacheItem();
-
-    $metadata = [
-      'size' => 1234,
-      'mimetype' => 'test_mimetype',
-      'visibility' => 'public',
-      'timestamp' => 123456,
-      'type' => 'file',
-      'contents' => 'test contents',
-      'path' => 'file_path',
-    ];
-
-    $cache_item->updateMetadata($metadata);
-
-    unset($metadata['contents'], $metadata['path']);
-
-    $this->assertSame($metadata, $cache_item->getMetadata());
-
-  }
-
-}
diff --git a/tests/src/Unit/Flysystem/Adapter/DrupalCacheAdapterTest.php b/tests/src/Unit/Flysystem/Adapter/DrupalCacheAdapterTest.php
deleted file mode 100644
index 0b6d04eb45f2a7c944aaea15a72164046ca06072..0000000000000000000000000000000000000000
--- a/tests/src/Unit/Flysystem/Adapter/DrupalCacheAdapterTest.php
+++ /dev/null
@@ -1,299 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\Flysystem\Adapter;
-
-use Drupal\Core\Cache\MemoryBackend;
-use Drupal\flysystem\Flysystem\Adapter\CacheItemBackend;
-use Drupal\flysystem\Flysystem\Adapter\DrupalCacheAdapter;
-use Drupal\Tests\UnitTestCase;
-use League\Flysystem\AdapterInterface;
-use League\Flysystem\Config;
-
-/**
- * Test the Drupal Cache Adapter.
- *
- * @group flysystem
- *
- * @coversDefaultClass \Drupal\flysystem\Flysystem\Adapter\DrupalCacheAdapter
- * @covers \Drupal\flysystem\Flysystem\Adapter\DrupalCacheAdapter
- */
-class DrupalCacheAdapterTest extends UnitTestCase {
-
-  /**
-   * URI scheme to use for testing.
-   *
-   * @var string
-   */
-  const SCHEME = 'test-scheme';
-
-  /**
-   * The main test file.
-   *
-   * @var string
-   */
-  const FILE = 'test.txt';
-
-  /**
-   * The wrapped Flysytem adaper.
-   *
-   * @var \League\Flysystem\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject
-   */
-  protected $adapter;
-
-  /**
-   * The cache adapter under test.
-   *
-   * @var \Drupal\flysystem\Flysystem\Adapter\DrupalCacheAdapter
-   */
-  protected $cacheAdapter;
-
-  /**
-   * The flysystem backend for testing.
-   *
-   * @var \Drupal\flysystem\Flysystem\Adapter\CacheItemBackend
-   */
-  protected $cacheItemBackend;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setUp(): void {
-    parent::setUp();
-    $this->cacheItemBackend = new CacheItemBackend(static::SCHEME, new MemoryBackend('foo'));
-    $this->adapter = $this->prophesize(AdapterInterface::class);
-    $this->cacheAdapter = new DrupalCacheAdapter(static::SCHEME, $this->adapter->reveal(), $this->cacheItemBackend);
-  }
-
-  /**
-   * Tests creating a public file.
-   */
-  public function testWriteSuccess() {
-    $config = new Config();
-    $this->adapter
-      ->write(static::FILE, 'contents', $config)
-      ->willReturn(['visibility' => 'public']);
-
-    $metadata = $this->cacheAdapter->write(static::FILE, 'contents', $config);
-    $this->assertSame('public', $metadata['visibility']);
-    $this->assertSame('public', $this->cacheAdapter->getVisibility(static::FILE)['visibility']);
-    $this->assertTrue($this->cacheItemBackend->has(static::FILE));
-  }
-
-  /**
-   * Tests creating a public file stream.
-   */
-  public function testWriteStreamSuccess() {
-    $config = new Config();
-    $stream = fopen('data:text/plain,contents', 'rb');
-
-    $this->adapter
-      ->writeStream(static::FILE, $stream, $config)
-      ->willReturn(['timestamp' => 12345]);
-
-    $metadata = $this->cacheAdapter->writeStream(static::FILE, $stream, $config);
-    $this->assertSame(12345, $metadata['timestamp']);
-    $this->assertSame(12345, $this->cacheAdapter->getTimestamp(static::FILE)['timestamp']);
-    $this->assertTrue($this->cacheItemBackend->has(static::FILE));
-  }
-
-  /**
-   * Tests public file updates.
-   */
-  public function testUpdateSuccess() {
-    $config = new Config();
-    $this->adapter
-      ->update(static::FILE, 'contents', $config)
-      ->willReturn(['visibility' => 'public']);
-
-    $metadata = $this->cacheAdapter->update(static::FILE, 'contents', $config);
-    $this->assertSame('public', $metadata['visibility']);
-    $this->assertSame('public', $this->cacheAdapter->getVisibility(static::FILE)['visibility']);
-  }
-
-  /**
-   * Tests public file stream updates.
-   */
-  public function testUpdateStreamSuccess() {
-    $config = new Config();
-    $stream = fopen('data:text/plain,contents', 'rb');
-
-    $this->adapter
-      ->updateStream(static::FILE, $stream, $config)
-      ->willReturn(['mimetype' => 'test_mimetype']);
-
-    $metadata = $this->cacheAdapter->updateStream(static::FILE, $stream, $config);
-    $this->assertSame('test_mimetype', $metadata['mimetype']);
-    $this->assertSame('test_mimetype', $this->cacheAdapter->getMimetype(static::FILE)['mimetype']);
-    $this->assertTrue($this->cacheItemBackend->has(static::FILE));
-  }
-
-  /**
-   * Tests renaming a file.
-   */
-  public function testRenameSuccess() {
-    $config = new Config();
-    $this->adapter
-      ->write(static::FILE, 'contents', $config)
-      ->willReturn(['size' => 1234]);
-
-    $this->cacheAdapter->write(static::FILE, 'contents', $config);
-
-    $this->adapter
-      ->rename(static::FILE, 'new.txt')
-      ->willReturn(TRUE);
-
-    $this->assertTrue($this->cacheAdapter->rename(static::FILE, 'new.txt'));
-    $this->assertSame(1234, $this->cacheAdapter->getSize('new.txt')['size']);
-
-    $this->assertFalse($this->cacheItemBackend->has(static::FILE));
-    $this->assertTrue($this->cacheItemBackend->has('new.txt'));
-
-  }
-
-  /**
-   * Tests copying a file.
-   */
-  public function testCopySuccess() {
-    $config = new Config();
-    $this->adapter
-      ->write(static::FILE, 'contents', $config)
-      ->willReturn(['size' => 1234]);
-
-    $this->cacheAdapter->write(static::FILE, 'contents', $config);
-
-    $this->adapter->copy(static::FILE, 'new.txt')->willReturn(TRUE);
-
-    $this->assertTrue($this->cacheAdapter->copy(static::FILE, 'new.txt'));
-
-    $this->assertSame(1234, $this->cacheAdapter->getSize(static::FILE)['size']);
-    $this->assertSame(1234, $this->cacheAdapter->getSize('new.txt')['size']);
-    $this->assertTrue($this->cacheItemBackend->has(static::FILE));
-    $this->assertTrue($this->cacheItemBackend->has('new.txt'));
-  }
-
-  /**
-   * Tests deleting a file.
-   */
-  public function testDeleteSuccess() {
-    $config = new Config();
-    $this->adapter
-      ->write(static::FILE, 'contents', $config)
-      ->willReturn(['size' => 1234]);
-
-    $this->cacheAdapter->write(static::FILE, 'contents', $config);
-
-    $this->adapter->delete(static::FILE)->willReturn(TRUE);
-
-    $this->assertTrue($this->cacheAdapter->delete(static::FILE));
-    $this->assertFalse($this->cacheItemBackend->has(static::FILE));
-  }
-
-  /**
-   * Tests deleting a file directory.
-   */
-  public function testDeleteDirSuccess() {
-    $config = new Config();
-    // Create a directory with one sub file.
-    $this->adapter->createDir('testdir', $config)->willReturn(['type' => 'dir']);
-    $this->adapter->write('testdir/test.txt', 'contents', $config)
-      ->willReturn(['size' => 1234]);
-    $this->adapter->deleteDir('testdir')->willReturn(TRUE);
-    $this->adapter->listContents('testdir', TRUE)->willReturn([
-      ['path' => 'testdir'],
-      ['path' => 'testdir/test.txt'],
-    ]);
-
-    $this->cacheAdapter->createDir('testdir', $config);
-    $this->cacheAdapter->write('testdir/test.txt', 'contents', $config);
-
-    $this->assertTrue($this->cacheAdapter->deleteDir('testdir'));
-
-    $this->assertFalse($this->cacheItemBackend->has('testdir/test.txt'));
-    $this->assertFalse($this->cacheItemBackend->has('testdir'));
-  }
-
-  /**
-   * Tests visibility checking on private files.
-   */
-  public function testSetVisibilitySuccess() {
-    $this->adapter
-      ->setVisibility(static::FILE, 'private')
-      ->willReturn(['visibility' => 'private']);
-
-    $metadata = $this->cacheAdapter->setVisibility(static::FILE, 'private');
-    $this->assertSame('private', $metadata['visibility']);
-    $this->assertSame('private', $this->cacheAdapter->getVisibility(static::FILE)['visibility']);
-    $this->assertTrue($this->cacheItemBackend->has(static::FILE));
-  }
-
-  /**
-   * Tests file loading success.
-   */
-  public function testHasSuccess() {
-    $cache_item = $this->cacheItemBackend->load(static::FILE);
-    $this->cacheItemBackend->set(static::FILE, $cache_item);
-    $this->assertTrue($this->cacheAdapter->has(static::FILE));
-  }
-
-  /**
-   * Tests file loading failure.
-   */
-  public function testHasFail() {
-    $this->adapter->has(static::FILE)->willReturn(TRUE);
-    $this->assertTrue($this->cacheAdapter->has(static::FILE));
-  }
-
-  /**
-   * Tests reading a file.
-   */
-  public function testRead() {
-    $this->adapter->read(static::FILE)->willReturn(TRUE);
-    $this->assertTrue($this->cacheAdapter->read(static::FILE));
-  }
-
-  /**
-   * Tests reading a stream.
-   */
-  public function testReadStream() {
-    $this->adapter->readStream(static::FILE)->willReturn(TRUE);
-    $this->assertTrue($this->cacheAdapter->readStream(static::FILE));
-  }
-
-  /**
-   * Tests listing contents of a directory.
-   */
-  public function testListContentsSuccess() {
-    $this->adapter->listContents('testdir', TRUE)->willReturn(TRUE);
-    $this->assertTrue($this->cacheAdapter->listContents('testdir', TRUE));
-  }
-
-  /**
-   * Tests retrieving file metadata.
-   */
-  public function testGetMetadataSuccess() {
-    $cache_item = $this->cacheItemBackend->load(static::FILE);
-    $cache_item->updateMetadata(['type' => 'dir']);
-    $this->cacheItemBackend->set(static::FILE, $cache_item);
-
-    $this->assertSame('dir', $this->cacheAdapter->getMetadata(static::FILE)['type']);
-  }
-
-  /**
-   * Tests failing to retrieve file metadata.
-   */
-  public function testGetMetadataFail() {
-    $this->adapter->getMetadata(static::FILE)->willReturn(['type' => 'dir']);
-
-    $this->assertSame('dir', $this->cacheAdapter->getMetadata(static::FILE)['type']);
-  }
-
-  /**
-   * Tests failing to retrieve file size.
-   */
-  public function testGetSizeFail() {
-    $this->adapter->getSize(static::FILE)->willReturn(['size' => 123]);
-
-    $this->assertSame(123, $this->cacheAdapter->getSize(static::FILE)['size']);
-  }
-
-}
diff --git a/tests/src/Unit/Flysystem/Adapter/MissingAdapterTest.php b/tests/src/Unit/Flysystem/Adapter/MissingAdapterTest.php
deleted file mode 100644
index 7bae52f524c2facf20a20331cce938fce7f54308..0000000000000000000000000000000000000000
--- a/tests/src/Unit/Flysystem/Adapter/MissingAdapterTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\Flysystem\Adapter;
-
-use Drupal\flysystem\Flysystem\Adapter\MissingAdapter;
-use Drupal\Tests\UnitTestCase;
-use League\Flysystem\Config;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\Flysystem\Adapter\MissingAdapter
- * @group flysystem
- */
-class MissingAdapterTest extends UnitTestCase {
-
-  /**
-   * @covers \Drupal\flysystem\Flysystem\Adapter\MissingAdapter
-   */
-  public function test() {
-    $adapter = new MissingAdapter();
-
-    $this->assertFalse($adapter->copy('', ''));
-    $this->assertFalse($adapter->createDir('', new Config()));
-    $this->assertFalse($adapter->delete(''));
-    $this->assertFalse($adapter->deleteDir(''));
-    $this->assertIsArray($adapter->listContents(''));
-    $this->assertFalse($adapter->getMetadata(''));
-    $this->assertFalse($adapter->getMimetype(''));
-    $this->assertFalse($adapter->getSize(''));
-    $this->assertFalse($adapter->getTimestamp(''));
-    $this->assertFalse($adapter->getVisibility(''));
-    $this->assertFalse($adapter->has(''));
-    $this->assertFalse($adapter->setVisibility('', 'public'));
-    $this->assertFalse($adapter->update('', '', new Config()));
-    $this->assertFalse($adapter->updateStream('', NULL, new Config()));
-    $this->assertFalse($adapter->read(''));
-    $this->assertFalse($adapter->readStream(''));
-    $this->assertFalse($adapter->rename('', ''));
-    $this->assertFalse($adapter->write('', '', new Config()));
-    $this->assertFalse($adapter->writeStream('', NULL, new Config()));
-  }
-
-}
diff --git a/tests/src/Unit/Flysystem/LocalTest.php b/tests/src/Unit/Flysystem/LocalTest.php
deleted file mode 100644
index 233f8b391f7d51c43e0c1c543c856166d284597c..0000000000000000000000000000000000000000
--- a/tests/src/Unit/Flysystem/LocalTest.php
+++ /dev/null
@@ -1,147 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\Flysystem;
-
-use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Drupal\Core\Logger\RfcLogLevel;
-use Drupal\Core\Routing\UrlGeneratorInterface;
-use Drupal\Core\Site\Settings;
-use Drupal\flysystem\Flysystem\Adapter\MissingAdapter;
-use Drupal\flysystem\Flysystem\Local;
-use Drupal\Tests\UnitTestCase;
-use League\Flysystem\Adapter\Local as LocalAdapter;
-use Prophecy\Argument;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\Flysystem\Local
- * @group flysystem
- */
-class LocalTest extends UnitTestCase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setUp(): void {
-    parent::setUp();
-    $GLOBALS['base_url'] = 'http://example.com';
-
-    $container = new ContainerBuilder();
-    $url_generator = $this->prophesize(UrlGeneratorInterface::class);
-    $url_generator->generateFromRoute(Argument::cetera())->willReturn('download');
-    $container->set('url_generator', $url_generator->reveal());
-    \Drupal::setContainer($container);
-    (new LocalAdapter('foo/bar'))->deleteDir('');
-    @rmdir('foo/bar');
-    @rmdir('foo');
-    mkdir('foo');
-    mkdir('foo/bar');
-
-    touch('test.txt');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function tearDown(): void {
-    (new LocalAdapter('foo'))->deleteDir('');
-    @rmdir('foo');
-
-    unlink('test.txt');
-
-    @unlink('does_not_exist/.htaccess');
-    @rmdir('does_not_exist');
-  }
-
-  /**
-   * @covers ::__construct
-   * @covers ::create
-   */
-  public function testCreateReturnsPlugin() {
-    $container = new ContainerBuilder();
-    $settings = new Settings([]);
-    $container->set('settings', $settings);
-
-    $configuration = ['root' => 'foo/bar'];
-
-    $this->assertInstanceOf(Local::class, Local::create($container, $configuration, '', []));
-  }
-
-  /**
-   * @covers ::getAdapter
-   * @covers ::ensureDirectory
-   */
-  public function testReturnsLocalAdapter() {
-    $this->assertInstanceOf(LocalAdapter::class, (new Local('foo/bar', FALSE))->getAdapter());
-  }
-
-  /**
-   * @covers ::getAdapter
-   * @covers ::ensureDirectory
-   */
-  public function testMissingAdapterReturnedWhenPathIsFile() {
-    $this->assertInstanceOf(MissingAdapter::class, (new Local('test.txt'))->getAdapter());
-  }
-
-  /**
-   * @covers ::getExternalUrl
-   */
-  public function testReturnsValidLocalUrl() {
-    $plugin = new Local('foo/bar', FALSE);
-    $this->assertSame('download', $plugin->getExternalUrl('uri://test.html'));
-  }
-
-  /**
-   * @covers ::getExternalUrl
-   */
-  public function testReturnsValidExternalUrl() {
-    $plugin = new Local('foo/bar', TRUE);
-    $this->assertSame('http://example.com/foo/bar/test%20thing.html', $plugin->getExternalUrl('uri://test thing.html'));
-  }
-
-  /**
-   * @covers ::ensure
-   * @covers ::ensureDirectory
-   */
-  public function testDirectoryIsAutoCreatedAndHtaccessIsWritten() {
-    new Local('does_not_exist');
-    $this->assertTrue(is_dir('does_not_exist'));
-    $this->assertTrue(is_file('does_not_exist/.htaccess'));
-
-  }
-
-  /**
-   * @covers ::ensure
-   * @covers ::writeHtaccess
-   */
-  public function testHtaccessNotOverwritten() {
-    file_put_contents('foo/bar/.htaccess', 'htcontent');
-
-    $result = (new Local('foo/bar'))->ensure();
-
-    $this->assertCount(1, $result);
-    $this->assertSame(RfcLogLevel::INFO, $result[0]['severity']);
-    $this->assertSame('htcontent', file_get_contents('foo/bar/.htaccess'));
-  }
-
-  /**
-   * @covers ::ensure
-   * @covers ::writeHtaccess
-   */
-  public function testHtaccessNotOverwrittenAndFails() {
-    mkdir('foo/bar/.htaccess', 0777, TRUE);
-
-    $result = (new Local('foo/bar'))->ensure(TRUE);
-    $this->assertCount(1, $result);
-    $this->assertSame('https://www.drupal.org/SA-CORE-2013-003', $result[0]['context']['@url']);
-  }
-
-  /**
-   * @covers ::ensure
-   * @covers ::writeHtaccess
-   */
-  public function testEnsureReturnsErrorWhenCantCreateDir() {
-    $result = (new Local('test.txt'))->ensure();
-    $this->assertSame('test.txt', $result[0]['context']['%root']);
-  }
-
-}
diff --git a/tests/src/Unit/Flysystem/MissingTest.php b/tests/src/Unit/Flysystem/MissingTest.php
deleted file mode 100644
index d69a8bbd4be12bca2dd143601418e09d92a3cded..0000000000000000000000000000000000000000
--- a/tests/src/Unit/Flysystem/MissingTest.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\Flysystem;
-
-use Drupal\flysystem\Flysystem\Adapter\MissingAdapter;
-use Drupal\flysystem\Flysystem\Missing;
-use Drupal\Tests\UnitTestCase;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\Flysystem\Missing
- * @group flysystem
- */
-class MissingTest extends UnitTestCase {
-
-  /**
-   * @covers \Drupal\flysystem\Flysystem\Missing
-   */
-  public function test() {
-    $plugin = new Missing([]);
-    $this->assertInstanceOf(MissingAdapter::class, $plugin->getAdapter());
-    $this->assertTrue(is_array($plugin->ensure()));
-    $this->assertCount(1, $plugin->ensure());
-    $this->assertSame('', $plugin->getExternalUrl('asdf'));
-  }
-
-}
diff --git a/tests/src/Unit/FlysystemServiceProviderTest.php b/tests/src/Unit/FlysystemServiceProviderTest.php
deleted file mode 100644
index 7312582b9c57baff2f3b4bf706e5e3d44dc884d2..0000000000000000000000000000000000000000
--- a/tests/src/Unit/FlysystemServiceProviderTest.php
+++ /dev/null
@@ -1,144 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit;
-
-use Drupal\Core\Asset\AssetDumper;
-use Drupal\Core\Asset\CssCollectionOptimizer;
-use Drupal\Core\Asset\CssOptimizer;
-use Drupal\Core\Asset\JsCollectionOptimizer;
-use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Drupal\Core\Site\Settings;
-use Drupal\flysystem\Asset\AssetDumper as FlysystemAssetDumper;
-use Drupal\flysystem\Asset\CssCollectionOptimizer as FlysystemCssCollectionOptimizer;
-use Drupal\flysystem\Asset\CssOptimizer as FlysystemCssOptimizer;
-use Drupal\flysystem\Asset\JsCollectionOptimizer as FlysystemJsCollectionOptimizer;
-use Drupal\flysystem\FlysystemStreamWrapper;
-use Drupal\flysystem\FlysystemServiceProvider;
-use Drupal\flysystem\PathProcessor\LocalPathProcessor;
-use Drupal\Tests\UnitTestCase;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\FlysystemServiceProvider
- * @group flysystem
- */
-class FlysystemServiceProviderTest extends UnitTestCase {
-
-  /**
-   * The container.
-   *
-   * @var \Symfony\Component\DependencyInjection\ContainerInterface
-   */
-  protected $container;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setUp(): void {
-    parent::setUp();
-    $this->container = new ContainerBuilder();
-  }
-
-  /**
-   * @covers ::register
-   */
-  public function testNothingFailsIfContainerIsEmpty() {
-    new Settings([]);
-    (new FlysystemServiceProvider())->register($this->container);
-    $this->assertFalse($this->container->has('flysystem_stream_wrapper'));
-  }
-
-  /**
-   * @covers ::register
-   */
-  public function testMissingDriverIsSkipped() {
-    new Settings(['flysystem' => ['testscheme' => []]]);
-
-    (new FlysystemServiceProvider())->register($this->container);
-
-    $this->assertFalse($this->container->has('flysystem_stream_wrapper.testscheme'));
-  }
-
-  /**
-   * @covers ::register
-   */
-  public function testValidSchemeConfiguration() {
-    new Settings(['flysystem' => ['testscheme' => ['driver' => 'whatever']]]);
-
-    (new FlysystemServiceProvider())->register($this->container);
-
-    $this->assertTrue($this->container->has('flysystem_stream_wrapper.testscheme'));
-    $this->assertSame(FlysystemStreamWrapper::class, $this->container->getDefinition('flysystem_stream_wrapper.testscheme')->getClass());
-    $this->assertSame([['scheme' => 'testscheme']], $this->container->getDefinition('flysystem_stream_wrapper.testscheme')->getTag('stream_wrapper'));
-  }
-
-  /**
-   * @covers ::register
-   */
-  public function testLocalRouteProviderGetsAdded() {
-    new Settings([
-      'flysystem' => [
-        'testscheme' => [
-          'driver' => 'local',
-          'config' => ['public' => TRUE],
-        ],
-      ],
-    ]);
-
-    (new FlysystemServiceProvider())->register($this->container);
-    $this->assertSame(LocalPathProcessor::class, $this->container->getDefinition('flysystem.testscheme.path_processor')->getClass());
-  }
-
-  /**
-   * @covers \Drupal\flysystem\FlysystemServiceProvider
-   */
-  public function test() {
-    // Test swapping the asset dumper.
-    $this->container->register('asset.js.dumper', AssetDumper::class);
-    (new FlysystemServiceProvider())->register($this->container);
-    $this->assertSame(AssetDumper::class, $this->container->getDefinition('asset.js.dumper')->getClass());
-
-    $this->container->register('asset.js.collection_optimizer', JsCollectionOptimizer::class);
-    (new FlysystemServiceProvider())->register($this->container);
-    $this->assertSame(AssetDumper::class, $this->container->getDefinition('asset.js.dumper')->getClass());
-    $this->assertSame(JsCollectionOptimizer::class, $this->container->getDefinition('asset.js.collection_optimizer')->getClass());
-
-    // A successful swap.
-    new Settings([
-      'flysystem' => [
-        'testscheme' => [
-          'driver' => 'whatever',
-          'serve_js' => TRUE,
-        ],
-      ],
-    ]);
-    (new FlysystemServiceProvider())->register($this->container);
-    $this->assertSame(FlysystemAssetDumper::class, $this->container->getDefinition('asset.js.dumper')->getClass());
-    $this->assertSame(FlysystemJsCollectionOptimizer::class, $this->container->getDefinition('asset.js.collection_optimizer')->getClass());
-  }
-
-  /**
-   * @covers \Drupal\flysystem\FlysystemServiceProvider
-   */
-  public function testSwappingCssServices() {
-    // Test swapping the asset dumper.
-    $this->container->register('asset.css.dumper', AssetDumper::class);
-    $this->container->register('asset.css.collection_optimizer', CssCollectionOptimizer::class);
-    $this->container->register('asset.css.optimizer', CssOptimizer::class);
-
-    new Settings([
-      'flysystem' => [
-        'testscheme' => [
-          'driver' => 'whatever',
-          'serve_css' => TRUE,
-        ],
-      ],
-    ]);
-
-    (new FlysystemServiceProvider())->register($this->container);
-
-    $this->assertSame(FlysystemAssetDumper::class, $this->container->getDefinition('asset.css.dumper')->getClass());
-    $this->assertSame(FlysystemCssCollectionOptimizer::class, $this->container->getDefinition('asset.css.collection_optimizer')->getClass());
-    $this->assertSame(FlysystemCssOptimizer::class, $this->container->getDefinition('asset.css.optimizer')->getClass());
-  }
-
-}
diff --git a/tests/src/Unit/FlysystemStreamWrapperManagerTest.php b/tests/src/Unit/FlysystemStreamWrapperManagerTest.php
deleted file mode 100644
index 9bf18dae9f199bfbec18d93baeff18b28c0048a6..0000000000000000000000000000000000000000
--- a/tests/src/Unit/FlysystemStreamWrapperManagerTest.php
+++ /dev/null
@@ -1,215 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit;
-
-use Drupal\Component\Plugin\PluginManagerInterface;
-use Drupal\Core\Cache\NullBackend;
-use Drupal\Core\Site\Settings;
-use Drupal\Core\StreamWrapper\StreamWrapperManager;
-use Drupal\flysystem\Flysystem\Adapter\DrupalCacheAdapter;
-use Drupal\flysystem\Flysystem\Adapter\MissingAdapter;
-use Drupal\flysystem\Flysystem\Missing;
-use Drupal\flysystem\FlysystemStreamWrapperManager;
-use Drupal\flysystem\Plugin\FlysystemPluginInterface;
-use Drupal\Tests\UnitTestCase;
-use League\Flysystem\Adapter\NullAdapter;
-use League\Flysystem\FilesystemInterface;
-use League\Flysystem\Replicate\ReplicateAdapter;
-use Prophecy\Argument;
-use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\FlysystemStreamWrapperManager
- * @group flysystem
- */
-class FlysystemStreamWrapperManagerTest extends UnitTestCase {
-
-  /**
-   * Backend Cache.
-   *
-   * @var \Drupal\Core\Cache\CacheBackendInterface
-   */
-  protected $cache;
-
-  /**
-   * Event Dispatcher.
-   *
-   * @var \Symfony\Contracts\EventDispatcher\EventDispatcherInterface
-   */
-  protected $eventDispatcher;
-
-  /**
-   * Mocked File System.
-   *
-   * @var \Prophecy\Prophecy\ObjectProphecy
-   */
-  protected $filesystem;
-
-  /**
-   * Mocked Plugin.
-   *
-   * @var \Prophecy\Prophecy\ObjectProphecy
-   */
-  protected $plugin;
-
-  /**
-   * Mocked Plugin Manager.
-   *
-   * @var \Prophecy\Prophecy\ObjectProphecy
-   */
-  protected $pluginManager;
-
-  /**
-   * Mocked Settings manager.
-   */
-  protected $settings;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setUp(): void {
-    parent::setUp();
-
-    $this->cache = new NullBackend('bin');
-    $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
-
-    $this->pluginManager = $this->prophesize(PluginManagerInterface::class);
-    $this->plugin = $this->prophesize(FlysystemPluginInterface::class);
-    $this->plugin->getAdapter()->willReturn(new NullAdapter());
-
-    $this->pluginManager->createInstance('testdriver', [])->willReturn($this->plugin->reveal());
-    $this->pluginManager->createInstance('', [])->willReturn(new Missing());
-
-    $this->filesystem = $this->prophesize(StreamWrapperManager::class);
-    $this->filesystem->isValidScheme(Argument::type('string'))->willReturn(TRUE);
-
-    $this->settings = $this->prophesize(Settings::class);
-  }
-
-  /**
-   * @covers ::getFilesystem
-   * @covers ::__construct
-   * @covers ::getAdapter
-   * @covers ::getSettings
-   * @covers ::getPlugin
-   */
-  public function testGetFilesystemReturnsValidFilesystem() {
-    new Settings([
-      'flysystem' => [
-        'testscheme' => ['driver' => 'testdriver'],
-      ],
-    ]);
-
-    $factory = $this->getFactory();
-
-    $this->assertInstanceOf(FilesystemInterface::class, $factory->getFilesystem('testscheme'));
-    $this->assertInstanceOf(NullAdapter::class, $factory->getFilesystem('testscheme')->getAdapter());
-  }
-
-  /**
-   * @covers ::getFilesystem
-   */
-  public function testGetFilesystemReturnsMissingFilesystem() {
-    new Settings([]);
-    $factory = $this->getFactory();
-    $this->assertInstanceOf(MissingAdapter::class, $factory->getFilesystem('testscheme')->getAdapter());
-  }
-
-  /**
-   * @covers ::getFilesystem
-   * @covers ::getAdapter
-   */
-  public function testGetFilesystemReturnsCachedAdapter() {
-    new Settings([
-      'flysystem' => [
-        'testscheme' => ['driver' => 'testdriver' , 'cache' => TRUE],
-      ],
-    ]);
-
-    $factory = $this->getFactory();
-    $this->assertInstanceOf(DrupalCacheAdapter::class, $factory->getFilesystem('testscheme')->getAdapter());
-  }
-
-  /**
-   * @covers ::getFilesystem
-   * @covers ::getAdapter
-   */
-  public function testGetFilesystemReturnsReplicateAdapter() {
-    // Test replicate.
-    $this->pluginManager->createInstance('wrapped', [])->willReturn($this->plugin->reveal());
-
-    new Settings([
-      'flysystem' => [
-        'testscheme' => ['driver' => 'testdriver' , 'replicate' => 'wrapped'],
-        'wrapped' => ['driver' => 'testdriver'],
-      ],
-    ]);
-
-    $factory = $this->getFactory();
-    $this->assertInstanceOf(ReplicateAdapter::class, $factory->getFilesystem('testscheme')->getAdapter());
-  }
-
-  /**
-   * @covers ::getSchemes
-   * @covers ::__construct
-   */
-  public function testGetSchemesFiltersInvalidSchemes() {
-    new Settings([
-      'flysystem' => [
-        'testscheme' => ['driver' => 'testdriver'],
-        'invalidscheme' => ['driver' => 'testdriver'],
-      ],
-    ]);
-
-    $this->filesystem->isValidScheme('invalidscheme')->willReturn(FALSE);
-
-    $this->assertSame(['testscheme'], $this->getFactory()->getSchemes());
-  }
-
-  /**
-   * @covers ::getSchemes
-   */
-  public function testGetSchemesHandlesNoSchemes() {
-    new Settings([]);
-    $this->assertSame([], $this->getFactory()->getSchemes());
-  }
-
-  /**
-   * @covers ::ensure
-   */
-  public function testEnsureReturnsErrors() {
-    new Settings([
-      'flysystem' => [
-        'testscheme' => ['driver' => 'testdriver'],
-      ],
-    ]);
-
-    $this->plugin->ensure(FALSE)->willReturn([[
-      'severity' => 'bad',
-      'message' => 'Something bad',
-      'context' => [],
-    ],
-    ]);
-
-    $errors = $this->getFactory()->ensure();
-
-    $this->assertSame('Something bad', $errors['testscheme'][0]['message']);
-  }
-
-  /**
-   * Gets and returns the Flysystem Factory.
-   *
-   * @return \Drupal\flysystem\FlysystemStreamWrapperManager
-   *   Flysystem Factory.
-   */
-  protected function getFactory() {
-    return new FlysystemStreamWrapperManager(
-      $this->pluginManager->reveal(),
-      $this->filesystem->reveal(),
-      $this->cache,
-      $this->eventDispatcher,
-      $this->settings
-    );
-  }
-
-}
diff --git a/tests/src/Unit/FlysystemStreamWrapperTest.php b/tests/src/Unit/FlysystemStreamWrapperTest.php
deleted file mode 100644
index de3f0196a27168af5ccaf6003faea287003a5291..0000000000000000000000000000000000000000
--- a/tests/src/Unit/FlysystemStreamWrapperTest.php
+++ /dev/null
@@ -1,123 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit;
-
-use Drupal\Core\StreamWrapper\StreamWrapperInterface;
-use Drupal\flysystem\Flysystem\Adapter\MissingAdapter;
-use Drupal\flysystem\Flysystem\Missing;
-use Drupal\flysystem\FlysystemStreamWrapper;
-use Drupal\flysystem\FlysystemStreamWrapperManager;
-use Drupal\Tests\UnitTestCase;
-use League\Flysystem\Filesystem;
-use Symfony\Component\DependencyInjection\ContainerBuilder;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\FlysystemStreamWrapper
- * @group flysystem
- */
-class FlysystemStreamWrapperTest extends UnitTestCase {
-
-  /**
-   * Flysystem Bridge.
-   *
-   * @var \Drupal\flysystem\FlysystemStreamWrapper
-   */
-  protected $bridge;
-
-  /**
-   * File system.
-   *
-   * @var \League\Flysystem\FilesystemInterface
-   */
-  protected $filesystem;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setUp(): void {
-    parent::setUp();
-    $this->bridge = new FlysystemStreamWrapper();
-    $this->bridge->setStringTranslation($this->getStringTranslationStub());
-    $this->bridge->setUri('testscheme://file.txt');
-
-    $factory = $this->prophesize(FlysystemStreamWrapperManager::class);
-    $factory->getPlugin('testscheme')->willReturn(new Missing());
-
-    $this->filesystem = new Filesystem(new MissingAdapter());
-
-    $factory->getFilesystem('testscheme')->willReturn($this->filesystem);
-
-    $factory->getSettings('testscheme')->willReturn([
-      'name' => '',
-      'description' => '',
-    ]);
-
-    $container = new ContainerBuilder();
-    $container->set('flysystem_factory', $factory->reveal());
-    \Drupal::setContainer($container);
-  }
-
-  /**
-   * @covers ::getType
-   */
-  public function testGetTypeReturnsWriteVisible() {
-    $this->assertSame(StreamWrapperInterface::WRITE_VISIBLE, FlysystemStreamWrapper::getType());
-  }
-
-  /**
-   * @covers ::getName
-   */
-  public function testGetNameFormattingCorrect() {
-    $this->assertSame('Flysystem: testscheme', (string) $this->bridge->getName());
-  }
-
-  /**
-   * @covers ::getDescription
-   */
-  public function testGetDescriptionFormattingCorrect() {
-    $this->assertSame('Flysystem: testscheme', (string) $this->bridge->getDescription());
-  }
-
-  /**
-   * @covers ::getUri
-   * @covers ::setUri
-   */
-  public function testGetUriMatchesSetUri() {
-    $this->bridge->setUri('beep://boop');
-    $this->assertSame('beep://boop', $this->bridge->getUri());
-  }
-
-  /**
-   * @covers ::getExternalUrl
-   * @covers ::getFactory
-   */
-  public function testGetExternalUrlDelegatesToPlugin() {
-    $this->assertSame('', $this->bridge->getExternalUrl('testscheme://testfile.txt'));
-  }
-
-  /**
-   * @covers ::realpath
-   */
-  public function testRealpathIsFalse() {
-    $this->assertFalse($this->bridge->realpath());
-  }
-
-  /**
-   * @covers ::dirname
-   */
-  public function testDirname() {
-    $this->assertSame('testscheme://', $this->bridge->dirname());
-    $this->assertSame('testscheme://dir://dir', $this->bridge->dirname('testscheme:///dir://dir/file.txt'));
-  }
-
-  /**
-   * @covers ::getFilesystem
-   * @covers ::getFilesystemForScheme
-   */
-  public function testGetFilesystemOverridden() {
-    $method = new \ReflectionMethod($this->bridge, 'getFilesystem');
-    $method->setAccessible(TRUE);
-    $this->assertSame($this->filesystem, $method->invoke($this->bridge));
-  }
-
-}
diff --git a/tests/src/Unit/Form/ConfigFormTest.php b/tests/src/Unit/Form/ConfigFormTest.php
deleted file mode 100644
index db43cadc0afd877ccbe4085847c591de7a584bcf..0000000000000000000000000000000000000000
--- a/tests/src/Unit/Form/ConfigFormTest.php
+++ /dev/null
@@ -1,300 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\Form {
-
-  use Drupal\Core\Form\FormState;
-  use Drupal\Core\Logger\LoggerChannelFactoryInterface;
-  use Drupal\Core\Messenger\MessengerInterface;
-  use Drupal\flysystem\FlysystemStreamWrapperManager;
-  use Drupal\flysystem\Form\ConfigForm;
-  use Drupal\Tests\UnitTestCase;
-  use League\Flysystem\Filesystem;
-  use League\Flysystem\FilesystemInterface;
-  use League\Flysystem\Memory\MemoryAdapter;
-  use Prophecy\Argument;
-  use Psr\Log\LoggerInterface;
-  use Symfony\Component\DependencyInjection\ContainerBuilder;
-  use function Drupal\flysystem\Form\batch_set;
-
-  /**
-   * @coversDefaultClass \Drupal\flysystem\Form\ConfigForm
-   * @group flysystem
-   */
-  class ConfigFormTest extends UnitTestCase {
-
-    /**
-     * The Flysystem factory prophecy.
-     *
-     * @var \Prophecy\Prophecy\ObjectProphecy
-     */
-    protected $factory;
-
-    /**
-     * The form object.
-     *
-     * @var \Drupal\flysystem\Form\ConfigForm
-     */
-    protected $form;
-
-    /**
-     * {@inheritdoc}
-     */
-    public function setUp(): void {
-      parent::setUp();
-
-      $this->factory = $this->prophesize(FlysystemStreamWrapperManager::class);
-      $this->factory->getFilesystem('from_empty')->willReturn(new Filesystem(new MemoryAdapter()));
-      $this->factory->getFilesystem('to_empty')->willReturn(new Filesystem(new MemoryAdapter()));
-      $this->factory->getSchemes()->willReturn(['from_empty', 'to_empty']);
-
-      $this->form = new ConfigForm($this->factory->reveal());
-      $this->form->setStringTranslation($this->getStringTranslationStub());
-      $messenger = $this->prophesize(MessengerInterface::class);
-
-      $container = new ContainerBuilder();
-      $container->set('string_translation', $this->getStringTranslationStub());
-      $container->set('flysystem_factory', $this->factory->reveal());
-      $container->set('messenger', $messenger->reveal());
-
-      $logger = $this->prophesize(LoggerChannelFactoryInterface::class);
-      $logger->get('flysystem')->willReturn($this->prophesize(LoggerInterface::class)->reveal());
-      $container->set('logger.factory', $logger->reveal());
-
-      \Drupal::setContainer($container);
-    }
-
-    /**
-     * @covers ::create
-     * @covers ::__construct
-     */
-    public function testCreate() {
-      $container = new ContainerBuilder();
-      $container->set('flysystem_factory', $this->factory->reveal());
-
-      $this->assertInstanceOf(ConfigForm::class, ConfigForm::create($container));
-    }
-
-    /**
-     * @covers ::getFormId
-     */
-    public function testGetFormId() {
-      $this->assertSame('flysystem_config_form', $this->form->getFormId());
-    }
-
-    /**
-     * @covers ::buildForm
-     */
-    public function testBuildForm() {
-      $form = $this->form->buildForm([], new FormState());
-      $this->assertCount(4, $form);
-
-      $this->assertTrue($form['sync_from']['#required']);
-      $this->assertTrue($form['sync_to']['#required']);
-    }
-
-    /**
-     * @covers ::validateForm
-     */
-    public function testValidateForm() {
-      $form_state = new FormState();
-      $form = $this->form->buildForm([], $form_state);
-      $form['sync_from']['#parents'] = ['sync_from'];
-      $form['sync_to']['#parents'] = ['sync_to'];
-
-      $form_state->setValue('sync_from', 'from');
-      $form_state->setValue('sync_to', 'to');
-
-      $this->form->validateForm($form, $form_state);
-      $this->assertCount(0, $form_state->getErrors());
-      $form_state->setValue('sync_to', 'from');
-
-      $this->form->validateForm($form, $form_state);
-      $this->assertCount(2, $form_state->getErrors());
-    }
-
-    /**
-     * @covers ::submitForm
-     * @covers ::getFileList
-     */
-    public function testSubmitForm() {
-      $form_state = new FormState();
-      $form = [];
-      $form_state->setValue('sync_from', 'from_empty');
-      $form_state->setValue('sync_to', 'to_empty');
-
-      $this->form->submitForm($form, $form_state);
-      $batch = batch_set();
-
-      $this->assertSame(ConfigForm::class . '::finishBatch', $batch['finished']);
-      $this->assertCount(0, $batch['operations']);
-
-      // Test with existing source files.
-      $from = new Filesystem(new MemoryAdapter());
-      $from->write('dir/test.txt', 'abcdefg');
-      $from->write('test.txt', 'abcdefg');
-      $this->factory->getFilesystem('from_files')->willReturn($from);
-
-      $form_state->setValue('sync_from', 'from_files');
-
-      $this->form->submitForm($form, $form_state);
-
-      $batch_files = array_map(function (array $operation) {
-        return $operation[1][2];
-      }, batch_set()['operations']);
-
-      $this->assertSame(['dir/test.txt', 'test.txt'], $batch_files);
-
-      // Test with existing destination files, and force true.
-      $form_state->setValue('force', TRUE);
-      $form_state->setValue('sync_to', 'from_files');
-
-      $this->form->submitForm($form, $form_state);
-
-      $batch_files = array_map(function (array $operation) {
-        return $operation[1][2];
-      }, batch_set()['operations']);
-
-      $this->assertSame(['dir/test.txt', 'test.txt'], $batch_files);
-    }
-
-    /**
-     * @covers ::copyFile
-     */
-    public function testCopyFile() {
-      $context = [];
-
-      $from = new Filesystem(new MemoryAdapter());
-      $from->write('dir/test.txt', 'abcdefg');
-      $this->factory->getFilesystem('from_files')->willReturn($from);
-
-      ConfigForm::copyFile('from_files', 'to_empty', 'dir/test.txt', $context);
-
-      $this->assertSame('abcdefg', $this->factory->reveal()->getFilesystem('to_empty')->read('dir/test.txt'));
-      $this->assertTrue(empty($context['results']));
-      $this->assertSame(1, $context['finished']);
-    }
-
-    /**
-     * @covers ::copyFile
-     */
-    public function testCopyFileFailedRead() {
-      // Tests failed read.
-      $context = [];
-      $failed_read = $this->prophesize(FilesystemInterface::class);
-      $failed_read->readStream('does_not_exist')->willReturn(FALSE);
-      $this->factory->getFilesystem('failed_read')->willReturn($failed_read->reveal());
-
-      ConfigForm::copyFile('failed_read', 'to_empty', 'does_not_exist', $context);
-
-      $to_files = $this->factory->reveal()->getFilesystem('to_empty')->listContents('', TRUE);
-      $this->assertCount(0, $to_files);
-      $this->assertCount(1, $context['results']['errors']);
-    }
-
-    /**
-     * @covers ::copyFile
-     */
-    public function testCopyFileFailedWrite() {
-      $context = [];
-
-      $from = new Filesystem(new MemoryAdapter());
-      $from->write('test.txt', 'abcdefg');
-      $this->factory->getFilesystem('from_files')->willReturn($from);
-
-      $failed_write = $this->prophesize(FilesystemInterface::class);
-      $failed_write->putStream(Argument::cetera())->willReturn(FALSE);
-      $this->factory->getFilesystem('to_fail')->willReturn($failed_write);
-
-      ConfigForm::copyFile('from_files', 'to_fail', 'test.txt', $context);
-
-      $this->assertCount(1, $context['results']['errors']);
-      $this->assertTrue(strpos($context['results']['errors'][0][0], 'could not be saved') !== FALSE);
-    }
-
-    /**
-     * @covers ::copyFile
-     */
-    public function testCopyFileException() {
-      $context = [];
-      ConfigForm::copyFile('from_empty', 'to_empty', 'does_not_exist.txt', $context);
-      $this->assertCount(2, $context['results']['errors']);
-      $this->assertTrue(strpos($context['results']['errors'][0][0], 'An eror occured while copying') !== FALSE);
-      $this->assertTrue(strpos($context['results']['errors'][1], 'File not found at path') !== FALSE);
-    }
-
-    /**
-     * @covers ::finishBatch
-     */
-    public function testFinishBatch() {
-      ConfigForm::finishBatch(TRUE, [], []);
-      ConfigForm::finishBatch(FALSE, [], ['from', 'to', 'file.txt']);
-      ConfigForm::finishBatch(TRUE, [
-        'errors' => [
-          'first error',
-          [
-            'second error', [''],
-          ],
-        ],
-      ], []);
-      // @todo refactor.
-      $this->assertTrue(TRUE);
-    }
-
-    /**
-     * Converts a file list fron Flysystem into a list of files.
-     *
-     * @param array $list
-     *   The file list from Flysystem::listContents().
-     *
-     * @return string[]
-     *   A list of file paths.
-     */
-    protected function getFileList(array $list) {
-      $list = array_filter($list, function (array $file) {
-        return $file['type'] === 'file';
-      });
-
-      return array_map(function (array $file) {
-        return $file['path'];
-      }, $list);
-    }
-
-  }
-}
-
-namespace Drupal\flysystem\Form {
-
-  /**
-   * Override for drupal_set_message().
-   */
-  function drupal_set_message() {
-  }
-
-  /**
-   * Mock batch_set() for testing.
-   */
-  function batch_set($batch = NULL) {
-    static $last_batch;
-
-    if (isset($batch)) {
-      $last_batch = $batch;
-    }
-    return $last_batch;
-  }
-
-  /**
-   * Override for drupal_set_time_limit().
-   */
-  function drupal_set_time_limit($limit) {
-    if ($limit !== 0) {
-      throw new \Exception();
-    }
-  }
-
-  /**
-   * Override for Watchdog exception().
-   */
-  function watchdog_exception() {
-  }
-
-}
diff --git a/tests/src/Unit/InstallFunctionsTest.php b/tests/src/Unit/InstallFunctionsTest.php
deleted file mode 100644
index a7c26f31d16ab3f599cbcf7b98f10214f3a1fdab..0000000000000000000000000000000000000000
--- a/tests/src/Unit/InstallFunctionsTest.php
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit;
-
-use Drupal\Core\Logger\RfcLogLevel;
-use Drupal\Core\Site\Settings;
-use Drupal\flysystem\FlysystemStreamWrapperManager;
-use Drupal\Tests\UnitTestCase;
-use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Twistor\FlysystemStreamWrapper;
-
-/**
- * Tests flysystem.install functions.
- *
- * @group flysystem
- */
-class InstallFunctionsTest extends UnitTestCase {
-
-  /**
-   * The Flysystem factory prophecy object.
-   *
-   * @var \Prophecy\Prophecy\ObjectProphecy
-   */
-  protected $factory;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setUp(): void {
-    parent::setUp();
-
-    if (!defined('REQUIREMENT_ERROR')) {
-      define('REQUIREMENT_ERROR', 2);
-    }
-
-    require_once dirname(dirname(dirname(__DIR__))) . '/flysystem.install';
-
-    $this->factory = $this->prophesize(FlysystemStreamWrapperManager::class);
-
-    $container = new ContainerBuilder();
-    $container->set('flysystem_factory', $this->factory->reveal());
-    $container->set('string_translation', $this->getStringTranslationStub());
-
-    \Drupal::setContainer($container);
-  }
-
-  /**
-   * Tests flysystem_requirements() handles update.
-   */
-  public function testFlysystemRequirementsHandlesUpdate() {
-    $dependencies_exist = (int) class_exists(FlysystemStreamWrapper::class);
-
-    $return = flysystem_requirements('update');
-    $this->assertCount((1 - $dependencies_exist), $return);
-  }
-
-  /**
-   * Tests flysystem_requirements() handles install.
-   */
-  public function testFlysystemRequirementsHandlesInstall() {
-    $dependencies_exist = (int) class_exists(FlysystemStreamWrapper::class);
-
-    $return = flysystem_requirements('install');
-    $this->assertCount((1 - $dependencies_exist), $return);
-  }
-
-  /**
-   * Tests flysystem_requirements() handles runtime.
-   */
-  public function testFlysystemRequirementsHandlesRuntime() {
-    $dependencies_exist = (int) class_exists(FlysystemStreamWrapper::class);
-
-    $this->factory->ensure()->willReturn([
-      'testscheme' => [
-        [
-          'message' => 'Test message',
-          'context' => [],
-          'severity' => RfcLogLevel::ERROR,
-        ],
-      ],
-    ]);
-
-    $return = flysystem_requirements('runtime');
-
-    $this->assertCount((2 - $dependencies_exist), $return);
-    $this->assertSame('Test message', (string) $return['flysystem:testscheme']['description']);
-  }
-
-  /**
-   * Tests flysystem_requirements() detects invalid schemes.
-   */
-  public function testFlysystemRequirementsHandlesInvalidSchemes() {
-    new Settings(['flysystem' => ['test_scheme' => []]]);
-    $requirements = flysystem_requirements('update');
-
-    $this->assertTrue(isset($requirements['flysystem_invalid_scheme']));
-  }
-
-  /**
-   * Tests flysystem_install() calls ensure().
-   */
-  public function testFlysystemInstallCallsEnsure() {
-    $this->factory->ensure()->shouldBeCalled();
-    flysystem_install();
-  }
-
-}
diff --git a/tests/src/Unit/Logger/ConvertTest.php b/tests/src/Unit/Logger/ConvertTest.php
deleted file mode 100644
index c8858796073a9fbb29432627187987070962de46..0000000000000000000000000000000000000000
--- a/tests/src/Unit/Logger/ConvertTest.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\Logger;
-
-use Drupal\Core\Logger\RfcLogLevel;
-use Drupal\flysystem\Logger\Convert;
-use Drupal\Tests\UnitTestCase;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\Logger\Convert
- * @group flysystem
- */
-class ConvertTest extends UnitTestCase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setUp(): void {
-    parent::setUp();
-    $consts = [
-      'REQUIREMENT_INFO' => -1,
-      'REQUIREMENT_OK' => 0,
-      'REQUIREMENT_WARNING' => 1,
-      'REQUIREMENT_ERROR' => 2,
-    ];
-
-    foreach ($consts as $const => $value) {
-      if (!defined($const)) {
-        define($const, $value);
-      }
-    }
-  }
-
-  /**
-   * @covers ::rfcToHookRequirements
-   */
-  public function test() {
-    $this->assertSame(REQUIREMENT_ERROR, Convert::rfcToHookRequirements(RfcLogLevel::EMERGENCY));
-    $this->assertSame(REQUIREMENT_ERROR, Convert::rfcToHookRequirements(RfcLogLevel::ERROR));
-    $this->assertSame(REQUIREMENT_WARNING, Convert::rfcToHookRequirements(RfcLogLevel::WARNING));
-    $this->assertSame(REQUIREMENT_INFO, Convert::rfcToHookRequirements(RfcLogLevel::NOTICE));
-    $this->assertSame(REQUIREMENT_INFO, Convert::rfcToHookRequirements(RfcLogLevel::INFO));
-    $this->assertSame(REQUIREMENT_OK, Convert::rfcToHookRequirements(RfcLogLevel::DEBUG));
-  }
-
-}
diff --git a/tests/src/Unit/ModuleFunctionsTest.php b/tests/src/Unit/ModuleFunctionsTest.php
deleted file mode 100644
index 6d461bc24415438cb0ea861660cfb02ed6922d73..0000000000000000000000000000000000000000
--- a/tests/src/Unit/ModuleFunctionsTest.php
+++ /dev/null
@@ -1,92 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit;
-
-use Drupal\Core\File\MimeType\ExtensionMimeTypeGuesser;
-use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
-use Drupal\flysystem\FlysystemStreamWrapperManager;
-use Drupal\Tests\UnitTestCase;
-use org\bovigo\vfs\vfsStream;
-use Prophecy\Argument;
-use Symfony\Component\DependencyInjection\ContainerBuilder;
-
-/**
- * Tests module functions.
- *
- * @group flysystem
- */
-class ModuleFunctionsTest extends UnitTestCase {
-
-  /**
-   * The Flysystem factory prophecy object.
-   *
-   * @var \Prophecy\Prophecy\ObjectProphecy
-   */
-  protected $factory;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setUp(): void {
-    parent::setUp();
-    vfsStream::setup('module_file');
-
-    require_once dirname(dirname(dirname(__DIR__))) . '/flysystem.module';
-
-    $this->factory = $this->prophesize(FlysystemStreamWrapperManager::class);
-    $this->factory->getSchemes()->willReturn(['vfs']);
-
-    $file_system_helper = $this->prophesize(StreamWrapperManagerInterface::class);
-    $file_system_helper->isValidScheme(Argument::type('string'))->will(function ($uri) {
-      [$scheme] = explode('://', $uri[0]);
-      return $scheme;
-    });
-
-    $guesser = $this->prophesize(ExtensionMimeTypeGuesser::class);
-    $guesser->guessMimeType(Argument::type('string'))->willReturn('txt/flysystem');
-
-    $container = new ContainerBuilder();
-    $container->set('file_system', $file_system_helper->reveal());
-    $container->set('flysystem_factory', $this->factory->reveal());
-    $container->set('file.mime_type.guesser.extension', $guesser->reveal());
-
-    \Drupal::setContainer($container);
-  }
-
-  /**
-   * Tests flysystem_cron() calls ensure.
-   */
-  public function testFlysystemCronCallsEnsure() {
-    $this->factory->ensure()->shouldBeCalled();
-    flysystem_cron();
-  }
-
-  /**
-   * Tests flysystem_rebuild() calls ensure.
-   */
-  public function testFlysystemRebuildCallsEnsure() {
-    $this->factory->ensure()->shouldBeCalled();
-    flysystem_rebuild();
-  }
-
-  /**
-   * Tests flysystem_file_download() handles valid schemes.
-   */
-  public function testFlysystemFileDownloadFindsValidScheme() {
-    $success = file_put_contents('vfs://module_file/file.txt', '1234');
-    $this->assertEquals($success, 4);
-    $return = flysystem_file_download('vfs://module_file/file.txt');
-
-    $this->assertEquals(2, count($return));
-    $this->assertSame('txt/flysystem', $return['Content-Type']);
-    $this->assertEquals(4, $return['Content-Length']);
-  }
-
-  /**
-   * Tests flysystem_file_download() ignores invalid schemes.
-   */
-  public function testFlysystemFileDownloadIgnoresInvalidScheme() {
-    $this->assertNull(flysystem_file_download('invalid://module_file/file.txt'));
-  }
-
-}
diff --git a/tests/src/Unit/PathProcessor/FlysystemPathProcessorTest.php b/tests/src/Unit/PathProcessor/FlysystemPathProcessorTest.php
deleted file mode 100644
index 6786151b9f2303eb1858dee7414cad869b66a87e..0000000000000000000000000000000000000000
--- a/tests/src/Unit/PathProcessor/FlysystemPathProcessorTest.php
+++ /dev/null
@@ -1,56 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\PathProcessor;
-
-use Drupal\flysystem\PathProcessor\FlysystemPathProcessor;
-use Drupal\Tests\UnitTestCase;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\PathProcessor\FlysystemPathProcessor
- * @group flysystem
- */
-class FlysystemPathProcessorTest extends UnitTestCase {
-
-  /**
-   * @covers ::processInbound
-   */
-  public function testCorrectPathsAreProccessed() {
-    $processor = new FlysystemPathProcessor();
-    $this->assertSame('beep', $processor->processInbound('beep', new Request()));
-    $this->assertSame('/_flysystem/scheme', $processor->processInbound('/_flysystem/scheme', new Request()));
-  }
-
-  /**
-   * @covers ::processInbound
-   */
-  public function testImageStylesAreProccessed() {
-    $request = new Request();
-    $processor = new FlysystemPathProcessor();
-    $this->assertSame('/_flysystem/styles/scheme/small', $processor->processInbound('/_flysystem/scheme/styles/scheme/small/image.jpg', $request));
-    $this->assertSame($request->query->get('file'), 'image.jpg');
-    $this->assertSame('/_flysystem/styles/scheme/small', $processor->processInbound('/_flysystem/scheme/styles/scheme/small/dir/image.jpg', $request));
-    $this->assertSame($request->query->get('file'), 'dir/image.jpg');
-  }
-
-  /**
-   * @covers ::processInbound
-   */
-  public function testDownloadPathsAreProccessed() {
-    $request = new Request();
-    $processor = new FlysystemPathProcessor();
-    $this->assertSame('/_flysystem/scheme', $processor->processInbound('/_flysystem/scheme/file.txt', $request));
-    $this->assertSame('file.txt', $request->query->get('file'));
-  }
-
-  /**
-   * @covers ::processInbound
-   */
-  public function testDownloadPathsInSubDirsAreProccessed() {
-    $request = new Request();
-    $processor = new FlysystemPathProcessor();
-    $this->assertSame('/_flysystem/scheme', $processor->processInbound('/_flysystem/scheme/a/b/c/file.txt', $request));
-    $this->assertSame('a/b/c/file.txt', $request->query->get('file'));
-  }
-
-}
diff --git a/tests/src/Unit/PathProcessor/LocalPathProcessorTest.php b/tests/src/Unit/PathProcessor/LocalPathProcessorTest.php
deleted file mode 100644
index 9cd9e1e48c63f59c25626bd24434a3235014b9ff..0000000000000000000000000000000000000000
--- a/tests/src/Unit/PathProcessor/LocalPathProcessorTest.php
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\PathProcessor;
-
-use Drupal\Core\Site\Settings;
-use Drupal\flysystem\PathProcessor\LocalPathProcessor;
-use Drupal\Tests\UnitTestCase;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\PathProcessor\LocalPathProcessor
- * @group flysystem
- */
-class LocalPathProcessorTest extends UnitTestCase {
-
-  /**
-   * Inbound Path processor.
-   *
-   * @var \Drupal\Core\PathProcessor\InboundPathProcessorInterface
-   */
-  protected $processor;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setUp(): void {
-    parent::setUp();
-    new Settings(
-      [
-        'flysystem' => [
-          'testscheme' => [
-            'driver' => 'local',
-            'config' => ['root' => 'sites/default/files/flysystem'],
-          ],
-        ],
-      ]);
-    $this->processor = new LocalPathProcessor('testscheme');
-  }
-
-  /**
-   * @covers ::processInbound
-   * @covers ::__construct
-   */
-  public function testProcessInboundIgnoresInvalidPaths() {
-    $this->assertSame('beep', $this->processor->processInbound('beep', new Request()));
-  }
-
-  /**
-   * @covers ::processInbound
-   */
-  public function testProcessInboundHandlesImageStyles() {
-    $request = new Request();
-
-    $this->assertSame('/sites/default/files/flysystem/styles/testscheme/small', $this->processor->processInbound('/sites/default/files/flysystem/styles/testscheme/small/image.jpg', $request));
-    $this->assertSame($request->query->get('file'), 'image.jpg');
-
-    $this->assertSame('/sites/default/files/flysystem/styles/testscheme/small', $this->processor->processInbound('/sites/default/files/flysystem/styles/testscheme/small/dir/image.jpg', $request));
-    $this->assertSame($request->query->get('file'), 'dir/image.jpg');
-  }
-
-  /**
-   * @covers ::processInbound
-   */
-  public function testProcessInboundHandlesSystemDownload() {
-    $request = new Request();
-
-    $this->assertSame('/sites/default/files/flysystem', $this->processor->processInbound('/sites/default/files/flysystem/file.txt', $request));
-    $this->assertSame('file.txt', $request->query->get('file'));
-
-    $this->assertSame('/sites/default/files/flysystem', $this->processor->processInbound('/sites/default/files/flysystem/a/b/c/file.txt', $request));
-    $this->assertSame('a/b/c/file.txt', $request->query->get('file'));
-  }
-
-}
diff --git a/tests/src/Unit/Plugin/FlysystemPluginManagerTest.php b/tests/src/Unit/Plugin/FlysystemPluginManagerTest.php
deleted file mode 100644
index ef9f6834b7f55fbcae870ccfcf9f381ae03f29c6..0000000000000000000000000000000000000000
--- a/tests/src/Unit/Plugin/FlysystemPluginManagerTest.php
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\Plugin;
-
-use Drupal\Core\Cache\MemoryBackend;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\flysystem\Plugin\FlysystemPluginManager;
-use Drupal\Tests\UnitTestCase;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\Plugin\FlysystemPluginManager
- * @group flysystem
- */
-class FlysystemPluginManagerTest extends UnitTestCase {
-
-  /**
-   * @covers \Drupal\flysystem\Plugin\FlysystemPluginManager
-   */
-  public function test() {
-    $namespaces = new \ArrayObject();
-    $cache_backend = new MemoryBackend('bin');
-    $module_handle = $this->createMock(ModuleHandlerInterface::class);
-
-    $manager = new FlysystemPluginManager($namespaces, $cache_backend, $module_handle);
-    $this->assertSame('missing', $manager->getFallbackPluginId('beep'));
-    $this->assertIsArray($manager->getDefinitions());
-
-    // Test alterDefinitions().
-    $method = new \ReflectionMethod($manager, 'alterDefinitions');
-    $method->setAccessible(TRUE);
-
-    $definitions = [
-      'test1' => ['extensions' => []],
-      'test2' => ['extensions' => ['pdo']],
-      'test3' => ['extensions' => ['missing_extension']],
-    ];
-
-    $method->invokeArgs($manager, [&$definitions]);
-    $this->assertCount(2, $definitions);
-    $this->assertArrayHasKey('test1', $definitions);
-    $this->assertArrayHasKey('test2', $definitions);
-    $this->assertArrayNotHasKey('test3', $definitions);
-  }
-
-}
diff --git a/tests/src/Unit/Plugin/FlysystemUrlTraitTest.php b/tests/src/Unit/Plugin/FlysystemUrlTraitTest.php
deleted file mode 100644
index 1155d85d3b1c8f955ea148496b746418a7a5fd06..0000000000000000000000000000000000000000
--- a/tests/src/Unit/Plugin/FlysystemUrlTraitTest.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\Plugin;
-
-use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Drupal\Core\Routing\UrlGenerator;
-use Drupal\flysystem\Plugin\FlysystemUrlTrait;
-use Drupal\Tests\UnitTestCase;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\Plugin\FlysystemUrlTrait
- * @group flysystem
- */
-class FlysystemUrlTraitTest extends UnitTestCase {
-
-  /**
-   * @covers ::getExternalUrl
-   * @covers ::getScheme
-   * @covers ::getTarget
-   */
-  public function testGetExternalUrl() {
-    $trait = $this->getMockForTrait(FlysystemUrlTrait::class);
-
-    $url_generator = $this->prophesize(UrlGenerator::class);
-    $url_generator->generateFromRoute(
-      'flysystem.serve',
-      ['scheme' => 'testscheme', 'filepath' => 'dir/file.txt'],
-      ['absolute' => TRUE],
-      FALSE)
-      ->willReturn('download');
-
-    $container = new ContainerBuilder();
-    $container->set('url_generator', $url_generator->reveal());
-
-    \Drupal::setContainer($container);
-
-    $this->assertSame('download', $trait->getExternalUrl('testscheme://dir\file.txt'));
-  }
-
-}
diff --git a/tests/src/Unit/Plugin/ImageStyleGenerationTraitTest.php b/tests/src/Unit/Plugin/ImageStyleGenerationTraitTest.php
deleted file mode 100644
index dbe15db408e778a82392d0cb82185af496085b31..0000000000000000000000000000000000000000
--- a/tests/src/Unit/Plugin/ImageStyleGenerationTraitTest.php
+++ /dev/null
@@ -1,87 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\Plugin;
-
-use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Entity\EntityTypeRepositoryInterface;
-use Drupal\Core\Lock\LockBackendInterface;
-use Drupal\Core\Lock\NullLockBackend;
-use Drupal\flysystem\Plugin\ImageStyleGenerationTrait;
-use Drupal\image\Entity\ImageStyle;
-use Drupal\Tests\UnitTestCase;
-use org\bovigo\vfs\vfsStream;
-use Prophecy\Argument;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\Plugin\ImageStyleGenerationTrait
- * @group flysystem
- */
-class ImageStyleGenerationTraitTest extends UnitTestCase {
-
-  /**
-   * @covers ::generateImageStyle
-   */
-  public function testGenerateImageStyle() {
-    vfsStream::setup('flysystem');
-    touch('vfs://flysystem/foo.jpg');
-    mkdir('vfs://flysystem/styles/pass', 0777, TRUE);
-
-    $container = new ContainerBuilder();
-
-    $image_style = $this->prophesize(ImageStyle::class);
-    $image_style->buildUri('vfs://flysystem/foo.jpg')->willReturn('vfs://flysystem/styles/pass/foo.jpg');
-    $image_style->buildUri('vfs://flysystem/foo.jpg.png')->willReturn('vfs://flysystem/styles/pass/foo.jpg.png');
-    $image_style->id()->willReturn('pass');
-    $image_style->createDerivative('vfs://flysystem/foo.jpg', 'vfs://flysystem/styles/pass/foo.jpg')->willReturn(TRUE);
-    $image_style->createDerivative('vfs://flysystem/foo.jpg', 'vfs://flysystem/styles/pass/foo.jpg.png')->willReturn(TRUE);
-
-    $storage = $this->prophesize(EntityStorageInterface::class);
-    $storage->load('pass')->willReturn($image_style->reveal());
-    $storage->load('fail')->willReturn(FALSE);
-
-    $entity_type_manager = $this->prophesize(EntityTypeManagerInterface::class);
-    $entity_tyep_repository = $this->prophesize(EntityTypeRepositoryInterface::class);
-    $entity_tyep_repository->getEntityTypeFromClass(ImageStyle::class)->willReturn('image_style');
-    $entity_type_manager->getStorage('image_style')->willReturn($storage->reveal());
-
-    $container->set('entity_type.repository', $entity_tyep_repository->reveal());
-    $container->set('entity_type.manager', $entity_type_manager->reveal());
-    $container->set('lock', new NullLockBackend());
-
-    \Drupal::setContainer($container);
-
-    $trait = $this->getMockForTrait(ImageStyleGenerationTrait::class);
-
-    $method = (new \ReflectionMethod($trait, 'generateImageStyle'))->getClosure($trait);
-
-    // Test invlid paths.
-    $this->assertFalse($method('foo/bar'));
-    $this->assertFalse($method('styles/image_style/vfs'));
-
-    // Test invalid image style.
-    $this->assertFalse($method('styles/fail/vfs/flysystem/foo.jpg'));
-
-    // Test existing derivative.
-    touch('vfs://flysystem/styles/pass/foo.jpg');
-    $this->assertTrue($method('styles/pass/vfs/flysystem/foo.jpg'));
-    unlink('vfs://flysystem/styles/pass/foo.jpg');
-
-    // Basic passing.
-    $this->assertTrue($method('styles/pass/vfs/flysystem/foo.jpg'));
-    $this->assertTrue($method('styles/pass/vfs/flysystem/foo.jpg.png'));
-
-    // Test failed lock.
-    $fail_lock = $this->prophesize(LockBackendInterface::class);
-    $fail_lock->acquire(Argument::type('string'))->willReturn(FALSE);
-    $container->set('lock', $fail_lock->reveal());
-    $this->assertFalse($method('styles/pass/vfs/flysystem/foo.jpg'));
-    $container->set('lock', new NullLockBackend());
-
-    // Test missing source.
-    unlink('vfs://flysystem/foo.jpg');
-    $this->assertFalse($method('styles/pass/vfs/flysystem/foo.jpg.png'));
-  }
-
-}
diff --git a/tests/src/Unit/Routing/FlysystemRoutesTest.php b/tests/src/Unit/Routing/FlysystemRoutesTest.php
deleted file mode 100644
index ad9c6098a5eda230c1b1cf4b044ef0ccbe3b277d..0000000000000000000000000000000000000000
--- a/tests/src/Unit/Routing/FlysystemRoutesTest.php
+++ /dev/null
@@ -1,165 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit\Routing;
-
-use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\Site\Settings;
-use Drupal\Core\StreamWrapper\LocalStream;
-use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
-use Drupal\flysystem\FlysystemStreamWrapperManager;
-use Drupal\flysystem\Routing\FlysystemRoutes;
-use Drupal\Tests\UnitTestCase;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\Routing\FlysystemRoutes
- * @group flysystem
- */
-class FlysystemRoutesTest extends UnitTestCase {
-
-  /**
-   * Flysystem Factory.
-   *
-   * @var \Drupal\flysystem\FlysystemStreamWrapperManager
-   */
-  protected $factory;
-
-  /**
-   * Drupal ModuleHandler.
-   *
-   * @var \Drupal\Core\Extension\ModuleHandlerInterface
-   */
-  protected $moduleHandler;
-
-  /**
-   * Flysystem routing for files.
-   *
-   * @var \Drupal\flysystem\Routing\FlysystemRoutes
-   */
-  protected $router;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setUp(): void {
-    parent::setUp();
-    $container = new ContainerBuilder();
-
-    $stream_wrapper = $this->prophesize(LocalStream::class);
-    $stream_wrapper->getDirectoryPath()->willReturn('sites/default/files');
-
-    $stream_wrapper_manager = $this->prophesize(StreamWrapperManagerInterface::class);
-    $stream_wrapper_manager->getViaScheme('public')->willReturn($stream_wrapper->reveal());
-
-    $this->moduleHandler = $this->prophesize(ModuleHandlerInterface::class);
-
-    $factory = $this->prophesize(FlysystemStreamWrapperManager::class);
-    $factory->getSchemes()->willReturn(['test']);
-
-    $container->set('flysystem_factory', $factory->reveal());
-    $container->set('stream_wrapper_manager', $stream_wrapper_manager->reveal());
-    $container->set('module_handler', $this->moduleHandler->reveal());
-
-    $this->router = FlysystemRoutes::create($container);
-  }
-
-  /**
-   * @covers ::__construct
-   * @covers ::create
-   * @covers ::routes
-   */
-  public function testInvalidSettingsAreSkipped() {
-    new Settings([
-      'flysystem' => [
-        'invalid' => ['driver' => 'local'],
-        'test' => ['driver' => 'local'],
-      ],
-    ]);
-
-    $this->assertSame([], $this->router->routes());
-  }
-
-  /**
-   * @covers ::routes
-   */
-  public function testInvalidDriversAreSkipped() {
-    new Settings(['flysystem' => ['test' => ['driver' => 'ftp']]]);
-
-    $this->assertSame([], $this->router->routes());
-  }
-
-  /**
-   * @covers ::routes
-   */
-  public function testDriversNotPublicAreSkipped() {
-    new Settings(['flysystem' => ['test' => ['driver' => 'local']]]);
-
-    $this->assertSame([], $this->router->routes());
-  }
-
-  /**
-   * @covers ::routes
-   */
-  public function testLocalPathSameAsPublicIsSkipped() {
-    new Settings([
-      'flysystem' => [
-        'test' => [
-          'driver' => 'local',
-          'public' => TRUE,
-          'config' => [
-            'public' => TRUE,
-            'root' => 'sites/default/files',
-          ],
-        ],
-      ],
-    ]);
-
-    $this->assertSame([], $this->router->routes());
-  }
-
-  /**
-   * @covers ::routes
-   */
-  public function testValidRoutesReturned() {
-    new Settings([
-      'flysystem' => [
-        'test' => [
-          'driver' => 'local',
-          'public' => TRUE,
-          'config' => [
-            'public' => TRUE,
-            'root' => 'sites/default/files/flysystem',
-          ],
-        ],
-      ],
-    ]);
-
-    $routes = $this->router->routes();
-    $this->assertCount(1, $routes);
-    $this->assertTrue(isset($routes['flysystem.test.serve']));
-  }
-
-  /**
-   * @covers ::routes
-   */
-  public function testValidRoutesReturnedWithImageModule() {
-    new Settings([
-      'flysystem' => [
-        'test' => [
-          'driver' => 'local',
-          'public' => TRUE,
-          'config' => [
-            'public' => TRUE,
-            'root' => 'sites/default/files/flysystem',
-          ],
-        ],
-      ],
-    ]);
-
-    $this->moduleHandler->moduleExists('image')->willReturn(TRUE);
-    $routes = $this->router->routes();
-    $this->assertCount(3, $routes);
-    $this->assertTrue(isset($routes['flysystem.image_style']));
-  }
-
-}
diff --git a/tests/src/Unit/SerializationStopperTraitTest.php b/tests/src/Unit/SerializationStopperTraitTest.php
deleted file mode 100644
index 71a242a96fa4f7fcfc8c20d4afada93532fe902f..0000000000000000000000000000000000000000
--- a/tests/src/Unit/SerializationStopperTraitTest.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-
-namespace Drupal\Tests\flysystem\Unit;
-
-use Drupal\flysystem\SerializationStopperTrait;
-use Drupal\Tests\UnitTestCase;
-
-/**
- * @coversDefaultClass \Drupal\flysystem\SerializationStopperTrait
- * @group flysystem
- */
-class SerializationStopperTraitTest extends UnitTestCase {
-
-  /**
-   * @covers ::__sleep
-   */
-  public function test() {
-    $this->expectException(\LogicException::class);
-    $this->expectExceptionMessage('can not be serialized.');
-    $trait = $this->getMockForTrait(SerializationStopperTrait::class);
-    serialize($trait);
-  }
-
-}