using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using VBASync.Model;
namespace VBASync.Tests.Mocks
{
internal class FakeSystemOperations : ISystemOperations
{
private readonly ConcurrentDictionary<string, byte[]> _files
= new ConcurrentDictionary<string, byte[]>(StringComparer.OrdinalIgnoreCase);
public virtual bool IsWindows => false;
public virtual Stream CreateNewFile(string path)
{
if (!_files.TryAdd(path, new byte[0]))
{
throw new ApplicationException($"Tried to create new file at '{path}', which already exists!");
}
return new MemoryStreamWithFlushCallback(s => _files[path] = s.ToArray());
}
public virtual void DirectoryCreateDirectory(string path)
{
}
public virtual void DirectoryDelete(string path, bool recursive)
{
}
public virtual IEnumerable<string> DirectoryGetFiles(string folderPath)
=> DirectoryGetFiles(folderPath, "*", false);
public virtual IEnumerable<string> DirectoryGetFiles(string folderPath, string mask)
=> DirectoryGetFiles(folderPath, mask, false);
public virtual IEnumerable<string> DirectoryGetFiles(string folderPath, string mask, bool recurse)
{
if (!folderPath.EndsWith("/"))
{
folderPath += "/";
}
foreach (var s in _files.Keys)
{
if (InRightDirectory(s) && FitsMask(PathGetFileName(s), mask))
{
yield return s;
}
}
bool FitsMask(string fileName, string fileMask)
{
if (fileMask == "*")
{
return true;
}
return new Regex("^" + fileMask.Replace(".", "[.]").Replace("*", ".*").Replace("?", ".")
+ "$", RegexOptions.IgnoreCase).IsMatch(fileName);
}
bool InRightDirectory(string filePath)
{
if (!filePath.StartsWith(folderPath))
{
return false;
}
if (recurse)
{
return true;
}
return filePath.LastIndexOf('/') < folderPath.Length;
}
}
public virtual void FileCopy(string src, string dest) => FileCopy(src, dest, false);
public virtual void FileCopy(string src, string dest, bool overwrite)
{
if (overwrite)
{
_files[dest] = _files[src];
}
else if (!_files.TryAdd(dest, _files[src]))
{
throw new ApplicationException($"Tried to copy to a location '{dest}' that already exists!");
}
}
public virtual void FileDelete(string path)
{
if (!_files.TryRemove(path, out ))
{
throw new ApplicationException($"Tried to remove '{path}', which doesn't exist!");
}
}
public virtual bool FileExists(string path) => _files.ContainsKey(path);
public virtual byte[] FileReadAllBytes(string path) => _files[path];
public virtual string FileReadAllText(string path, Encoding encoding)
=> encoding.GetString(FileReadAllBytes(path));
public virtual void FileWriteAllBytes(string path, byte[] bytes) => _files[path] = bytes;
public virtual void FileWriteAllLines(string path, IEnumerable<string> lines, Encoding encoding)
=> FileWriteAllText(path, string.Join("\n", lines), encoding);
public virtual void FileWriteAllText(string path, string text, Encoding encoding)
=> FileWriteAllBytes(path, encoding.GetBytes(text));
public virtual Stream OpenFileForRead(string path) => new MemoryStream(_files[path]);
public virtual Stream OpenFileForWrite(string path)
=> new MemoryStreamWithFlushCallback(FileReadAllBytes(path), s => _files[path] = s.ToArray());
public string PathCombine(params string[] parts)
{
var sb = new StringBuilder();
for (var i = 0; i < parts.Length; ++i)
{
if (i > 0)
{
sb.Append('/');
}
if (i < parts.Length - 1)
{
sb.Append(parts[i].TrimEnd('/'));
}
else
{
sb.Append(parts[i]);
}
}
return sb.ToString();
}
public string PathGetDirectoryName(string path)
{
if (string.IsNullOrEmpty(path))
{
return null;
}
if (path == "/")
{
return "/";
}
if (path.EndsWith("/"))
{
path = path.Substring(0, path.Length - 1);
}
var idx = path.LastIndexOf('/');
if (idx == 0)
{
return "/";
}
if (idx < 0)
{
return "";
}
return path.Substring(0, idx);
}
public virtual string PathGetExtension(string path)
{
var idx = path.LastIndexOf('.');
return idx >= 0 ? path.Substring(idx) : "";
}
public virtual string PathGetFileName(string path)
{
var idx = path.LastIndexOf('/');
return idx >= 0 ? path.Substring(idx + 1) : path;
}
public virtual string PathGetFileNameWithoutExtension(string path)
{
var ext = PathGetExtension(path);
var fn = PathGetFileName(path);
return fn.Substring(0, fn.Length - ext.Length);
}
public virtual string PathGetTempPath() => "/tmp/";
public virtual void ProcessStartAndWaitForExit(ProcessStartInfo psi)
{
}
private class MemoryStreamWithFlushCallback : MemoryStream
{
private readonly Action<MemoryStream> _flushCallback;
internal MemoryStreamWithFlushCallback(Action<MemoryStream> flushCallback)
{
_flushCallback = flushCallback;
}
internal MemoryStreamWithFlushCallback(byte[] buffer, Action<MemoryStream> flushCallback) : this(flushCallback)
{
Write(buffer, 0, buffer.Length);
base.Flush();
}
public override void Flush()
{
base.Flush();
_flushCallback(this);
}
}
}
internal class WindowsFakeSystemOperations : FakeSystemOperations
{
public override bool IsWindows => true;
}
}