feat(configmanager): add IFileSystem abstraction

Add file system abstraction to enable testability for file operations.
- IFileSystem interface with common file operations
- FileSystem implementation wrapping System.IO
- Unit tests for FileExists functionality
This commit is contained in:
Joseph Doherty
2026-01-19 17:33:39 -05:00
parent 54d4fd0eb6
commit c055bc6c78
3 changed files with 99 additions and 0 deletions
@@ -0,0 +1,40 @@
namespace JdeScoping.ConfigManager.Services;
/// <summary>
/// Real file system implementation.
/// </summary>
public class FileSystem : IFileSystem
{
public bool FileExists(string path) => File.Exists(path);
public bool DirectoryExists(string path) => Directory.Exists(path);
public async Task<string> ReadAllTextAsync(string path, CancellationToken ct = default)
=> await File.ReadAllTextAsync(path, ct);
public async Task WriteAllTextAsync(string path, string content, CancellationToken ct = default)
=> await File.WriteAllTextAsync(path, content, ct);
public Task<string[]> GetFilesAsync(string directory, string pattern, CancellationToken ct = default)
=> Task.FromResult(Directory.GetFiles(directory, pattern));
public async Task CopyFileAsync(string source, string destination, CancellationToken ct = default)
{
var content = await File.ReadAllBytesAsync(source, ct);
await File.WriteAllBytesAsync(destination, content, ct);
}
public Task DeleteFileAsync(string path, CancellationToken ct = default)
{
File.Delete(path);
return Task.CompletedTask;
}
public string GetDirectoryName(string path) => Path.GetDirectoryName(path) ?? string.Empty;
public string GetFileName(string path) => Path.GetFileName(path);
public string GetFileNameWithoutExtension(string path) => Path.GetFileNameWithoutExtension(path);
public string Combine(params string[] paths) => Path.Combine(paths);
}
@@ -0,0 +1,19 @@
namespace JdeScoping.ConfigManager.Services;
/// <summary>
/// Abstraction for file system operations to enable testing.
/// </summary>
public interface IFileSystem
{
bool FileExists(string path);
bool DirectoryExists(string path);
Task<string> ReadAllTextAsync(string path, CancellationToken ct = default);
Task WriteAllTextAsync(string path, string content, CancellationToken ct = default);
Task<string[]> GetFilesAsync(string directory, string pattern, CancellationToken ct = default);
Task CopyFileAsync(string source, string destination, CancellationToken ct = default);
Task DeleteFileAsync(string path, CancellationToken ct = default);
string GetDirectoryName(string path);
string GetFileName(string path);
string GetFileNameWithoutExtension(string path);
string Combine(params string[] paths);
}