Skip to content

Commit

Permalink
feat: add ToString methods to simplify debugging (#335)
Browse files Browse the repository at this point in the history
Add `ToString` methods and direct `Container` property to the
`MockFileSystem` to simplify debugging.

---------

Co-authored-by: Valentin Breuß <v.breuss@tig.at>
  • Loading branch information
vbreuss and vbtig authored Jul 23, 2023
1 parent 9c08f7e commit 64ced94
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Testably.Abstractions.Helpers;

namespace Testably.Abstractions.Testing.Helpers;
Expand Down Expand Up @@ -44,4 +45,16 @@ internal void CopyMetadataTo(IFileSystemExtensibility target)
}
}
}

/// <inheritdoc cref="object.ToString()" />
public override string ToString()
{
if (_metadata.Count == 0)
{
return "[]";
}

return
$"[{string.Join(", ", _metadata.Select(x => $"{x.Key}: {x.Value}"))}]";
}
}
15 changes: 15 additions & 0 deletions Source/Testably.Abstractions.Testing/MockFileSystem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Linq;
using Testably.Abstractions.Testing.FileSystem;
using Testably.Abstractions.Testing.Storage;

Expand Down Expand Up @@ -40,6 +42,15 @@ public sealed class MockFileSystem : IFileSystem
/// </summary>
internal IStorage Storage => _storage;

/// <summary>
/// The registered containers in the in-Memory <see cref="Storage" />.
/// </summary>
internal IReadOnlyList<IStorageContainer> Containers
=> _storage.Containers
.OrderBy(x => x.Key.FullPath)
.Select(x => x.Value)
.ToList();

private readonly DirectoryMock _directoryMock;
private readonly FileMock _fileMock;
private readonly PathMock _pathMock;
Expand Down Expand Up @@ -110,6 +121,10 @@ public IPath Path

#endregion

/// <inheritdoc cref="object.ToString()" />
public override string ToString()
=> $"MockFileSystem (directories: {_storage.Containers.Count(x => x.Value.Type == FileSystemTypes.Directory)}, files: {_storage.Containers.Count(x => x.Value.Type == FileSystemTypes.File)})";

/// <summary>
/// Implements a custom access control (ACL) mechanism.
/// <para />
Expand Down
7 changes: 6 additions & 1 deletion Source/Testably.Abstractions.Testing/MockRandomSystem.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Testably.Abstractions.RandomSystem;
using System;
using Testably.Abstractions.RandomSystem;
using Testably.Abstractions.Testing.RandomSystem;

namespace Testably.Abstractions.Testing;
Expand Down Expand Up @@ -46,4 +47,8 @@ public IRandomFactory Random
=> _randomFactoryMock;

#endregion

/// <inheritdoc cref="object.ToString()" />
public override string ToString()
=> "MockRandomSystem";
}
4 changes: 4 additions & 0 deletions Source/Testably.Abstractions.Testing/MockTimeSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ public ITimerFactory Timer

#endregion

/// <inheritdoc cref="object.ToString()" />
public override string ToString()
=> $"MockTimeSystem (now: {DateTime.UtcNow}Z)";

/// <summary>
/// Specifies the <see cref="ITimerStrategy" /> to use when dealing with timers.
/// </summary>
Expand Down
20 changes: 20 additions & 0 deletions Source/Testably.Abstractions.Testing/Storage/InMemoryContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,22 @@ public void WriteBytes(byte[] bytes)

#endregion

/// <inheritdoc cref="object.ToString()" />
public override string ToString()
{
if (Type == FileSystemTypes.Directory)
{
return $"{_location.FullPath}: Directory";
}

if (Type == FileSystemTypes.File)
{
return $"{_location.FullPath}: File ({_bytes.Length} bytes)";
}

return $"{_location.FullPath}: Unknown Container";
}

/// <summary>
/// Create a new directory on the <paramref name="location" />.
/// </summary>
Expand Down Expand Up @@ -318,6 +334,10 @@ public void Set(DateTime time, DateTimeKind kind)
}

#endregion

/// <inheritdoc cref="object.ToString()" />
public override string ToString()
=> _time.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ssZ");
}

private sealed class FileHandle : IStorageAccessHandle
Expand Down
62 changes: 31 additions & 31 deletions Source/Testably.Abstractions.Testing/Storage/InMemoryStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ namespace Testably.Abstractions.Testing.Storage;
/// </summary>
internal sealed class InMemoryStorage : IStorage
{
private readonly ConcurrentDictionary<IStorageLocation, IStorageContainer>
_containers = new();
internal readonly ConcurrentDictionary<IStorageLocation, IStorageContainer>
Containers = new();

private readonly ConcurrentDictionary<string, IStorageDrive> _drives =
new(StringComparer.OrdinalIgnoreCase);
Expand Down Expand Up @@ -45,7 +45,7 @@ public InMemoryStorage(MockFileSystem fileSystem)
{
ThrowIfParentDoesNotExist(destination, _ => ExceptionFactory.DirectoryNotFound());

if (!_containers.TryGetValue(source,
if (!Containers.TryGetValue(source,
out IStorageContainer? sourceContainer))
{
return null;
Expand All @@ -59,15 +59,15 @@ public InMemoryStorage(MockFileSystem fileSystem)
using (_ = sourceContainer.RequestAccess(FileAccess.ReadWrite, FileShare.None))
{
if (overwrite &&
_containers.TryRemove(destination,
Containers.TryRemove(destination,
out IStorageContainer? existingContainer))
{
existingContainer.ClearBytes();
}

IStorageContainer copiedContainer =
InMemoryContainer.NewFile(destination, _fileSystem);
if (_containers.TryAdd(destination, copiedContainer))
if (Containers.TryAdd(destination, copiedContainer))
{
copiedContainer.WriteBytes(sourceContainer.GetBytes().ToArray());
Execute.OnMac(
Expand Down Expand Up @@ -99,11 +99,11 @@ public InMemoryStorage(MockFileSystem fileSystem)
/// <inheritdoc cref="IStorage.DeleteContainer(IStorageLocation, bool)" />
public bool DeleteContainer(IStorageLocation location, bool recursive = false)
{
if (!_containers.TryGetValue(location, out IStorageContainer? container))
if (!Containers.TryGetValue(location, out IStorageContainer? container))
{
IStorageLocation? parentLocation = location.GetParent();
if (parentLocation != null &&
!_containers.TryGetValue(parentLocation, out _))
!Containers.TryGetValue(parentLocation, out _))
{
throw ExceptionFactory.DirectoryNotFound(parentLocation.FullPath);
}
Expand Down Expand Up @@ -140,7 +140,7 @@ public bool DeleteContainer(IStorageLocation location, bool recursive = false)
using (container.RequestAccess(FileAccess.Write, FileShare.ReadWrite,
deleteAccess: true))
{
if (_containers.TryRemove(location, out IStorageContainer? removed))
if (Containers.TryRemove(location, out IStorageContainer? removed))
{
removed.ClearBytes();
_fileSystem.ChangeHandler.NotifyCompletedChange(fileSystemChange);
Expand All @@ -160,7 +160,7 @@ public IEnumerable<IStorageLocation> EnumerateLocations(
EnumerationOptions? enumerationOptions = null)
{
ValidateExpression(searchPattern);
if (!_containers.ContainsKey(location))
if (!Containers.ContainsKey(location))
{
throw ExceptionFactory.DirectoryNotFound(location.FullPath);
}
Expand All @@ -177,7 +177,7 @@ public IEnumerable<IStorageLocation> EnumerateLocations(
fullPath += _fileSystem.Path.DirectorySeparatorChar;
}

foreach (KeyValuePair<IStorageLocation, IStorageContainer> item in _containers
foreach (KeyValuePair<IStorageLocation, IStorageContainer> item in Containers
.Where(x => x.Key.FullPath.StartsWith(fullPath,
InMemoryLocation.StringComparisonMode) &&
!x.Key.Equals(location)))
Expand Down Expand Up @@ -215,7 +215,7 @@ public IEnumerable<IStorageLocation> EnumerateLocations(
return null;
}

if (_containers.TryGetValue(location, out IStorageContainer? container))
if (Containers.TryGetValue(location, out IStorageContainer? container))
{
return container;
}
Expand Down Expand Up @@ -287,7 +287,7 @@ public IStorageContainer GetOrCreateContainer(
IFileSystemExtensibility? fileSystemExtensibility = null)
{
ChangeDescription? fileSystemChange = null;
IStorageContainer container = _containers.GetOrAdd(location,
IStorageContainer container = Containers.GetOrAdd(location,
loc =>
{
IStorageContainer container =
Expand All @@ -302,7 +302,7 @@ public IStorageContainer GetOrCreateContainer(
{
IStorageLocation? parentLocation = loc.GetParent();
if (parentLocation is { IsRooted: false } &&
!_containers.ContainsKey(parentLocation))
!Containers.ContainsKey(parentLocation))
{
throw ExceptionFactory.DirectoryNotFound(loc.FullPath);
}
Expand Down Expand Up @@ -359,13 +359,13 @@ public IStorageContainer GetOrCreateContainer(
() => ExceptionFactory.DirectoryNotFound(location.FullPath),
() => ExceptionFactory.FileNotFound(location.FullPath)));

if (!_containers.TryGetValue(source,
if (!Containers.TryGetValue(source,
out IStorageContainer? sourceContainer))
{
return null;
}

if (!_containers.TryGetValue(destination,
if (!Containers.TryGetValue(destination,
out IStorageContainer? destinationContainer))
{
return null;
Expand All @@ -383,22 +383,22 @@ public IStorageContainer GetOrCreateContainer(
using (_ = destinationContainer.RequestAccess(FileAccess.ReadWrite,
FileShare.None, ignoreMetadataErrors: ignoreMetadataErrors))
{
if (_containers.TryRemove(destination,
if (Containers.TryRemove(destination,
out IStorageContainer? existingDestinationContainer))
{
int destinationBytesLength =
existingDestinationContainer.GetBytes().Length;
destination.Drive?.ChangeUsedBytes(-1 * destinationBytesLength);
if (backup != null &&
_containers.TryAdd(backup, existingDestinationContainer))
Containers.TryAdd(backup, existingDestinationContainer))
{
Execute.OnWindowsIf(sourceContainer.Type == FileSystemTypes.File,
() => existingDestinationContainer.Attributes |=
FileAttributes.Archive);
backup.Drive?.ChangeUsedBytes(destinationBytesLength);
}

if (_containers.TryRemove(source,
if (Containers.TryRemove(source,
out IStorageContainer? existingSourceContainer))
{
int sourceBytesLength = existingSourceContainer.GetBytes().Length;
Expand All @@ -414,7 +414,7 @@ public IStorageContainer GetOrCreateContainer(
DateTimeKind.Utc),
DateTimeKind.Utc);
});
_containers.TryAdd(destination, existingSourceContainer);
Containers.TryAdd(destination, existingSourceContainer);
return destination;
}
}
Expand All @@ -429,13 +429,13 @@ public IStorageContainer GetOrCreateContainer(
public IStorageLocation? ResolveLinkTarget(IStorageLocation location,
bool returnFinalTarget = false)
{
if (_containers.TryGetValue(location,
if (Containers.TryGetValue(location,
out IStorageContainer? initialContainer) &&
initialContainer.LinkTarget != null)
{
IStorageLocation? nextLocation =
_fileSystem.Storage.GetLocation(initialContainer.LinkTarget);
if (_containers.TryGetValue(nextLocation,
if (Containers.TryGetValue(nextLocation,
out IStorageContainer? container))
{
if (returnFinalTarget)
Expand All @@ -462,14 +462,14 @@ public bool TryAddContainer(
{
IStorageLocation? parentLocation = location.GetParent();
if (parentLocation is { IsRooted: false } &&
!_containers.ContainsKey(parentLocation))
!Containers.ContainsKey(parentLocation))
{
throw ExceptionFactory.DirectoryNotFound(location.FullPath);
}

ChangeDescription? fileSystemChange = null;

container = _containers.GetOrAdd(
container = Containers.GetOrAdd(
location,
_ =>
{
Expand Down Expand Up @@ -535,7 +535,7 @@ private void CreateParents(MockFileSystem fileSystem, IStorageLocation location)
ChangeDescription? fileSystemChange = null;
IStorageLocation parentLocation =
_fileSystem.Storage.GetLocation(parentPath);
_ = _containers.AddOrUpdate(
_ = Containers.AddOrUpdate(
parentLocation,
loc =>
{
Expand Down Expand Up @@ -571,7 +571,7 @@ private void CreateParents(MockFileSystem fileSystem, IStorageLocation location)
FileSystemTypes? sourceType,
List<Rollback>? rollbacks = null)
{
if (!_containers.TryGetValue(source,
if (!Containers.TryGetValue(source,
out IStorageContainer? container))
{
return null;
Expand Down Expand Up @@ -615,16 +615,16 @@ private void CreateParents(MockFileSystem fileSystem, IStorageLocation location)
NotifyFilters.FileName,
destination,
source);
if (_containers.TryRemove(source, out IStorageContainer? sourceContainer))
if (Containers.TryRemove(source, out IStorageContainer? sourceContainer))
{
if (overwrite &&
_containers.TryRemove(destination,
Containers.TryRemove(destination,
out IStorageContainer? existingContainer))
{
existingContainer.ClearBytes();
}

if (_containers.TryAdd(destination, sourceContainer))
if (Containers.TryAdd(destination, sourceContainer))
{
int bytesLength = sourceContainer.GetBytes().Length;
source.Drive?.ChangeUsedBytes(-1 * bytesLength);
Expand All @@ -638,7 +638,7 @@ private void CreateParents(MockFileSystem fileSystem, IStorageLocation location)
return destination;
}

_containers.TryAdd(source, sourceContainer);
Containers.TryAdd(source, sourceContainer);
throw ExceptionFactory.CannotCreateFileWhenAlreadyExists(
sourceType == FileSystemTypes.Directory
? -2147024891
Expand All @@ -665,7 +665,7 @@ private void CreateParents(MockFileSystem fileSystem, IStorageLocation location)
}

nextLocation = _fileSystem.Storage.GetLocation(container.LinkTarget);
if (!_containers.TryGetValue(nextLocation,
if (!Containers.TryGetValue(nextLocation,
out IStorageContainer? nextContainer))
{
return nextLocation;
Expand All @@ -692,7 +692,7 @@ private void ThrowIfParentDoesNotExist(IStorageLocation location,
if (parentLocation != null &&
_fileSystem.Path.GetPathRoot(parentLocation.FullPath) !=
parentLocation.FullPath &&
!_containers.TryGetValue(parentLocation, out _))
!Containers.TryGetValue(parentLocation, out _))
{
throw exceptionCallback(parentLocation);
}
Expand Down

0 comments on commit 64ced94

Please sign in to comment.