From c113a1ec55f09a979db4bfc18ca5b08dc03ee265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Sun, 23 Jul 2023 15:36:57 +0200 Subject: [PATCH 1/2] Add `ToString` methods to simplify debugging --- .../Helpers/FileSystemExtensibility.cs | 13 ++++ .../MockFileSystem.cs | 12 ++++ .../MockRandomSystem.cs | 7 ++- .../MockTimeSystem.cs | 4 ++ .../Storage/InMemoryContainer.cs | 20 ++++++ .../Storage/InMemoryStorage.cs | 62 +++++++++---------- 6 files changed, 86 insertions(+), 32 deletions(-) diff --git a/Source/Testably.Abstractions.Testing/Helpers/FileSystemExtensibility.cs b/Source/Testably.Abstractions.Testing/Helpers/FileSystemExtensibility.cs index 1b86d139e..c96f307ad 100644 --- a/Source/Testably.Abstractions.Testing/Helpers/FileSystemExtensibility.cs +++ b/Source/Testably.Abstractions.Testing/Helpers/FileSystemExtensibility.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Linq; using Testably.Abstractions.Helpers; namespace Testably.Abstractions.Testing.Helpers; @@ -44,4 +45,16 @@ internal void CopyMetadataTo(IFileSystemExtensibility target) } } } + + /// + public override string ToString() + { + if (_metadata.Count == 0) + { + return "[]"; + } + + return + $"[{string.Join(", ", _metadata.Select(x => $"{x.Key}: {x.Value}"))}]"; + } } diff --git a/Source/Testably.Abstractions.Testing/MockFileSystem.cs b/Source/Testably.Abstractions.Testing/MockFileSystem.cs index 00c6e5cf3..635a41d21 100644 --- a/Source/Testably.Abstractions.Testing/MockFileSystem.cs +++ b/Source/Testably.Abstractions.Testing/MockFileSystem.cs @@ -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; @@ -40,6 +42,12 @@ public sealed class MockFileSystem : IFileSystem /// internal IStorage Storage => _storage; + /// + /// The registered containers in the in-Memory . + /// + internal IReadOnlyList 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; @@ -110,6 +118,10 @@ public IPath Path #endregion + /// + 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)})"; + /// /// Implements a custom access control (ACL) mechanism. /// diff --git a/Source/Testably.Abstractions.Testing/MockRandomSystem.cs b/Source/Testably.Abstractions.Testing/MockRandomSystem.cs index a6337988a..739ef27d1 100644 --- a/Source/Testably.Abstractions.Testing/MockRandomSystem.cs +++ b/Source/Testably.Abstractions.Testing/MockRandomSystem.cs @@ -1,4 +1,5 @@ -using Testably.Abstractions.RandomSystem; +using System; +using Testably.Abstractions.RandomSystem; using Testably.Abstractions.Testing.RandomSystem; namespace Testably.Abstractions.Testing; @@ -46,4 +47,8 @@ public IRandomFactory Random => _randomFactoryMock; #endregion + + /// + public override string ToString() + => "MockRandomSystem"; } diff --git a/Source/Testably.Abstractions.Testing/MockTimeSystem.cs b/Source/Testably.Abstractions.Testing/MockTimeSystem.cs index c4fbb821e..146a52f73 100644 --- a/Source/Testably.Abstractions.Testing/MockTimeSystem.cs +++ b/Source/Testably.Abstractions.Testing/MockTimeSystem.cs @@ -80,6 +80,10 @@ public ITimerFactory Timer #endregion + /// + public override string ToString() + => $"MockTimeSystem (now: {DateTime.UtcNow}Z)"; + /// /// Specifies the to use when dealing with timers. /// diff --git a/Source/Testably.Abstractions.Testing/Storage/InMemoryContainer.cs b/Source/Testably.Abstractions.Testing/Storage/InMemoryContainer.cs index b4e81f03a..a3144cf71 100644 --- a/Source/Testably.Abstractions.Testing/Storage/InMemoryContainer.cs +++ b/Source/Testably.Abstractions.Testing/Storage/InMemoryContainer.cs @@ -212,6 +212,22 @@ public void WriteBytes(byte[] bytes) #endregion + /// + 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"; + } + /// /// Create a new directory on the . /// @@ -318,6 +334,10 @@ public void Set(DateTime time, DateTimeKind kind) } #endregion + + /// + public override string ToString() + => _time.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ssZ"); } private sealed class FileHandle : IStorageAccessHandle diff --git a/Source/Testably.Abstractions.Testing/Storage/InMemoryStorage.cs b/Source/Testably.Abstractions.Testing/Storage/InMemoryStorage.cs index 1a9d140ca..147bda404 100644 --- a/Source/Testably.Abstractions.Testing/Storage/InMemoryStorage.cs +++ b/Source/Testably.Abstractions.Testing/Storage/InMemoryStorage.cs @@ -15,8 +15,8 @@ namespace Testably.Abstractions.Testing.Storage; /// internal sealed class InMemoryStorage : IStorage { - private readonly ConcurrentDictionary - _containers = new(); + internal readonly ConcurrentDictionary + Containers = new(); private readonly ConcurrentDictionary _drives = new(StringComparer.OrdinalIgnoreCase); @@ -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; @@ -59,7 +59,7 @@ public InMemoryStorage(MockFileSystem fileSystem) using (_ = sourceContainer.RequestAccess(FileAccess.ReadWrite, FileShare.None)) { if (overwrite && - _containers.TryRemove(destination, + Containers.TryRemove(destination, out IStorageContainer? existingContainer)) { existingContainer.ClearBytes(); @@ -67,7 +67,7 @@ public InMemoryStorage(MockFileSystem fileSystem) IStorageContainer copiedContainer = InMemoryContainer.NewFile(destination, _fileSystem); - if (_containers.TryAdd(destination, copiedContainer)) + if (Containers.TryAdd(destination, copiedContainer)) { copiedContainer.WriteBytes(sourceContainer.GetBytes().ToArray()); Execute.OnMac( @@ -99,11 +99,11 @@ public InMemoryStorage(MockFileSystem fileSystem) /// 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); } @@ -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); @@ -160,7 +160,7 @@ public IEnumerable EnumerateLocations( EnumerationOptions? enumerationOptions = null) { ValidateExpression(searchPattern); - if (!_containers.ContainsKey(location)) + if (!Containers.ContainsKey(location)) { throw ExceptionFactory.DirectoryNotFound(location.FullPath); } @@ -177,7 +177,7 @@ public IEnumerable EnumerateLocations( fullPath += _fileSystem.Path.DirectorySeparatorChar; } - foreach (KeyValuePair item in _containers + foreach (KeyValuePair item in Containers .Where(x => x.Key.FullPath.StartsWith(fullPath, InMemoryLocation.StringComparisonMode) && !x.Key.Equals(location))) @@ -215,7 +215,7 @@ public IEnumerable EnumerateLocations( return null; } - if (_containers.TryGetValue(location, out IStorageContainer? container)) + if (Containers.TryGetValue(location, out IStorageContainer? container)) { return container; } @@ -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 = @@ -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); } @@ -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; @@ -383,14 +383,14 @@ 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 |= @@ -398,7 +398,7 @@ public IStorageContainer GetOrCreateContainer( backup.Drive?.ChangeUsedBytes(destinationBytesLength); } - if (_containers.TryRemove(source, + if (Containers.TryRemove(source, out IStorageContainer? existingSourceContainer)) { int sourceBytesLength = existingSourceContainer.GetBytes().Length; @@ -414,7 +414,7 @@ public IStorageContainer GetOrCreateContainer( DateTimeKind.Utc), DateTimeKind.Utc); }); - _containers.TryAdd(destination, existingSourceContainer); + Containers.TryAdd(destination, existingSourceContainer); return destination; } } @@ -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) @@ -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, _ => { @@ -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 => { @@ -571,7 +571,7 @@ private void CreateParents(MockFileSystem fileSystem, IStorageLocation location) FileSystemTypes? sourceType, List? rollbacks = null) { - if (!_containers.TryGetValue(source, + if (!Containers.TryGetValue(source, out IStorageContainer? container)) { return null; @@ -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); @@ -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 @@ -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; @@ -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); } From eade3bfffb2b0d43155bbbb533d24c9fb4544868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Sun, 23 Jul 2023 15:40:52 +0200 Subject: [PATCH 2/2] Cleanup --- Source/Testably.Abstractions.Testing/MockFileSystem.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Testably.Abstractions.Testing/MockFileSystem.cs b/Source/Testably.Abstractions.Testing/MockFileSystem.cs index 635a41d21..94992e864 100644 --- a/Source/Testably.Abstractions.Testing/MockFileSystem.cs +++ b/Source/Testably.Abstractions.Testing/MockFileSystem.cs @@ -46,7 +46,10 @@ public sealed class MockFileSystem : IFileSystem /// The registered containers in the in-Memory . /// internal IReadOnlyList Containers - => _storage.Containers.OrderBy(x => x.Key.FullPath).Select(x => x.Value).ToList(); + => _storage.Containers + .OrderBy(x => x.Key.FullPath) + .Select(x => x.Value) + .ToList(); private readonly DirectoryMock _directoryMock; private readonly FileMock _fileMock;