diff --git a/Source/Testably.Abstractions.Testing/MockFileSystem.cs b/Source/Testably.Abstractions.Testing/MockFileSystem.cs index 94992e864..d07cb196d 100644 --- a/Source/Testably.Abstractions.Testing/MockFileSystem.cs +++ b/Source/Testably.Abstractions.Testing/MockFileSystem.cs @@ -1,7 +1,6 @@ using Microsoft.Win32.SafeHandles; using System; using System.Collections.Generic; -using System.Linq; using Testably.Abstractions.Testing.FileSystem; using Testably.Abstractions.Testing.Storage; @@ -45,11 +44,8 @@ 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(); + internal IReadOnlyList StorageContainers + => _storage.GetContainers(); private readonly DirectoryMock _directoryMock; private readonly FileMock _fileMock; @@ -123,7 +119,7 @@ public IPath Path /// 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)})"; + => $"MockFileSystem ({_storage})"; /// /// Implements a custom access control (ACL) mechanism. diff --git a/Source/Testably.Abstractions.Testing/MockTimeSystem.cs b/Source/Testably.Abstractions.Testing/MockTimeSystem.cs index 146a52f73..5eee0bc3d 100644 --- a/Source/Testably.Abstractions.Testing/MockTimeSystem.cs +++ b/Source/Testably.Abstractions.Testing/MockTimeSystem.cs @@ -82,7 +82,7 @@ public ITimerFactory Timer /// public override string ToString() - => $"MockTimeSystem (now: {DateTime.UtcNow}Z)"; + => $"MockTimeSystem (provider: {TimeProvider}, now: {DateTime.UtcNow}Z)"; /// /// Specifies the to use when dealing with timers. diff --git a/Source/Testably.Abstractions.Testing/Storage/InMemoryStorage.cs b/Source/Testably.Abstractions.Testing/Storage/InMemoryStorage.cs index 4ed2a7119..e331d5e42 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 { - internal readonly ConcurrentDictionary - Containers = new(); + private 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, _ => { @@ -499,6 +499,19 @@ public bool TryAddContainer( #endregion + /// + public override string ToString() + => $"directories: {_containers.Count(x => x.Value.Type == FileSystemTypes.Directory)}, files: {_containers.Count(x => x.Value.Type == FileSystemTypes.File)}"; + + /// + /// Returns an ordered list of all stored containers. + /// + internal IReadOnlyList GetContainers() + => _containers + .OrderBy(x => x.Key.FullPath) + .Select(x => x.Value) + .ToList(); + private void CheckAndAdjustParentDirectoryTimes(IStorageLocation location) { IStorageContainer? parentContainer = GetContainer(location.GetParent()); @@ -535,7 +548,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 +584,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 +628,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 +651,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 +678,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 +705,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); } diff --git a/Source/Testably.Abstractions.Testing/TimeProvider.cs b/Source/Testably.Abstractions.Testing/TimeProvider.cs index f24a0e922..6c94e4084 100644 --- a/Source/Testably.Abstractions.Testing/TimeProvider.cs +++ b/Source/Testably.Abstractions.Testing/TimeProvider.cs @@ -14,7 +14,7 @@ public static class TimeProvider /// public static ITimeProvider Now() { - return new TimeProviderMock(DateTime.UtcNow); + return new TimeProviderMock(DateTime.UtcNow, "Now"); } /// @@ -26,7 +26,7 @@ public static ITimeProvider Random() { DateTime randomTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) .AddSeconds(RandomFactory.Shared.Next()); - return new TimeProviderMock(randomTime); + return new TimeProviderMock(randomTime, "Random"); } /// @@ -34,6 +34,6 @@ public static ITimeProvider Random() /// public static ITimeProvider Use(DateTime time) { - return new TimeProviderMock(time); + return new TimeProviderMock(time, "Fixed"); } } diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/TimeProviderMock.cs b/Source/Testably.Abstractions.Testing/TimeSystem/TimeProviderMock.cs index 55438f0c9..c33347633 100644 --- a/Source/Testably.Abstractions.Testing/TimeSystem/TimeProviderMock.cs +++ b/Source/Testably.Abstractions.Testing/TimeSystem/TimeProviderMock.cs @@ -8,11 +8,13 @@ namespace Testably.Abstractions.Testing.TimeSystem; internal sealed class TimeProviderMock : ITimeProvider { private DateTime _now; + private readonly string _description; private readonly object _lock = new(); - public TimeProviderMock(DateTime now) + public TimeProviderMock(DateTime now, string description) { _now = now; + _description = description; } #region ITimeProvider Members @@ -57,4 +59,8 @@ public void SetTo(DateTime value) } #endregion + + /// + public override string ToString() + => _description; }