Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions Source/Testably.Abstractions.Testing/MockFileSystem.cs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -45,11 +44,8 @@ public sealed class MockFileSystem : IFileSystem
/// <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();
internal IReadOnlyList<IStorageContainer> StorageContainers
=> _storage.GetContainers();

private readonly DirectoryMock _directoryMock;
private readonly FileMock _fileMock;
Expand Down Expand Up @@ -123,7 +119,7 @@ public IPath Path

/// <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)})";
=> $"MockFileSystem ({_storage})";

/// <summary>
/// Implements a custom access control (ACL) mechanism.
Expand Down
2 changes: 1 addition & 1 deletion Source/Testably.Abstractions.Testing/MockTimeSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public ITimerFactory Timer

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

/// <summary>
/// Specifies the <see cref="ITimerStrategy" /> to use when dealing with timers.
Expand Down
75 changes: 44 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
{
internal readonly ConcurrentDictionary<IStorageLocation, IStorageContainer>
Containers = new();
private 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 @@ -499,6 +499,19 @@ public bool TryAddContainer(

#endregion

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

/// <summary>
/// Returns an ordered list of all stored containers.
/// </summary>
internal IReadOnlyList<IStorageContainer> GetContainers()
=> _containers
.OrderBy(x => x.Key.FullPath)
.Select(x => x.Value)
.ToList();

private void CheckAndAdjustParentDirectoryTimes(IStorageLocation location)
{
IStorageContainer? parentContainer = GetContainer(location.GetParent());
Expand Down Expand Up @@ -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 =>
{
Expand Down Expand Up @@ -571,7 +584,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 +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);
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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);
}
Expand Down
6 changes: 3 additions & 3 deletions Source/Testably.Abstractions.Testing/TimeProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public static class TimeProvider
/// </summary>
public static ITimeProvider Now()
{
return new TimeProviderMock(DateTime.UtcNow);
return new TimeProviderMock(DateTime.UtcNow, "Now");
}

/// <summary>
Expand All @@ -26,14 +26,14 @@ 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");
}

/// <summary>
/// Initializes the <see cref="MockTimeSystem.TimeProvider" /> with the specified <paramref name="time" />.
/// </summary>
public static ITimeProvider Use(DateTime time)
{
return new TimeProviderMock(time);
return new TimeProviderMock(time, "Fixed");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -57,4 +59,8 @@ public void SetTo(DateTime value)
}

#endregion

/// <inheritdoc cref="object.ToString()" />
public override string ToString()
=> _description;
}