Code/FileIO/MockFileIOProvider.cs
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace SandbankDatabase;
internal sealed class MockFileIOProvider : IFileIOProvider
{
private MockDirectory _fileSystem = new();
public string ReadAllText( string file )
{
var data = _fileSystem.GetFile( file )?.Contents;
Logging.Info( $"reading text from file {file} (read {data?.Length ?? 0} characters)" );
return data;
}
public void WriteAllText( string file, string text )
{
Logging.Info( $"writing to file {file}" );
_fileSystem.CreateFileAt( file, text );
}
public void CreateDirectory( string directory )
{
Logging.Info( $"creating directory {directory}" );
_fileSystem.CreateDirectoryAt( directory );
}
/// <summary>
/// Don't know how a directory deletion could ever not be recursive but that's
/// how s&box has it.
/// </summary>
public void DeleteDirectory( string directory )
{
Logging.Info( $"deleting directory {directory}" );
_fileSystem.DeleteDirectoryAt( directory );
}
public bool DirectoryExists( string directory )
{
var result = _fileSystem.GetDirectory( directory ) != null;
Logging.Info( $"checking if directory {directory} exists ({ (result ? "it does" : "it doesn't" ) })" );
return result;
}
public IEnumerable<string> FindFile( string folder, string pattern = "*", bool recursive = false )
{
if ( recursive )
throw new SandbankException( "not supported" );
if ( pattern != "*" )
throw new SandbankException( "not supported" );
var result = _fileSystem.GetFilesInDirectory( folder )
.Where( x => x.FileType == MockFileType.File );
Logging.Info( $"finding files in directory {folder} (found {result.Count()})" );
return result.Select( x => x.Name );
}
public IEnumerable<string> FindDirectory( string folder, string pattern = "*", bool recursive = false )
{
if ( recursive )
throw new SandbankException( "not supported" );
if ( pattern != "*" )
throw new SandbankException( "not supported" );
var result = _fileSystem.GetFilesInDirectory( folder )
.Where( x => x.FileType == MockFileType.Directory );
Logging.Info( $"finding directories in directory {folder} (found {result.Count()})" );
return result.Select( x => x.Name );
}
public void DeleteFile( string file )
{
Logging.Info( $"deleting file {file}" );
_fileSystem.DeleteFileAt( file );
}
class MockFileBase
{
public string Name;
public MockFileType FileType;
}
class MockFile : MockFileBase
{
public string Contents;
}
class MockDirectory : MockFileBase
{
ConcurrentDictionary<string, MockFileBase> Files = new();
public void DeleteFileAt( string path )
{
var directoryPath = path.Split( '/' ).Where( x => x.Count() > 0 ).ToList();
var fileName = directoryPath[directoryPath.Count - 1];
directoryPath.RemoveAt( directoryPath.Count - 1 );
var directory = GetDirectory( string.Join('/', directoryPath ) );
if ( directory == null )
return;
if ( !directory.Files.ContainsKey( fileName ) )
return;
var file = directory.Files[fileName];
if ( file.FileType != MockFileType.File )
return;
directory.Files.Remove( fileName, out _ );
}
public void DeleteDirectoryAt( string path )
{
var directoryPath = path.Split( '/' ).Where( x => x.Count() > 0 ).ToList();
var directoryName = directoryPath[directoryPath.Count - 1];
directoryPath.RemoveAt( directoryPath.Count - 1 );
var directory = GetDirectory( string.Join( '/', directoryPath ) );
if ( directory == null )
return;
if ( !directory.Files.ContainsKey( directoryName ) )
return;
var directoryToDelete = directory.Files[directoryName];
if ( directoryToDelete.FileType != MockFileType.Directory )
return;
directory.Files.Remove( directoryName, out _ );
}
public void CreateDirectoryAt( string path )
{
if ( GetDirectory( path ) != null )
return;
var parts = path.Split( '/' ).Where( x => x.Count() > 0 ).ToList();
string parentPath = "";
// If there is only one part then we just create the directory on ourselves.
if ( parts.Count == 1 )
{
Files[parts[0]] = new MockDirectory()
{
FileType = MockFileType.Directory,
Name = parts[0],
};
return;
}
var folderName = parts[parts.Count - 1];
// parts now only contains the parent directories.
parts.RemoveAt( parts.Count - 1 );
// Make sure parent paths exist.
// Don't do the last path because that isn't a parent path.
foreach ( var part in parts )
{
parentPath += part + "/";
if ( GetDirectory( parentPath ) == null )
CreateDirectoryAt( parentPath );
}
var directory = GetDirectory( parentPath );
directory.Files[folderName] = new MockDirectory()
{
FileType = MockFileType.Directory,
Name = folderName,
};
}
public void CreateFileAt( string path, string contents )
{
var currentFile = GetFile( path );
if ( currentFile != null )
{
currentFile.Contents = contents;
return;
}
var parts = path.Split( '/' ).Where( x => x.Count() > 0 ).ToList();
var fileName = parts[parts.Count - 1];
parts.RemoveAt( parts.Count - 1 );
var containingFolder = string.Join( '/', parts );
var directory = GetDirectory( containingFolder );
if (directory == null)
{
CreateDirectoryAt( containingFolder );
directory = GetDirectory( containingFolder );
}
directory.Files[fileName] = new MockFile()
{
FileType = MockFileType.File,
Name = fileName,
Contents = contents
};
}
public MockDirectory GetDirectory( string directory )
{
if ( directory.Count() == 0 || directory == "/" )
return this;
var parts = directory.Split( '/' ).Where(x => x.Count() > 0);
var current = this;
foreach ( var part in parts )
{
if ( !current.Files.ContainsKey( part ) )
return null;
var next = current.Files[part];
if ( next.FileType != MockFileType.Directory )
return null;
current = (MockDirectory)next;
}
return current;
}
public MockFile GetFile( string path )
{
var parts = path.Split( '/' ).Where( x => x.Count() > 0 ).ToList();
var fileName = parts.Last();
parts.RemoveAt( parts.Count - 1 );
var directory = GetDirectory( string.Join( "/", parts ) );
if ( directory == null )
return null;
if ( !directory.Files.ContainsKey( fileName ) )
return null;
var file = directory.Files[fileName];
if ( file.FileType != MockFileType.File )
return null;
return (MockFile)file;
}
public List<MockFileBase> GetFilesInDirectory( string directory )
{
var dir = GetDirectory( directory );
return dir != null ?
dir.Files.Select( x => x.Value).ToList()
: new List<MockFileBase>();
}
}
private enum MockFileType
{
File,
Directory
}
}