diff --git a/Directory.Packages.props b/Directory.Packages.props
index 66093eba9..e7ae96fd3 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -6,7 +6,7 @@
-
+
diff --git a/Feature.Flags.props b/Feature.Flags.props
index 222a6244c..2d16c5bf2 100644
--- a/Feature.Flags.props
+++ b/Feature.Flags.props
@@ -1,9 +1,10 @@
- 1
- 1
- 1
+ 1
+ 1
+ 1
+ 1
$(DefineConstants);NETFRAMEWORK
$(DefineConstants);CAN_SIMULATE_OTHER_OS
@@ -30,6 +31,9 @@
$(DefineConstants);FEATURE_GUID_FORMATPROVIDER
$(DefineConstants);FEATURE_RANDOM_ITEMS
$(DefineConstants);FEATURE_COMPRESSION_STREAM
+ $(DefineConstants);FEATURE_PATH_SPAN
+ $(DefineConstants);FEATURE_FILE_SPAN
+ $(DefineConstants);FEATURE_GUID_V7
diff --git a/Source/Directory.Build.props b/Source/Directory.Build.props
index 81054c19a..ec85e9df3 100644
--- a/Source/Directory.Build.props
+++ b/Source/Directory.Build.props
@@ -13,7 +13,7 @@
- net6.0;net8.0;netstandard2.1;netstandard2.0
+ net6.0;net8.0;net9.0;netstandard2.1;netstandard2.0
netstandard2.0
diff --git a/Source/Testably.Abstractions.Interface/Helpers/GuidSystemBase.cs b/Source/Testably.Abstractions.Interface/Helpers/GuidSystemBase.cs
index 9cdc33156..e3cbe06ac 100644
--- a/Source/Testably.Abstractions.Interface/Helpers/GuidSystemBase.cs
+++ b/Source/Testably.Abstractions.Interface/Helpers/GuidSystemBase.cs
@@ -32,6 +32,16 @@ protected GuidSystemBase(IRandomSystem randomSystem)
///
public abstract Guid NewGuid();
+#if FEATURE_GUID_V7
+ ///
+ public abstract Guid CreateVersion7();
+#endif
+
+#if FEATURE_GUID_V7
+ ///
+ public abstract Guid CreateVersion7(DateTimeOffset timestamp);
+#endif
+
#if FEATURE_GUID_PARSE
#pragma warning disable MA0011
///
diff --git a/Source/Testably.Abstractions.Interface/RandomSystem/IGuid.cs b/Source/Testably.Abstractions.Interface/RandomSystem/IGuid.cs
index 18f8e2a85..61b10d62c 100644
--- a/Source/Testably.Abstractions.Interface/RandomSystem/IGuid.cs
+++ b/Source/Testably.Abstractions.Interface/RandomSystem/IGuid.cs
@@ -16,6 +16,16 @@ public interface IGuid : IRandomSystemEntity
///
Guid NewGuid();
+#if FEATURE_GUID_V7
+ ///
+ Guid CreateVersion7();
+#endif
+
+#if FEATURE_GUID_V7
+ ///
+ Guid CreateVersion7(DateTimeOffset timestamp);
+#endif
+
#if FEATURE_GUID_PARSE
///
Guid Parse(string input);
diff --git a/Source/Testably.Abstractions.Testing/FileSystem/FileMock.cs b/Source/Testably.Abstractions.Testing/FileSystem/FileMock.cs
index 914d3cf81..4a3be755b 100644
--- a/Source/Testably.Abstractions.Testing/FileSystem/FileMock.cs
+++ b/Source/Testably.Abstractions.Testing/FileSystem/FileMock.cs
@@ -31,6 +31,74 @@ internal FileMock(MockFileSystem fileSystem)
///
public IFileSystem FileSystem
=> _fileSystem;
+
+#if FEATURE_FILE_SPAN
+ ///
+ public void AppendAllBytes(string path, byte[] bytes)
+ {
+ using IDisposable registration = _fileSystem.StatisticsRegistration
+ .File.RegisterMethod(nameof(AppendAllBytes),
+ path, bytes);
+
+ IStorageContainer container =
+ _fileSystem.Storage.GetOrCreateContainer(
+ _fileSystem.Storage.GetLocation(
+ path.EnsureValidFormat(_fileSystem)),
+ InMemoryContainer.NewFile);
+
+ if (container.Type != FileSystemTypes.File)
+ {
+ throw ExceptionFactory.AccessToPathDenied(path);
+ }
+
+ using (container.RequestAccess(
+ FileAccess.ReadWrite,
+ FileStreamFactoryMock.DefaultShare))
+ {
+ container.AppendBytes(bytes);
+ }
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public void AppendAllBytes(string path, ReadOnlySpan bytes)
+ {
+ using IDisposable registration = _fileSystem.StatisticsRegistration
+ .File.RegisterMethod(nameof(AppendAllBytes),
+ path, bytes);
+
+ AppendAllBytes(path, bytes.ToArray());
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public Task AppendAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default)
+ {
+ using IDisposable registration = _fileSystem.StatisticsRegistration
+ .File.RegisterMethod(nameof(AppendAllBytesAsync),
+ path, bytes, cancellationToken);
+
+ ThrowIfCancelled(cancellationToken);
+ AppendAllBytes(path, bytes);
+ return Task.CompletedTask;
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public Task AppendAllBytesAsync(string path, ReadOnlyMemory bytes, CancellationToken cancellationToken = default)
+ {
+ using IDisposable registration = _fileSystem.StatisticsRegistration
+ .File.RegisterMethod(nameof(AppendAllBytesAsync),
+ path, bytes, cancellationToken);
+
+ ThrowIfCancelled(cancellationToken);
+ AppendAllBytes(path, bytes.ToArray());
+ return Task.CompletedTask;
+ }
+#endif
///
public void AppendAllLines(string path, IEnumerable contents)
@@ -132,6 +200,30 @@ public void AppendAllText(string path, string? contents, Encoding encoding)
}
}
}
+
+#if FEATURE_FILE_SPAN
+ ///
+ public void AppendAllText(string path, ReadOnlySpan contents)
+ {
+ using IDisposable registration = _fileSystem.StatisticsRegistration
+ .File.RegisterMethod(nameof(AppendAllText),
+ path, contents);
+
+ AppendAllText(path, contents.ToString(), Encoding.Default);
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public void AppendAllText(string path, ReadOnlySpan contents, Encoding encoding)
+ {
+ using IDisposable registration = _fileSystem.StatisticsRegistration
+ .File.RegisterMethod(nameof(AppendAllText),
+ path, contents, encoding);
+
+ AppendAllText(path, contents.ToString(), encoding);
+ }
+#endif
#if FEATURE_FILESYSTEM_ASYNC
///
@@ -160,6 +252,35 @@ public Task AppendAllTextAsync(string path, string? contents, Encoding encoding,
return Task.CompletedTask;
}
#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public Task AppendAllTextAsync(string path, ReadOnlyMemory contents, CancellationToken cancellationToken = default)
+ {
+ using IDisposable registration = _fileSystem.StatisticsRegistration
+ .File.RegisterMethod(nameof(AppendAllTextAsync),
+ path, contents, cancellationToken);
+
+ ThrowIfCancelled(cancellationToken);
+ AppendAllText(path, contents.ToString(), Encoding.Default);
+ return Task.CompletedTask;
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public Task AppendAllTextAsync(string path, ReadOnlyMemory contents, Encoding encoding,
+ CancellationToken cancellationToken = default)
+ {
+ using IDisposable registration = _fileSystem.StatisticsRegistration
+ .File.RegisterMethod(nameof(AppendAllTextAsync),
+ path, contents, encoding, cancellationToken);
+
+ ThrowIfCancelled(cancellationToken);
+ AppendAllText(path, contents.ToString(), encoding);
+ return Task.CompletedTask;
+ }
+#endif
///
public StreamWriter AppendText(string path)
@@ -1241,6 +1362,18 @@ public void WriteAllBytes(string path, byte[] bytes)
container.WriteBytes(bytes);
}
}
+
+#if FEATURE_FILE_SPAN
+ ///
+ public void WriteAllBytes(string path, ReadOnlySpan bytes)
+ {
+ using IDisposable registration = _fileSystem.StatisticsRegistration
+ .File.RegisterMethod(nameof(WriteAllBytes),
+ path, bytes);
+
+ WriteAllBytes(path, bytes.ToArray());
+ }
+#endif
#if FEATURE_FILESYSTEM_ASYNC
///
@@ -1256,6 +1389,20 @@ public Task WriteAllBytesAsync(string path, byte[] bytes,
return Task.CompletedTask;
}
#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public Task WriteAllBytesAsync(string path, ReadOnlyMemory bytes, CancellationToken cancellationToken = default)
+ {
+ using IDisposable registration = _fileSystem.StatisticsRegistration
+ .File.RegisterMethod(nameof(WriteAllBytesAsync),
+ path, bytes, cancellationToken);
+
+ ThrowIfCancelled(cancellationToken);
+ WriteAllBytes(path, bytes.ToArray());
+ return Task.CompletedTask;
+ }
+#endif
///
public void WriteAllLines(string path, string[] contents)
@@ -1388,6 +1535,31 @@ public void WriteAllText(string path, string? contents, Encoding encoding)
}
}
}
+
+#if FEATURE_FILE_SPAN
+ ///
+ public void WriteAllText(string path, ReadOnlySpan contents)
+ {
+ using IDisposable registration = _fileSystem.StatisticsRegistration
+ .File.RegisterMethod(nameof(WriteAllText),
+ path, contents);
+
+ WriteAllText(path, contents.ToString(), Encoding.Default);
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+
+ ///
+ public void WriteAllText(string path, ReadOnlySpan contents, Encoding encoding)
+ {
+ using IDisposable registration = _fileSystem.StatisticsRegistration
+ .File.RegisterMethod(nameof(WriteAllText),
+ path, contents, encoding);
+
+ WriteAllText(path, contents.ToString(), encoding);
+ }
+#endif
#if FEATURE_FILESYSTEM_ASYNC
///
@@ -1416,6 +1588,35 @@ public Task WriteAllTextAsync(string path, string? contents, Encoding encoding,
return Task.CompletedTask;
}
#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public Task WriteAllTextAsync(string path, ReadOnlyMemory contents, CancellationToken cancellationToken = default)
+ {
+ using IDisposable registration = _fileSystem.StatisticsRegistration
+ .File.RegisterMethod(nameof(WriteAllTextAsync),
+ path, contents, cancellationToken);
+
+ ThrowIfCancelled(cancellationToken);
+ WriteAllText(path, contents.ToString(), Encoding.Default);
+ return Task.CompletedTask;
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public Task WriteAllTextAsync(string path, ReadOnlyMemory contents, Encoding encoding,
+ CancellationToken cancellationToken = default)
+ {
+ using IDisposable registration = _fileSystem.StatisticsRegistration
+ .File.RegisterMethod(nameof(WriteAllTextAsync),
+ path, contents, encoding, cancellationToken);
+
+ ThrowIfCancelled(cancellationToken);
+ WriteAllText(path, contents.ToString(), encoding);
+ return Task.CompletedTask;
+ }
+#endif
#endregion
diff --git a/Source/Testably.Abstractions.Testing/FileSystem/PathMock.cs b/Source/Testably.Abstractions.Testing/FileSystem/PathMock.cs
index 174c81425..b7513e3a7 100644
--- a/Source/Testably.Abstractions.Testing/FileSystem/PathMock.cs
+++ b/Source/Testably.Abstractions.Testing/FileSystem/PathMock.cs
@@ -117,6 +117,18 @@ public string Combine(params string[] paths)
return _fileSystem.Execute.Path.Combine(paths);
}
+
+#if FEATURE_PATH_SPAN
+ ///
+ public string Combine(params ReadOnlySpan paths)
+ {
+ using IDisposable register = _fileSystem.StatisticsRegistration
+ .Path.RegisterMethod(nameof(Combine),
+ paths);
+
+ return _fileSystem.Execute.Path.Combine(paths);
+ }
+#endif
#if FEATURE_PATH_ADVANCED
///
@@ -512,6 +524,18 @@ public string Join(params string?[] paths)
return _fileSystem.Execute.Path.Join(paths);
}
#endif
+
+#if FEATURE_PATH_SPAN
+ ///
+ public string Join(params ReadOnlySpan paths)
+ {
+ using IDisposable register = _fileSystem.StatisticsRegistration
+ .Path.RegisterMethod(nameof(Join),
+ paths);
+
+ return _fileSystem.Execute.Path.Join(paths);
+ }
+#endif
#if FEATURE_PATH_ADVANCED
///
diff --git a/Source/Testably.Abstractions.Testing/Helpers/Execute.NativePath.cs b/Source/Testably.Abstractions.Testing/Helpers/Execute.NativePath.cs
index c262e1ae0..27ee67618 100644
--- a/Source/Testably.Abstractions.Testing/Helpers/Execute.NativePath.cs
+++ b/Source/Testably.Abstractions.Testing/Helpers/Execute.NativePath.cs
@@ -54,6 +54,12 @@ public string Combine(string path1, string path2, string path3, string path4)
///
public string Combine(params string[] paths)
=> System.IO.Path.Combine(paths);
+
+#if FEATURE_PATH_SPAN
+ ///
+ public string Combine(params ReadOnlySpan paths)
+ => System.IO.Path.Combine(paths);
+#endif
#if FEATURE_PATH_ADVANCED
///
@@ -279,6 +285,12 @@ public string Join(string? path1, string? path2, string? path3, string? path4)
public string Join(params string?[] paths)
=> System.IO.Path.Join(paths);
#endif
+
+#if FEATURE_PATH_SPAN
+ ///
+ public string Join(params ReadOnlySpan paths)
+ => System.IO.Path.Join(paths);
+#endif
#if FEATURE_PATH_ADVANCED
///
diff --git a/Source/Testably.Abstractions.Testing/Helpers/Execute.SimulatedPath.cs b/Source/Testably.Abstractions.Testing/Helpers/Execute.SimulatedPath.cs
index 4d454ecab..7bb43f883 100644
--- a/Source/Testably.Abstractions.Testing/Helpers/Execute.SimulatedPath.cs
+++ b/Source/Testably.Abstractions.Testing/Helpers/Execute.SimulatedPath.cs
@@ -128,6 +128,12 @@ public string Combine(string path1, string path2, string path3, string path4)
///
public string Combine(params string[] paths)
=> CombineInternal(paths);
+
+#if FEATURE_PATH_SPAN
+ ///
+ public string Combine(params ReadOnlySpan paths)
+ => CombineInternal(paths.ToArray());
+#endif
#if FEATURE_PATH_ADVANCED
///
@@ -440,6 +446,12 @@ public string Join(string? path1, string? path2, string? path3, string? path4)
public string Join(params string?[] paths)
=> JoinInternal(paths);
#endif
+
+#if FEATURE_PATH_SPAN
+ ///
+ public string Join(params ReadOnlySpan paths)
+ => JoinInternal(paths.ToArray());
+#endif
#if FEATURE_PATH_ADVANCED
///
diff --git a/Source/Testably.Abstractions.Testing/RandomSystem/GuidMock.cs b/Source/Testably.Abstractions.Testing/RandomSystem/GuidMock.cs
index 182b2c8be..47b34a432 100644
--- a/Source/Testably.Abstractions.Testing/RandomSystem/GuidMock.cs
+++ b/Source/Testably.Abstractions.Testing/RandomSystem/GuidMock.cs
@@ -16,4 +16,16 @@ internal GuidMock(MockRandomSystem randomSystem) : base(randomSystem)
///
public override Guid NewGuid()
=> _mockRandomSystem.RandomProvider.GetGuid();
+
+#if FEATURE_GUID_V7
+ ///
+ public override Guid CreateVersion7()
+ => _mockRandomSystem.RandomProvider.GetGuid();
+#endif
+
+#if FEATURE_GUID_V7
+ ///
+ public override Guid CreateVersion7(DateTimeOffset timestamp)
+ => _mockRandomSystem.RandomProvider.GetGuid();
+#endif
}
diff --git a/Source/Testably.Abstractions.Testing/RandomSystem/RandomProviderMock.cs b/Source/Testably.Abstractions.Testing/RandomSystem/RandomProviderMock.cs
index 8d9fd2f03..59caeafca 100644
--- a/Source/Testably.Abstractions.Testing/RandomSystem/RandomProviderMock.cs
+++ b/Source/Testably.Abstractions.Testing/RandomSystem/RandomProviderMock.cs
@@ -24,7 +24,7 @@ public RandomProviderMock(
#region IRandomProvider Members
- ///
+ ///
public Guid GetGuid()
=> _guidGenerator.GetNext();
diff --git a/Source/Testably.Abstractions.Testing/Statistics/CallStatistics.cs b/Source/Testably.Abstractions.Testing/Statistics/CallStatistics.cs
index 555863a64..4ff863475 100644
--- a/Source/Testably.Abstractions.Testing/Statistics/CallStatistics.cs
+++ b/Source/Testably.Abstractions.Testing/Statistics/CallStatistics.cs
@@ -199,6 +199,45 @@ internal IDisposable RegisterMethod(string name, ReadOnlySpan parameter1
}
#endif
+#if FEATURE_FILE_SPAN
+ ///
+ /// Registers the method with and .
+ ///
+ /// A disposable which ignores all registrations, until it is disposed.
+ internal IDisposable RegisterMethod(string name, T1 parameter1, ReadOnlySpan parameter2)
+ {
+ if (_statisticsGate.TryGetLock(out IDisposable release))
+ {
+ int counter = _statisticsGate.GetCounter();
+ _methods.Enqueue(new MethodStatistic(counter, name,
+ ParameterDescription.FromParameter(parameter1),
+ ParameterDescription.FromParameter(parameter2)));
+ }
+
+ return release;
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ /// Registers the method with , and .
+ ///
+ /// A disposable which ignores all registrations, until it is disposed.
+ internal IDisposable RegisterMethod(string name, T1 parameter1, ReadOnlySpan parameter2, T3 parameter3)
+ {
+ if (_statisticsGate.TryGetLock(out IDisposable release))
+ {
+ int counter = _statisticsGate.GetCounter();
+ _methods.Enqueue(new MethodStatistic(counter, name,
+ ParameterDescription.FromParameter(parameter1),
+ ParameterDescription.FromParameter(parameter2),
+ ParameterDescription.FromParameter(parameter3)));
+ }
+
+ return release;
+ }
+#endif
+
#if FEATURE_SPAN
///
/// Registers the method with and
diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/TimeProviderMock.cs b/Source/Testably.Abstractions.Testing/TimeSystem/TimeProviderMock.cs
index c33347633..231037bed 100644
--- a/Source/Testably.Abstractions.Testing/TimeSystem/TimeProviderMock.cs
+++ b/Source/Testably.Abstractions.Testing/TimeSystem/TimeProviderMock.cs
@@ -9,7 +9,11 @@ internal sealed class TimeProviderMock : ITimeProvider
{
private DateTime _now;
private readonly string _description;
+#if NET9_0_OR_GREATER
+ private readonly System.Threading.Lock _lock = new();
+#else
private readonly object _lock = new();
+#endif
public TimeProviderMock(DateTime now, string description)
{
diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/TimerMock.cs b/Source/Testably.Abstractions.Testing/TimeSystem/TimerMock.cs
index 7b1fd49f2..c2ef90293 100644
--- a/Source/Testably.Abstractions.Testing/TimeSystem/TimerMock.cs
+++ b/Source/Testably.Abstractions.Testing/TimeSystem/TimerMock.cs
@@ -16,7 +16,11 @@ internal sealed class TimerMock : ITimerMock
private TimeSpan _dueTime;
private Exception? _exception;
private bool _isDisposed;
+#if NET9_0_OR_GREATER
+ private readonly Lock _lock = new();
+#else
private readonly object _lock = new();
+#endif
private readonly MockTimeSystem _mockTimeSystem;
private Action? _onDispose;
private TimeSpan _period;
diff --git a/Source/Testably.Abstractions/FileSystem/FileWrapper.cs b/Source/Testably.Abstractions/FileSystem/FileWrapper.cs
index a99ba6692..314d36b42 100644
--- a/Source/Testably.Abstractions/FileSystem/FileWrapper.cs
+++ b/Source/Testably.Abstractions/FileSystem/FileWrapper.cs
@@ -24,6 +24,30 @@ internal FileWrapper(RealFileSystem fileSystem)
///
public IFileSystem FileSystem { get; }
+
+#if FEATURE_FILE_SPAN
+ ///
+ public void AppendAllBytes(string path, byte[] bytes)
+ => File.AppendAllBytes(path, bytes);
+#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public void AppendAllBytes(string path, ReadOnlySpan bytes)
+ => File.AppendAllBytes(path, bytes);
+#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public Task AppendAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default)
+ => File.AppendAllBytesAsync(path, bytes, cancellationToken);
+#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public Task AppendAllBytesAsync(string path, ReadOnlyMemory bytes, CancellationToken cancellationToken = default)
+ => File.AppendAllBytesAsync(path, bytes, cancellationToken);
+#endif
///
public void AppendAllLines(string path, IEnumerable contents)
@@ -59,6 +83,18 @@ public void AppendAllText(string path, string? contents)
///
public void AppendAllText(string path, string? contents, Encoding encoding)
=> File.AppendAllText(path, contents, encoding);
+
+#if FEATURE_FILE_SPAN
+ ///
+ public void AppendAllText(string path, ReadOnlySpan contents)
+ => File.AppendAllText(path, contents);
+#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public void AppendAllText(string path, ReadOnlySpan contents, Encoding encoding)
+ => File.AppendAllText(path, contents, encoding);
+#endif
#if FEATURE_FILESYSTEM_ASYNC
///
@@ -76,6 +112,19 @@ public Task AppendAllTextAsync(string path, string? contents, Encoding encoding,
=> File.AppendAllTextAsync(path, contents, encoding,
cancellationToken);
#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public Task AppendAllTextAsync(string path, ReadOnlyMemory contents, CancellationToken cancellationToken = default)
+ => File.AppendAllTextAsync(path, contents, cancellationToken);
+#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public Task AppendAllTextAsync(string path, ReadOnlyMemory contents, Encoding encoding,
+ CancellationToken cancellationToken = default)
+ => File.AppendAllTextAsync(path, contents, encoding, cancellationToken);
+#endif
///
public StreamWriter AppendText(string path)
@@ -497,6 +546,12 @@ public void SetUnixFileMode(SafeFileHandle fileHandle, UnixFileMode mode)
///
public void WriteAllBytes(string path, byte[] bytes)
=> File.WriteAllBytes(path, bytes);
+
+#if FEATURE_FILE_SPAN
+ ///
+ public void WriteAllBytes(string path, ReadOnlySpan bytes)
+ => File.WriteAllBytes(path, bytes);
+#endif
#if FEATURE_FILESYSTEM_ASYNC
///
@@ -505,6 +560,12 @@ public Task WriteAllBytesAsync(string path, byte[] bytes,
default)
=> File.WriteAllBytesAsync(path, bytes, cancellationToken);
#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public Task WriteAllBytesAsync(string path, ReadOnlyMemory bytes, CancellationToken cancellationToken = default)
+ => File.WriteAllBytesAsync(path, bytes, cancellationToken);
+#endif
///
public void WriteAllLines(string path, string[] contents)
@@ -548,6 +609,19 @@ public void WriteAllText(string path, string? contents)
///
public void WriteAllText(string path, string? contents, Encoding encoding)
=> File.WriteAllText(path, contents, encoding);
+
+#if FEATURE_FILE_SPAN
+ ///
+ public void WriteAllText(string path, ReadOnlySpan contents)
+ => File.WriteAllText(path, contents);
+#endif
+
+#if FEATURE_FILE_SPAN
+
+ ///
+ public void WriteAllText(string path, ReadOnlySpan contents, Encoding encoding)
+ => File.WriteAllText(path, contents, encoding);
+#endif
#if FEATURE_FILESYSTEM_ASYNC
///
@@ -565,6 +639,19 @@ public Task WriteAllTextAsync(string path, string? contents, Encoding encoding,
=> File.WriteAllTextAsync(path, contents, encoding,
cancellationToken);
#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public Task WriteAllTextAsync(string path, ReadOnlyMemory contents, CancellationToken cancellationToken = default)
+ => File.WriteAllTextAsync(path, contents, cancellationToken);
+#endif
+
+#if FEATURE_FILE_SPAN
+ ///
+ public Task WriteAllTextAsync(string path, ReadOnlyMemory contents, Encoding encoding,
+ CancellationToken cancellationToken = default)
+ => File.WriteAllTextAsync(path, contents, encoding, cancellationToken);
+#endif
#endregion
}
diff --git a/Source/Testably.Abstractions/FileSystem/PathWrapper.cs b/Source/Testably.Abstractions/FileSystem/PathWrapper.cs
index e59104b02..5a6151093 100644
--- a/Source/Testably.Abstractions/FileSystem/PathWrapper.cs
+++ b/Source/Testably.Abstractions/FileSystem/PathWrapper.cs
@@ -56,6 +56,12 @@ public string Combine(string path1, string path2, string path3, string path4)
///
public string Combine(params string[] paths)
=> Path.Combine(paths);
+
+#if FEATURE_PATH_SPAN
+ ///
+ public string Combine(params ReadOnlySpan paths)
+ => Path.Combine(paths);
+#endif
#if FEATURE_PATH_ADVANCED
///
@@ -247,6 +253,12 @@ public string Join(string? path1, string? path2, string? path3, string? path4)
public string Join(params string?[] paths)
=> Path.Join(paths);
#endif
+
+#if FEATURE_PATH_SPAN
+ ///
+ public string Join(params ReadOnlySpan paths)
+ => Path.Join(paths);
+#endif
#if FEATURE_PATH_ADVANCED
///
diff --git a/Source/Testably.Abstractions/RandomSystem/GuidWrapper.cs b/Source/Testably.Abstractions/RandomSystem/GuidWrapper.cs
index ca96b4455..6010c7b6e 100644
--- a/Source/Testably.Abstractions/RandomSystem/GuidWrapper.cs
+++ b/Source/Testably.Abstractions/RandomSystem/GuidWrapper.cs
@@ -12,4 +12,16 @@ internal GuidWrapper(RealRandomSystem randomSystem) : base(randomSystem)
///
public override Guid NewGuid()
=> Guid.NewGuid();
+
+#if FEATURE_GUID_V7
+ ///
+ public override Guid CreateVersion7()
+ => Guid.CreateVersion7();
+#endif
+
+#if FEATURE_GUID_V7
+ ///
+ public override Guid CreateVersion7(DateTimeOffset timestamp)
+ => Guid.CreateVersion7(timestamp);
+#endif
}
diff --git a/Testably.Abstractions.sln.DotSettings b/Testably.Abstractions.sln.DotSettings
index ba93afa1f..60cbae69e 100644
--- a/Testably.Abstractions.sln.DotSettings
+++ b/Testably.Abstractions.sln.DotSettings
@@ -16,6 +16,7 @@
Required
Required
Required
+ True
False
False
False
diff --git a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.AccessControl_net9.0.txt b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.AccessControl_net9.0.txt
new file mode 100644
index 000000000..bbff50437
--- /dev/null
+++ b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.AccessControl_net9.0.txt
@@ -0,0 +1,54 @@
+[assembly: System.CLSCompliant(true)]
+[assembly: System.Reflection.AssemblyMetadata("RepositoryUrl", "https://github.com/Testably/Testably.Abstractions.git")]
+[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Testably.Abstractions.AccessControl.Tests")]
+[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v9.0", FrameworkDisplayName=".NET 9.0")]
+namespace Testably.Abstractions
+{
+ public static class DirectoryAclExtensions
+ {
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static void CreateDirectory(this System.IO.Abstractions.IDirectory directory, string path, System.Security.AccessControl.DirectorySecurity directorySecurity) { }
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static System.Security.AccessControl.DirectorySecurity GetAccessControl(this System.IO.Abstractions.IDirectory directory, string path) { }
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static System.Security.AccessControl.DirectorySecurity GetAccessControl(this System.IO.Abstractions.IDirectory directory, string path, System.Security.AccessControl.AccessControlSections includeSections) { }
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static void SetAccessControl(this System.IO.Abstractions.IDirectory directory, string path, System.Security.AccessControl.DirectorySecurity directorySecurity) { }
+ }
+ public static class DirectoryInfoAclExtensions
+ {
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static void Create(this System.IO.Abstractions.IDirectoryInfo directoryInfo, System.Security.AccessControl.DirectorySecurity directorySecurity) { }
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static System.Security.AccessControl.DirectorySecurity GetAccessControl(this System.IO.Abstractions.IDirectoryInfo directoryInfo) { }
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static System.Security.AccessControl.DirectorySecurity GetAccessControl(this System.IO.Abstractions.IDirectoryInfo directoryInfo, System.Security.AccessControl.AccessControlSections includeSections) { }
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static void SetAccessControl(this System.IO.Abstractions.IDirectoryInfo directoryInfo, System.Security.AccessControl.DirectorySecurity directorySecurity) { }
+ }
+ public static class FileAclExtensions
+ {
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static System.Security.AccessControl.FileSecurity GetAccessControl(this System.IO.Abstractions.IFile file, string path) { }
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static System.Security.AccessControl.FileSecurity GetAccessControl(this System.IO.Abstractions.IFile file, string path, System.Security.AccessControl.AccessControlSections includeSections) { }
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static void SetAccessControl(this System.IO.Abstractions.IFile file, string path, System.Security.AccessControl.FileSecurity fileSecurity) { }
+ }
+ public static class FileInfoAclExtensions
+ {
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static System.Security.AccessControl.FileSecurity GetAccessControl(this System.IO.Abstractions.IFileInfo fileInfo) { }
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static System.Security.AccessControl.FileSecurity GetAccessControl(this System.IO.Abstractions.IFileInfo fileInfo, System.Security.AccessControl.AccessControlSections includeSections) { }
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static void SetAccessControl(this System.IO.Abstractions.IFileInfo fileInfo, System.Security.AccessControl.FileSecurity fileSecurity) { }
+ }
+ public static class FileStreamAclExtensions
+ {
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static System.Security.AccessControl.FileSecurity GetAccessControl(this System.IO.Abstractions.FileSystemStream fileStream) { }
+ [System.Runtime.Versioning.SupportedOSPlatform("windows")]
+ public static void SetAccessControl(this System.IO.Abstractions.FileSystemStream fileStream, System.Security.AccessControl.FileSecurity fileSecurity) { }
+ }
+}
\ No newline at end of file
diff --git a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Compression_net9.0.txt b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Compression_net9.0.txt
new file mode 100644
index 000000000..8cb294b9c
--- /dev/null
+++ b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Compression_net9.0.txt
@@ -0,0 +1,68 @@
+[assembly: System.Reflection.AssemblyMetadata("RepositoryUrl", "https://github.com/Testably/Testably.Abstractions.git")]
+[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Testably.Abstractions.Compression.Tests")]
+[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v9.0", FrameworkDisplayName=".NET 9.0")]
+namespace Testably.Abstractions
+{
+ public static class FileSystemExtensions
+ {
+ public static Testably.Abstractions.IZipArchiveFactory ZipArchive(this System.IO.Abstractions.IFileSystem fileSystem) { }
+ public static Testably.Abstractions.IZipFile ZipFile(this System.IO.Abstractions.IFileSystem fileSystem) { }
+ }
+ public interface IZipArchive : System.IDisposable, System.IO.Abstractions.IFileSystemEntity
+ {
+ string Comment { get; set; }
+ System.Collections.ObjectModel.ReadOnlyCollection Entries { get; }
+ System.IO.Compression.ZipArchiveMode Mode { get; }
+ Testably.Abstractions.IZipArchiveEntry CreateEntry(string entryName);
+ Testably.Abstractions.IZipArchiveEntry CreateEntry(string entryName, System.IO.Compression.CompressionLevel compressionLevel);
+ Testably.Abstractions.IZipArchiveEntry CreateEntryFromFile(string sourceFileName, string entryName);
+ Testably.Abstractions.IZipArchiveEntry CreateEntryFromFile(string sourceFileName, string entryName, System.IO.Compression.CompressionLevel compressionLevel);
+ void ExtractToDirectory(string destinationDirectoryName);
+ void ExtractToDirectory(string destinationDirectoryName, bool overwriteFiles);
+ Testably.Abstractions.IZipArchiveEntry? GetEntry(string entryName);
+ }
+ public interface IZipArchiveEntry : System.IO.Abstractions.IFileSystemEntity
+ {
+ Testably.Abstractions.IZipArchive Archive { get; }
+ string Comment { get; set; }
+ long CompressedLength { get; }
+ uint Crc32 { get; }
+ int ExternalAttributes { get; set; }
+ string FullName { get; }
+ bool IsEncrypted { get; }
+ System.DateTimeOffset LastWriteTime { get; set; }
+ long Length { get; }
+ string Name { get; }
+ void Delete();
+ void ExtractToFile(string destinationFileName);
+ void ExtractToFile(string destinationFileName, bool overwrite);
+ System.IO.Stream Open();
+ }
+ public interface IZipArchiveFactory : System.IO.Abstractions.IFileSystemEntity
+ {
+ Testably.Abstractions.IZipArchive New(System.IO.Stream stream);
+ Testably.Abstractions.IZipArchive New(System.IO.Stream stream, System.IO.Compression.ZipArchiveMode mode);
+ Testably.Abstractions.IZipArchive New(System.IO.Stream stream, System.IO.Compression.ZipArchiveMode mode, bool leaveOpen);
+ Testably.Abstractions.IZipArchive New(System.IO.Stream stream, System.IO.Compression.ZipArchiveMode mode, bool leaveOpen, System.Text.Encoding? entryNameEncoding);
+ }
+ public interface IZipFile : System.IO.Abstractions.IFileSystemEntity
+ {
+ void CreateFromDirectory(string sourceDirectoryName, System.IO.Stream destination);
+ void CreateFromDirectory(string sourceDirectoryName, string destinationArchiveFileName);
+ void CreateFromDirectory(string sourceDirectoryName, System.IO.Stream destination, System.IO.Compression.CompressionLevel compressionLevel, bool includeBaseDirectory);
+ void CreateFromDirectory(string sourceDirectoryName, string destinationArchiveFileName, System.IO.Compression.CompressionLevel compressionLevel, bool includeBaseDirectory);
+ void CreateFromDirectory(string sourceDirectoryName, System.IO.Stream destination, System.IO.Compression.CompressionLevel compressionLevel, bool includeBaseDirectory, System.Text.Encoding entryNameEncoding);
+ void CreateFromDirectory(string sourceDirectoryName, string destinationArchiveFileName, System.IO.Compression.CompressionLevel compressionLevel, bool includeBaseDirectory, System.Text.Encoding entryNameEncoding);
+ void ExtractToDirectory(System.IO.Stream source, string destinationDirectoryName);
+ void ExtractToDirectory(string sourceArchiveFileName, string destinationDirectoryName);
+ void ExtractToDirectory(System.IO.Stream source, string destinationDirectoryName, bool overwriteFiles);
+ void ExtractToDirectory(System.IO.Stream source, string destinationDirectoryName, System.Text.Encoding entryNameEncoding);
+ void ExtractToDirectory(string sourceArchiveFileName, string destinationDirectoryName, bool overwriteFiles);
+ void ExtractToDirectory(string sourceArchiveFileName, string destinationDirectoryName, System.Text.Encoding? entryNameEncoding);
+ void ExtractToDirectory(System.IO.Stream source, string destinationDirectoryName, System.Text.Encoding entryNameEncoding, bool overwriteFiles);
+ void ExtractToDirectory(string sourceArchiveFileName, string destinationDirectoryName, System.Text.Encoding? entryNameEncoding, bool overwriteFiles);
+ Testably.Abstractions.IZipArchive Open(string archiveFileName, System.IO.Compression.ZipArchiveMode mode);
+ Testably.Abstractions.IZipArchive Open(string archiveFileName, System.IO.Compression.ZipArchiveMode mode, System.Text.Encoding? entryNameEncoding);
+ Testably.Abstractions.IZipArchive OpenRead(string archiveFileName);
+ }
+}
\ No newline at end of file
diff --git a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Interface_net9.0.txt b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Interface_net9.0.txt
new file mode 100644
index 000000000..a261d7ec3
--- /dev/null
+++ b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Interface_net9.0.txt
@@ -0,0 +1,160 @@
+[assembly: System.CLSCompliant(true)]
+[assembly: System.Reflection.AssemblyMetadata("RepositoryUrl", "https://github.com/Testably/Testably.Abstractions.git")]
+[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v9.0", FrameworkDisplayName=".NET 9.0")]
+namespace Testably.Abstractions.Helpers
+{
+ public abstract class GuidSystemBase : Testably.Abstractions.RandomSystem.IGuid, Testably.Abstractions.RandomSystem.IRandomSystemEntity
+ {
+ protected GuidSystemBase(Testably.Abstractions.IRandomSystem randomSystem) { }
+ public System.Guid Empty { get; }
+ public Testably.Abstractions.IRandomSystem RandomSystem { get; }
+ public abstract System.Guid CreateVersion7();
+ public abstract System.Guid CreateVersion7(System.DateTimeOffset timestamp);
+ public abstract System.Guid NewGuid();
+ public System.Guid Parse(System.ReadOnlySpan input) { }
+ public System.Guid Parse(string input) { }
+ public System.Guid Parse(System.ReadOnlySpan s, System.IFormatProvider? provider) { }
+ public System.Guid Parse(string s, System.IFormatProvider? provider) { }
+ public System.Guid ParseExact(System.ReadOnlySpan input, System.ReadOnlySpan format) { }
+ public System.Guid ParseExact(string input, string format) { }
+ public bool TryParse(System.ReadOnlySpan input, out System.Guid result) { }
+ public bool TryParse(string? input, out System.Guid result) { }
+ public bool TryParse(System.ReadOnlySpan s, System.IFormatProvider? provider, out System.Guid result) { }
+ public bool TryParse(string? s, System.IFormatProvider? provider, out System.Guid result) { }
+ public bool TryParseExact(System.ReadOnlySpan input, System.ReadOnlySpan format, out System.Guid result) { }
+ public bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? format, out System.Guid result) { }
+ }
+ public interface IFileSystemExtensibility
+ {
+ T? RetrieveMetadata(string key);
+ void StoreMetadata(string key, T? value);
+ bool TryGetWrappedInstance([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out T? wrappedInstance);
+ }
+ public sealed class RandomWrapper : Testably.Abstractions.RandomSystem.IRandom
+ {
+ public RandomWrapper(System.Random instance) { }
+ public T[] GetItems(System.ReadOnlySpan choices, int length) { }
+ public void GetItems(System.ReadOnlySpan choices, System.Span destination) { }
+ public T[] GetItems(T[] choices, int length) { }
+ public int Next() { }
+ public int Next(int maxValue) { }
+ public int Next(int minValue, int maxValue) { }
+ public void NextBytes(byte[] buffer) { }
+ public void NextBytes(System.Span buffer) { }
+ public double NextDouble() { }
+ public long NextInt64() { }
+ public long NextInt64(long maxValue) { }
+ public long NextInt64(long minValue, long maxValue) { }
+ public float NextSingle() { }
+ public void Shuffle(System.Span values) { }
+ public void Shuffle(T[] values) { }
+ }
+}
+namespace Testably.Abstractions
+{
+ public interface IRandomSystem
+ {
+ Testably.Abstractions.RandomSystem.IGuid Guid { get; }
+ Testably.Abstractions.RandomSystem.IRandomFactory Random { get; }
+ }
+ public interface ITimeSystem
+ {
+ Testably.Abstractions.TimeSystem.IDateTime DateTime { get; }
+ Testably.Abstractions.TimeSystem.ITask Task { get; }
+ Testably.Abstractions.TimeSystem.IThread Thread { get; }
+ Testably.Abstractions.TimeSystem.ITimerFactory Timer { get; }
+ }
+}
+namespace Testably.Abstractions.RandomSystem
+{
+ public interface IGuid : Testably.Abstractions.RandomSystem.IRandomSystemEntity
+ {
+ System.Guid Empty { get; }
+ System.Guid CreateVersion7();
+ System.Guid CreateVersion7(System.DateTimeOffset timestamp);
+ System.Guid NewGuid();
+ System.Guid Parse(System.ReadOnlySpan input);
+ System.Guid Parse(string input);
+ System.Guid Parse(System.ReadOnlySpan s, System.IFormatProvider? provider);
+ System.Guid Parse(string s, System.IFormatProvider? provider);
+ System.Guid ParseExact(System.ReadOnlySpan input, System.ReadOnlySpan format);
+ System.Guid ParseExact(string input, string format);
+ bool TryParse(System.ReadOnlySpan input, out System.Guid result);
+ bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, out System.Guid result);
+ bool TryParse(System.ReadOnlySpan s, System.IFormatProvider? provider, out System.Guid result);
+ bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? s, System.IFormatProvider? provider, out System.Guid result);
+ bool TryParseExact(System.ReadOnlySpan input, System.ReadOnlySpan format, out System.Guid result);
+ bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? format, out System.Guid result);
+ }
+ public interface IRandom
+ {
+ T[] GetItems(System.ReadOnlySpan choices, int length);
+ void GetItems(System.ReadOnlySpan choices, System.Span destination);
+ T[] GetItems(T[] choices, int length);
+ int Next();
+ int Next(int maxValue);
+ int Next(int minValue, int maxValue);
+ void NextBytes(byte[] buffer);
+ void NextBytes(System.Span buffer);
+ double NextDouble();
+ long NextInt64();
+ long NextInt64(long maxValue);
+ long NextInt64(long minValue, long maxValue);
+ float NextSingle();
+ void Shuffle(System.Span values);
+ void Shuffle(T[] values);
+ }
+ public interface IRandomFactory : Testably.Abstractions.RandomSystem.IRandomSystemEntity
+ {
+ Testably.Abstractions.RandomSystem.IRandom Shared { get; }
+ Testably.Abstractions.RandomSystem.IRandom New();
+ Testably.Abstractions.RandomSystem.IRandom New(int seed);
+ }
+ public interface IRandomSystemEntity
+ {
+ Testably.Abstractions.IRandomSystem RandomSystem { get; }
+ }
+}
+namespace Testably.Abstractions.TimeSystem
+{
+ public interface IDateTime : Testably.Abstractions.TimeSystem.ITimeSystemEntity
+ {
+ System.DateTime MaxValue { get; }
+ System.DateTime MinValue { get; }
+ System.DateTime Now { get; }
+ System.DateTime Today { get; }
+ System.DateTime UnixEpoch { get; }
+ System.DateTime UtcNow { get; }
+ }
+ public interface ITask : Testably.Abstractions.TimeSystem.ITimeSystemEntity
+ {
+ System.Threading.Tasks.Task Delay(int millisecondsDelay);
+ System.Threading.Tasks.Task Delay(System.TimeSpan delay);
+ System.Threading.Tasks.Task Delay(int millisecondsDelay, System.Threading.CancellationToken cancellationToken);
+ System.Threading.Tasks.Task Delay(System.TimeSpan delay, System.Threading.CancellationToken cancellationToken);
+ }
+ public interface IThread : Testably.Abstractions.TimeSystem.ITimeSystemEntity
+ {
+ void Sleep(int millisecondsTimeout);
+ void Sleep(System.TimeSpan timeout);
+ }
+ public interface ITimeSystemEntity
+ {
+ Testably.Abstractions.ITimeSystem TimeSystem { get; }
+ }
+ public interface ITimer : System.IAsyncDisposable, System.IDisposable, Testably.Abstractions.TimeSystem.ITimeSystemEntity
+ {
+ bool Change(int dueTime, int period);
+ bool Change(long dueTime, long period);
+ bool Change(System.TimeSpan dueTime, System.TimeSpan period);
+ bool Dispose(System.Threading.WaitHandle notifyObject);
+ }
+ public interface ITimerFactory : Testably.Abstractions.TimeSystem.ITimeSystemEntity
+ {
+ Testably.Abstractions.TimeSystem.ITimer New(System.Threading.TimerCallback callback);
+ Testably.Abstractions.TimeSystem.ITimer New(System.Threading.TimerCallback callback, object? state, int dueTime, int period);
+ Testably.Abstractions.TimeSystem.ITimer New(System.Threading.TimerCallback callback, object? state, long dueTime, long period);
+ Testably.Abstractions.TimeSystem.ITimer New(System.Threading.TimerCallback callback, object? state, System.TimeSpan dueTime, System.TimeSpan period);
+ Testably.Abstractions.TimeSystem.ITimer Wrap(System.Threading.Timer timer);
+ }
+}
\ No newline at end of file
diff --git a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net9.0.txt b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net9.0.txt
new file mode 100644
index 000000000..1822d8f1b
--- /dev/null
+++ b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net9.0.txt
@@ -0,0 +1,420 @@
+[assembly: System.CLSCompliant(true)]
+[assembly: System.Reflection.AssemblyMetadata("RepositoryUrl", "https://github.com/Testably/Testably.Abstractions.git")]
+[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Testably.Abstractions.Testing.Tests")]
+[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v9.0", FrameworkDisplayName=".NET 9.0")]
+namespace Testably.Abstractions.Testing.FileSystem
+{
+ public class ChangeDescription
+ {
+ public System.IO.WatcherChangeTypes ChangeType { get; }
+ public Testably.Abstractions.Testing.FileSystemTypes FileSystemType { get; }
+ public string? Name { get; }
+ public System.IO.NotifyFilters NotifyFilters { get; }
+ public string? OldName { get; }
+ public string? OldPath { get; }
+ public string Path { get; }
+ public override string ToString() { }
+ }
+ public class DefaultAccessControlStrategy : Testably.Abstractions.Testing.FileSystem.IAccessControlStrategy
+ {
+ public DefaultAccessControlStrategy(System.Func callback) { }
+ public bool IsAccessGranted(string fullPath, Testably.Abstractions.Helpers.IFileSystemExtensibility extensibility) { }
+ }
+ public class DefaultSafeFileHandleStrategy : Testably.Abstractions.Testing.FileSystem.ISafeFileHandleStrategy
+ {
+ public DefaultSafeFileHandleStrategy(System.Func callback) { }
+ [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification="SafeFileHandle cannot be unit tested.")]
+ public Testably.Abstractions.Testing.FileSystem.SafeFileHandleMock MapSafeFileHandle(Microsoft.Win32.SafeHandles.SafeFileHandle fileHandle) { }
+ }
+ public interface IAccessControlStrategy
+ {
+ bool IsAccessGranted(string fullPath, Testably.Abstractions.Helpers.IFileSystemExtensibility extensibility);
+ }
+ public interface IInterceptionHandler : System.IO.Abstractions.IFileSystemEntity
+ {
+ Testably.Abstractions.Testing.IAwaitableCallback Event(System.Action interceptionCallback, System.Func? predicate = null);
+ }
+ public interface INotificationHandler : System.IO.Abstractions.IFileSystemEntity
+ {
+ Testably.Abstractions.Testing.IAwaitableCallback OnEvent(System.Action? notificationCallback = null, System.Func? predicate = null);
+ }
+ public interface ISafeFileHandleStrategy
+ {
+ Testably.Abstractions.Testing.FileSystem.SafeFileHandleMock MapSafeFileHandle(Microsoft.Win32.SafeHandles.SafeFileHandle fileHandle);
+ }
+ public class NullAccessControlStrategy : Testably.Abstractions.Testing.FileSystem.IAccessControlStrategy
+ {
+ public NullAccessControlStrategy() { }
+ public bool IsAccessGranted(string fullPath, Testably.Abstractions.Helpers.IFileSystemExtensibility extensibility) { }
+ }
+ public class NullSafeFileHandleStrategy : Testably.Abstractions.Testing.FileSystem.ISafeFileHandleStrategy
+ {
+ public NullSafeFileHandleStrategy() { }
+ [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification="SafeFileHandle cannot be unit tested.")]
+ public Testably.Abstractions.Testing.FileSystem.SafeFileHandleMock MapSafeFileHandle(Microsoft.Win32.SafeHandles.SafeFileHandle fileHandle) { }
+ }
+ public class SafeFileHandleMock
+ {
+ public SafeFileHandleMock(string path, System.IO.FileMode mode = 3, System.IO.FileShare share = 0) { }
+ public System.IO.FileMode Mode { get; }
+ public string Path { get; }
+ public System.IO.FileShare Share { get; }
+ }
+}
+namespace Testably.Abstractions.Testing
+{
+ public static class FileSystemInitializerExtensions
+ {
+ public static Testably.Abstractions.Testing.Initializer.IFileSystemInitializer Initialize(this TFileSystem fileSystem, System.Action? options = null)
+ where TFileSystem : System.IO.Abstractions.IFileSystem { }
+ public static void InitializeEmbeddedResourcesFromAssembly(this System.IO.Abstractions.IFileSystem fileSystem, string directoryPath, System.Reflection.Assembly assembly, string? relativePath = null, string searchPattern = "*", System.IO.SearchOption searchOption = 1) { }
+ public static Testably.Abstractions.Testing.Initializer.IFileSystemInitializer InitializeIn(this TFileSystem fileSystem, string basePath, System.Action? options = null)
+ where TFileSystem : System.IO.Abstractions.IFileSystem { }
+ public static Testably.Abstractions.Testing.Initializer.IDirectoryCleaner SetCurrentDirectoryToEmptyTemporaryDirectory(this System.IO.Abstractions.IFileSystem fileSystem, string? prefix = null, System.Action? logger = null) { }
+ }
+ public class FileSystemInitializerOptions
+ {
+ public FileSystemInitializerOptions() { }
+ public bool InitializeTempDirectory { get; set; }
+ }
+ [System.Flags]
+ public enum FileSystemTypes
+ {
+ Directory = 1,
+ File = 2,
+ DirectoryOrFile = 3,
+ }
+ public interface IAwaitableCallback : System.IDisposable
+ {
+ void Wait(System.Func? filter = null, int timeout = 30000, int count = 1, System.Action? executeWhenWaiting = null);
+ }
+ public static class InterceptionHandlerExtensions
+ {
+ public static Testably.Abstractions.Testing.IAwaitableCallback Changing(this Testably.Abstractions.Testing.FileSystem.IInterceptionHandler handler, Testably.Abstractions.Testing.FileSystemTypes fileSystemType, System.Action interceptionCallback, string globPattern = "*", System.Func? predicate = null) { }
+ public static Testably.Abstractions.Testing.IAwaitableCallback Creating(this Testably.Abstractions.Testing.FileSystem.IInterceptionHandler handler, Testably.Abstractions.Testing.FileSystemTypes fileSystemType, System.Action interceptionCallback, string globPattern = "*", System.Func? predicate = null) { }
+ public static Testably.Abstractions.Testing.IAwaitableCallback Deleting(this Testably.Abstractions.Testing.FileSystem.IInterceptionHandler handler, Testably.Abstractions.Testing.FileSystemTypes fileSystemType, System.Action interceptionCallback, string globPattern = "*", System.Func? predicate = null) { }
+ }
+ public sealed class MockFileSystem : System.IO.Abstractions.IFileSystem
+ {
+ public MockFileSystem() { }
+ public MockFileSystem(System.Func options) { }
+ public System.IO.Abstractions.IDirectory Directory { get; }
+ public System.IO.Abstractions.IDirectoryInfoFactory DirectoryInfo { get; }
+ public System.IO.Abstractions.IDriveInfoFactory DriveInfo { get; }
+ public System.IO.Abstractions.IFile File { get; }
+ public System.IO.Abstractions.IFileInfoFactory FileInfo { get; }
+ public System.IO.Abstractions.IFileStreamFactory FileStream { get; }
+ public System.IO.Abstractions.IFileSystemWatcherFactory FileSystemWatcher { get; }
+ public System.IO.Abstractions.IFileVersionInfoFactory FileVersionInfo { get; }
+ public Testably.Abstractions.Testing.FileSystem.IInterceptionHandler Intercept { get; }
+ public Testably.Abstractions.Testing.FileSystem.INotificationHandler Notify { get; }
+ public System.IO.Abstractions.IPath Path { get; }
+ public Testably.Abstractions.IRandomSystem RandomSystem { get; }
+ public Testably.Abstractions.Testing.SimulationMode SimulationMode { get; }
+ public Testably.Abstractions.Testing.Statistics.IFileSystemStatistics Statistics { get; }
+ public Testably.Abstractions.ITimeSystem TimeSystem { get; }
+ public override string ToString() { }
+ public Testably.Abstractions.Testing.MockFileSystem WithAccessControlStrategy(Testably.Abstractions.Testing.FileSystem.IAccessControlStrategy accessControlStrategy) { }
+ public Testably.Abstractions.Testing.MockFileSystem WithDrive(string? drive, System.Action? driveCallback = null) { }
+ public Testably.Abstractions.Testing.MockFileSystem WithFileVersionInfo(string globPattern, System.Action fileVersionInfoBuilder) { }
+ public Testably.Abstractions.Testing.MockFileSystem WithSafeFileHandleStrategy(Testably.Abstractions.Testing.FileSystem.ISafeFileHandleStrategy safeFileHandleStrategy) { }
+ public class MockFileSystemOptions
+ {
+ public MockFileSystemOptions() { }
+ public Testably.Abstractions.Testing.MockFileSystem.MockFileSystemOptions SimulatingOperatingSystem(Testably.Abstractions.Testing.SimulationMode simulationMode) { }
+ public Testably.Abstractions.Testing.MockFileSystem.MockFileSystemOptions UseCurrentDirectory() { }
+ public Testably.Abstractions.Testing.MockFileSystem.MockFileSystemOptions UseCurrentDirectory(string path) { }
+ public Testably.Abstractions.Testing.MockFileSystem.MockFileSystemOptions UseRandomProvider(Testably.Abstractions.Testing.RandomSystem.IRandomProvider randomProvider) { }
+ }
+ }
+ public static class MockFileSystemExtensions
+ {
+ public static System.IO.Abstractions.IDriveInfo GetDefaultDrive(this Testably.Abstractions.Testing.MockFileSystem mockFileSystem) { }
+ public static Testably.Abstractions.Testing.MockFileSystem WithDrive(this Testably.Abstractions.Testing.MockFileSystem mockFileSystem, System.Action driveCallback) { }
+ public static Testably.Abstractions.Testing.MockFileSystem WithUncDrive(this Testably.Abstractions.Testing.MockFileSystem mockFileSystem, string server, System.Action? driveCallback = null) { }
+ }
+ public sealed class MockRandomSystem : Testably.Abstractions.IRandomSystem
+ {
+ public MockRandomSystem() { }
+ public MockRandomSystem(Testably.Abstractions.Testing.RandomSystem.IRandomProvider randomProvider) { }
+ public Testably.Abstractions.RandomSystem.IGuid Guid { get; }
+ public Testably.Abstractions.RandomSystem.IRandomFactory Random { get; }
+ public Testably.Abstractions.Testing.RandomSystem.IRandomProvider RandomProvider { get; }
+ public override string ToString() { }
+ }
+ public sealed class MockTimeSystem : Testably.Abstractions.ITimeSystem
+ {
+ public MockTimeSystem() { }
+ public MockTimeSystem(System.DateTime time) { }
+ public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProvider timeProvider) { }
+ public Testably.Abstractions.TimeSystem.IDateTime DateTime { get; }
+ public Testably.Abstractions.Testing.TimeSystem.INotificationHandler On { get; }
+ public Testably.Abstractions.TimeSystem.ITask Task { get; }
+ public Testably.Abstractions.TimeSystem.IThread Thread { get; }
+ public Testably.Abstractions.Testing.TimeSystem.ITimeProvider TimeProvider { get; }
+ public Testably.Abstractions.TimeSystem.ITimerFactory Timer { get; }
+ public Testably.Abstractions.Testing.TimeSystem.ITimerHandler TimerHandler { get; }
+ public override string ToString() { }
+ public Testably.Abstractions.Testing.MockTimeSystem WithTimerStrategy(Testably.Abstractions.Testing.TimeSystem.ITimerStrategy timerStrategy) { }
+ }
+ public static class Notification
+ {
+ public static Testably.Abstractions.Testing.IAwaitableCallback ExecuteWhileWaiting(this Testably.Abstractions.Testing.IAwaitableCallback awaitable, System.Action callback) { }
+ public static Testably.Abstractions.Testing.Notification.IAwaitableCallback ExecuteWhileWaiting(this Testably.Abstractions.Testing.IAwaitableCallback awaitable, System.Func callback) { }
+ public interface IAwaitableCallback : System.IDisposable, Testably.Abstractions.Testing.IAwaitableCallback
+ {
+ TFunc Wait(System.Func? filter = null, int timeout = 30000, int count = 1, System.Action? executeWhenWaiting = null);
+ }
+ }
+ public static class NotificationHandlerExtensions
+ {
+ public static Testably.Abstractions.Testing.IAwaitableCallback OnChanged(this Testably.Abstractions.Testing.FileSystem.INotificationHandler handler, Testably.Abstractions.Testing.FileSystemTypes fileSystemType, System.Action? notificationCallback = null, string globPattern = "*", System.Func? predicate = null) { }
+ public static Testably.Abstractions.Testing.IAwaitableCallback OnCreated(this Testably.Abstractions.Testing.FileSystem.INotificationHandler handler, Testably.Abstractions.Testing.FileSystemTypes fileSystemType, System.Action? notificationCallback = null, string globPattern = "*", System.Func? predicate = null) { }
+ public static Testably.Abstractions.Testing.IAwaitableCallback OnDeleted(this Testably.Abstractions.Testing.FileSystem.INotificationHandler handler, Testably.Abstractions.Testing.FileSystemTypes fileSystemType, System.Action? notificationCallback = null, string globPattern = "*", System.Func? predicate = null) { }
+ }
+ public static class RandomProvider
+ {
+ public static Testably.Abstractions.Testing.RandomSystem.IRandomProvider Default() { }
+ public static Testably.Abstractions.Testing.RandomSystem.IRandomProvider Generate(int seed = -1, Testably.Abstractions.Testing.RandomProvider.Generator? guidGenerator = null, Testably.Abstractions.Testing.RandomProvider.Generator? intGenerator = null, Testably.Abstractions.Testing.RandomProvider.Generator? longGenerator = null, Testably.Abstractions.Testing.RandomProvider.Generator? singleGenerator = null, Testably.Abstractions.Testing.RandomProvider.Generator? doubleGenerator = null, Testably.Abstractions.Testing.RandomProvider.Generator? byteGenerator = null) { }
+ public abstract class Generator
+ {
+ protected Generator() { }
+ public static Testably.Abstractions.Testing.RandomProvider.Generator FromArray(T[] values) { }
+ public static Testably.Abstractions.Testing.RandomProvider.Generator FromCallback(System.Func callback) { }
+ public static Testably.Abstractions.Testing.RandomProvider.Generator FromEnumerable(System.Collections.Generic.IEnumerable enumerable) { }
+ public static Testably.Abstractions.Testing.RandomProvider.Generator FromValue(T value) { }
+ }
+ public sealed class Generator : Testably.Abstractions.Testing.RandomProvider.Generator, System.IDisposable
+ {
+ public void Dispose() { }
+ public T GetNext() { }
+ public static Testably.Abstractions.Testing.RandomProvider.Generator op_Implicit(System.Func callback) { }
+ public static Testably.Abstractions.Testing.RandomProvider.Generator op_Implicit(T value) { }
+ public static Testably.Abstractions.Testing.RandomProvider.Generator op_Implicit(T[] values) { }
+ }
+ }
+ public enum SimulationMode
+ {
+ Native = 0,
+ Linux = 1,
+ MacOS = 2,
+ Windows = 3,
+ }
+ public static class TimeProvider
+ {
+ public static Testably.Abstractions.Testing.TimeSystem.ITimeProvider Now() { }
+ public static Testably.Abstractions.Testing.TimeSystem.ITimeProvider Random() { }
+ public static Testably.Abstractions.Testing.TimeSystem.ITimeProvider Use(System.DateTime time) { }
+ }
+}
+namespace Testably.Abstractions.Testing.Initializer
+{
+ public class DirectoryDescription : Testably.Abstractions.Testing.Initializer.FileSystemInfoDescription
+ {
+ public DirectoryDescription(string name) { }
+ public DirectoryDescription(string name, params Testably.Abstractions.Testing.Initializer.FileSystemInfoDescription[] children) { }
+ public Testably.Abstractions.Testing.Initializer.FileSystemInfoDescription[] Children { get; }
+ public override Testably.Abstractions.Testing.Initializer.FileSystemInfoDescription this[string path] { get; }
+ }
+ public class FileDescription : Testably.Abstractions.Testing.Initializer.FileSystemInfoDescription
+ {
+ public FileDescription(string name, byte[] bytes) { }
+ public FileDescription(string name, string? content = null) { }
+ public byte[]? Bytes { get; }
+ public string? Content { get; }
+ public bool IsReadOnly { get; set; }
+ public override Testably.Abstractions.Testing.Initializer.FileSystemInfoDescription this[string? path] { get; }
+ }
+ public abstract class FileSystemInfoDescription
+ {
+ protected FileSystemInfoDescription(string name) { }
+ public abstract Testably.Abstractions.Testing.Initializer.FileSystemInfoDescription this[string path] { get; }
+ public string Name { get; }
+ }
+ public sealed class FileVersionInfoBuilder
+ {
+ public FileVersionInfoBuilder() { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetComments(string? comments) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetCompanyName(string? companyName) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetFileDescription(string? fileDescription) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetFileVersion(string? fileVersion) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetInternalName(string? internalName) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetIsDebug(bool isDebug) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetIsPatched(bool isPatched) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetIsPreRelease(bool isPreRelease) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetIsPrivateBuild(bool isPrivateBuild) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetIsSpecialBuild(bool isSpecialBuild) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetLanguage(string? language) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetLegalCopyright(string? legalCopyright) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetLegalTrademarks(string? legalTrademarks) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetOriginalFilename(string? originalFilename) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetPrivateBuild(string? privateBuild) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetProductName(string? productName) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetProductVersion(string? productVersion) { }
+ public Testably.Abstractions.Testing.Initializer.FileVersionInfoBuilder SetSpecialBuild(string? specialBuild) { }
+ }
+ public interface IDirectoryCleaner : System.IDisposable
+ {
+ string BasePath { get; }
+ }
+ public interface IFileManipulator : System.IO.Abstractions.IFileSystemEntity
+ {
+ System.IO.Abstractions.IFileInfo File { get; }
+ Testably.Abstractions.Testing.Initializer.IFileManipulator HasBytesContent(byte[] bytes);
+ Testably.Abstractions.Testing.Initializer.IFileManipulator HasStringContent(string contents);
+ }
+ public interface IFileSystemDirectoryInitializer : Testably.Abstractions.Testing.Initializer.IFileSystemInitializer
+ where out TFileSystem : System.IO.Abstractions.IFileSystem
+ {
+ System.IO.Abstractions.IDirectoryInfo Directory { get; }
+ Testably.Abstractions.Testing.Initializer.IFileSystemDirectoryInitializer Initialized(System.Action> subdirectoryInitializer);
+ }
+ public interface IFileSystemFileInitializer : Testably.Abstractions.Testing.Initializer.IFileSystemInitializer
+ where out TFileSystem : System.IO.Abstractions.IFileSystem
+ {
+ System.IO.Abstractions.IFileInfo File { get; }
+ Testably.Abstractions.Testing.Initializer.IFileSystemFileInitializer Which(System.Action fileManipulation);
+ }
+ public interface IFileSystemInitializer
+ where out TFileSystem : System.IO.Abstractions.IFileSystem
+ {
+ System.IO.Abstractions.IDirectoryInfo BaseDirectory { get; }
+ TFileSystem FileSystem { get; }
+ System.IO.Abstractions.IFileSystemInfo this[int index] { get; }
+ Testably.Abstractions.Testing.Initializer.IFileSystemInitializer With(params Testably.Abstractions.Testing.Initializer.FileSystemInfoDescription[] descriptions);
+ Testably.Abstractions.Testing.Initializer.IFileSystemInitializer With(TDescription[] descriptions)
+ where TDescription : Testably.Abstractions.Testing.Initializer.FileSystemInfoDescription;
+ Testably.Abstractions.Testing.Initializer.IFileSystemFileInitializer WithAFile(string? extension = null);
+ Testably.Abstractions.Testing.Initializer.IFileSystemDirectoryInitializer WithASubdirectory();
+ Testably.Abstractions.Testing.Initializer.IFileSystemFileInitializer WithFile(string fileName);
+ Testably.Abstractions.Testing.Initializer.IFileSystemInitializer WithSubdirectories(params string[] paths);
+ Testably.Abstractions.Testing.Initializer.IFileSystemDirectoryInitializer WithSubdirectory(string directoryName);
+ }
+ public class TestingException : System.Exception
+ {
+ public TestingException(string message) { }
+ public TestingException(string message, System.Exception inner) { }
+ }
+}
+namespace Testably.Abstractions.Testing.RandomSystem
+{
+ public interface IRandomProvider
+ {
+ System.Guid GetGuid();
+ Testably.Abstractions.RandomSystem.IRandom GetRandom(int seed = -1);
+ }
+}
+namespace Testably.Abstractions.Testing.Statistics
+{
+ public interface IFileSystemStatistics
+ {
+ Testably.Abstractions.Testing.Statistics.IStatistics Directory { get; }
+ Testably.Abstractions.Testing.Statistics.IPathStatistics DirectoryInfo { get; }
+ Testably.Abstractions.Testing.Statistics.IPathStatistics DriveInfo { get; }
+ Testably.Abstractions.Testing.Statistics.IStatistics File { get; }
+ Testably.Abstractions.Testing.Statistics.IPathStatistics FileInfo { get; }
+ Testably.Abstractions.Testing.Statistics.IPathStatistics FileStream { get; }
+ Testably.Abstractions.Testing.Statistics.IPathStatistics FileSystemWatcher { get; }
+ Testably.Abstractions.Testing.Statistics.IPathStatistics FileVersionInfo { get; }
+ Testably.Abstractions.Testing.Statistics.IStatistics Path { get; }
+ int TotalCount { get; }
+ }
+ public interface IPathStatistics : Testably.Abstractions.Testing.Statistics.IStatistics, Testably.Abstractions.Testing.Statistics.IStatistics
+ {
+ Testably.Abstractions.Testing.Statistics.IStatistics this[string path] { get; }
+ }
+ public interface IStatistics
+ {
+ Testably.Abstractions.Testing.Statistics.MethodStatistic[] Methods { get; }
+ Testably.Abstractions.Testing.Statistics.PropertyStatistic[] Properties { get; }
+ }
+ public interface IStatistics : Testably.Abstractions.Testing.Statistics.IStatistics { }
+ public sealed class MethodStatistic
+ {
+ public int Counter { get; }
+ public string Name { get; }
+ public Testably.Abstractions.Testing.Statistics.ParameterDescription[] Parameters { get; }
+ public override string ToString() { }
+ }
+ public abstract class ParameterDescription
+ {
+ protected ParameterDescription(bool isOutParameter) { }
+ public bool IsOutParameter { get; }
+ public bool Is(System.Func comparer) { }
+ public bool Is(System.ReadOnlySpan value) { }
+ public bool Is(System.Span value) { }
+ public bool Is(T value) { }
+ public bool Is(T[] value) { }
+ public static Testably.Abstractions.Testing.Statistics.ParameterDescription FromOutParameter(T value) { }
+ public static Testably.Abstractions.Testing.Statistics.ParameterDescription FromParameter(System.ReadOnlySpan value) { }
+ public static Testably.Abstractions.Testing.Statistics.ParameterDescription FromParameter(System.Span value) { }
+ public static Testably.Abstractions.Testing.Statistics.ParameterDescription FromParameter(T value) { }
+ }
+ public enum PropertyAccess
+ {
+ Get = 0,
+ Set = 1,
+ }
+ public sealed class PropertyStatistic
+ {
+ public Testably.Abstractions.Testing.Statistics.PropertyAccess Access { get; }
+ public int Counter { get; }
+ public string Name { get; }
+ public override string ToString() { }
+ }
+}
+namespace Testably.Abstractions.Testing.Storage
+{
+ public interface IStorageDrive : System.IO.Abstractions.IDriveInfo, System.IO.Abstractions.IFileSystemEntity
+ {
+ bool IsUncPath { get; }
+ Testably.Abstractions.Testing.Storage.IStorageDrive ChangeUsedBytes(long usedBytesDelta);
+ Testably.Abstractions.Testing.Storage.IStorageDrive SetDriveFormat(string driveFormat = "NTFS");
+ Testably.Abstractions.Testing.Storage.IStorageDrive SetDriveType(System.IO.DriveType driveType = 3);
+ Testably.Abstractions.Testing.Storage.IStorageDrive SetIsReady(bool isReady = true);
+ Testably.Abstractions.Testing.Storage.IStorageDrive SetTotalSize(long totalSize = 1073741824);
+ }
+}
+namespace Testably.Abstractions.Testing.TimeSystem
+{
+ public interface INotificationHandler
+ {
+ Testably.Abstractions.Testing.IAwaitableCallback DateTimeRead(System.Action? callback = null, System.Func? predicate = null);
+ Testably.Abstractions.Testing.IAwaitableCallback TaskDelay(System.Action? callback = null, System.Func? predicate = null);
+ Testably.Abstractions.Testing.IAwaitableCallback ThreadSleep(System.Action? callback = null, System.Func? predicate = null);
+ }
+ public interface ITimeProvider
+ {
+ System.DateTime MaxValue { get; set; }
+ System.DateTime MinValue { get; set; }
+ System.DateTime UnixEpoch { get; set; }
+ void AdvanceBy(System.TimeSpan interval);
+ System.DateTime Read();
+ void SetTo(System.DateTime value);
+ }
+ public interface ITimerHandler
+ {
+ Testably.Abstractions.Testing.TimeSystem.ITimerMock this[int index] { get; }
+ }
+ public interface ITimerMock : System.IAsyncDisposable, System.IDisposable, Testably.Abstractions.TimeSystem.ITimeSystemEntity, Testably.Abstractions.TimeSystem.ITimer
+ {
+ Testably.Abstractions.Testing.TimeSystem.ITimerMock Wait(int executionCount = 1, int timeout = 10000, System.Action? callback = null);
+ }
+ public interface ITimerStrategy
+ {
+ Testably.Abstractions.Testing.TimeSystem.TimerMode Mode { get; }
+ bool SwallowExceptions { get; }
+ }
+ public enum TimerMode
+ {
+ StartImmediately = 1,
+ StartOnMockWait = 2,
+ }
+ public class TimerStrategy : Testably.Abstractions.Testing.TimeSystem.ITimerStrategy
+ {
+ public TimerStrategy(Testably.Abstractions.Testing.TimeSystem.TimerMode mode = 1, bool swallowExceptions = false) { }
+ public Testably.Abstractions.Testing.TimeSystem.TimerMode Mode { get; }
+ public bool SwallowExceptions { get; }
+ public static Testably.Abstractions.Testing.TimeSystem.ITimerStrategy Default { get; }
+ }
+}
\ No newline at end of file
diff --git a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions_net9.0.txt b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions_net9.0.txt
new file mode 100644
index 000000000..cc57bd753
--- /dev/null
+++ b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions_net9.0.txt
@@ -0,0 +1,34 @@
+[assembly: System.CLSCompliant(true)]
+[assembly: System.Reflection.AssemblyMetadata("RepositoryUrl", "https://github.com/Testably/Testably.Abstractions.git")]
+[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Testably.Abstractions.Tests")]
+[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v9.0", FrameworkDisplayName=".NET 9.0")]
+namespace Testably.Abstractions
+{
+ public sealed class RealFileSystem : System.IO.Abstractions.IFileSystem
+ {
+ public RealFileSystem() { }
+ public System.IO.Abstractions.IDirectory Directory { get; }
+ public System.IO.Abstractions.IDirectoryInfoFactory DirectoryInfo { get; }
+ public System.IO.Abstractions.IDriveInfoFactory DriveInfo { get; }
+ public System.IO.Abstractions.IFile File { get; }
+ public System.IO.Abstractions.IFileInfoFactory FileInfo { get; }
+ public System.IO.Abstractions.IFileStreamFactory FileStream { get; }
+ public System.IO.Abstractions.IFileSystemWatcherFactory FileSystemWatcher { get; }
+ public System.IO.Abstractions.IFileVersionInfoFactory FileVersionInfo { get; }
+ public System.IO.Abstractions.IPath Path { get; }
+ }
+ public sealed class RealRandomSystem : Testably.Abstractions.IRandomSystem
+ {
+ public RealRandomSystem() { }
+ public Testably.Abstractions.RandomSystem.IGuid Guid { get; }
+ public Testably.Abstractions.RandomSystem.IRandomFactory Random { get; }
+ }
+ public sealed class RealTimeSystem : Testably.Abstractions.ITimeSystem
+ {
+ public RealTimeSystem() { }
+ public Testably.Abstractions.TimeSystem.IDateTime DateTime { get; }
+ public Testably.Abstractions.TimeSystem.ITask Task { get; }
+ public Testably.Abstractions.TimeSystem.IThread Thread { get; }
+ public Testably.Abstractions.TimeSystem.ITimerFactory Timer { get; }
+ }
+}
\ No newline at end of file
diff --git a/Tests/Directory.Build.props b/Tests/Directory.Build.props
index 3590f1f85..9ce367335 100644
--- a/Tests/Directory.Build.props
+++ b/Tests/Directory.Build.props
@@ -5,8 +5,8 @@
- net6.0;net8.0;net48
- net6.0;net8.0
+ net6.0;net8.0;net9.0;net48
+ net6.0;net8.0;net9.0
net48
diff --git a/Tests/Helpers/Testably.Abstractions.TestHelpers/AutoDomainDataAttribute.cs b/Tests/Helpers/Testably.Abstractions.TestHelpers/AutoDomainDataAttribute.cs
index 557353ca6..7f744b7b1 100644
--- a/Tests/Helpers/Testably.Abstractions.TestHelpers/AutoDomainDataAttribute.cs
+++ b/Tests/Helpers/Testably.Abstractions.TestHelpers/AutoDomainDataAttribute.cs
@@ -1,35 +1,20 @@
using AutoFixture;
-using AutoFixture.Xunit3;
using AutoFixture.AutoNSubstitute;
+using AutoFixture.Xunit3;
using System;
-using System.Linq;
using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
namespace Testably.Abstractions.TestHelpers;
///
-/// Extension of that uses applies domain-specific customizations.
+/// Extension of that uses applies domain-specific customizations.
///
public class AutoDomainDataAttribute : AutoDataAttribute
{
- private Type? _customizeWith;
- private readonly DomainFixtureFactory _fixtureFactory;
-
- ///
- /// Extension of that uses applies domain-specific customizations.
- ///
- public AutoDomainDataAttribute() : this(new DomainFixtureFactory())
- {
- }
-
- private AutoDomainDataAttribute(DomainFixtureFactory fixtureFactory)
- : base(fixtureFactory.GetFixtureFactory)
- {
- _fixtureFactory = fixtureFactory;
- }
-
///
- /// Adds an additional that is applied for only this test.
+ /// Adds an additional that is applied for only this test.
///
public Type? CustomizeWith
{
@@ -44,31 +29,32 @@ public Type? CustomizeWith
}
}
+ private Type? _customizeWith;
+ private readonly DomainFixtureFactory _fixtureFactory;
+
+ ///
+ /// Extension of that uses applies domain-specific customizations.
+ ///
+ public AutoDomainDataAttribute() : this(new DomainFixtureFactory())
+ {
+ }
+
+ private AutoDomainDataAttribute(DomainFixtureFactory fixtureFactory)
+ : base(fixtureFactory.GetFixtureFactory)
+ {
+ _fixtureFactory = fixtureFactory;
+ }
+
private sealed class DomainFixtureFactory
{
- private ICustomization? _customizeWith;
private static Lazy _domainCustomisation { get; } = new(Initialize);
-
- public Fixture GetFixtureFactory()
- {
- var fixture = new Fixture();
- fixture.Customize(new AutoNSubstituteCustomization());
- foreach (var domainCustomization in _domainCustomisation.Value)
- {
- domainCustomization.Customize(fixture);
- }
- if (_customizeWith != null)
- {
- fixture.Customize(_customizeWith);
- }
- return fixture;
- }
+ private ICustomization? _customizeWith;
public void CustomizeWith(Type? type)
{
Type customizationInterface = typeof(ICustomization);
if (type != null &&
- customizationInterface.IsAssignableFrom(type))
+ customizationInterface.IsAssignableFrom(type))
{
try
{
@@ -82,28 +68,58 @@ public void CustomizeWith(Type? type)
}
}
+ public Fixture GetFixtureFactory()
+ {
+ Fixture fixture = new();
+ fixture.Customize(new AutoNSubstituteCustomization());
+ foreach (ICustomization domainCustomization in _domainCustomisation.Value)
+ {
+ domainCustomization.Customize(fixture);
+ }
+
+ if (_customizeWith != null)
+ {
+ fixture.Customize(_customizeWith);
+ }
+
+ return fixture;
+ }
+
private static ICustomization[] Initialize()
{
List domainCustomizations = new();
Type autoDataCustomizationInterface = typeof(IAutoDataCustomization);
- foreach (Type type in AppDomain.CurrentDomain.GetAssemblies()
- .SelectMany(a => a.GetTypes())
- .Where(x => x.IsClass && autoDataCustomizationInterface.IsAssignableFrom(x)))
+ foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
- IAutoDataCustomization? domainCustomization = (IAutoDataCustomization?)Activator.CreateInstance(type);
- if (domainCustomization != null)
+ foreach (Type type in assembly.GetTypes()
+ .Where(x => x.IsClass &&
+ autoDataCustomizationInterface.IsAssignableFrom(x)))
{
- domainCustomizations.Add(domainCustomization);
+ try
+ {
+ IAutoDataCustomization? domainCustomization =
+ (IAutoDataCustomization?)Activator.CreateInstance(type);
+ if (domainCustomization != null)
+ {
+ domainCustomizations.Add(domainCustomization);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException(
+ $"Could not instantiate auto data customization '{type.Name}'!",
+ ex);
+ }
}
}
- catch (Exception ex)
+ catch (ReflectionTypeLoadException)
{
- throw new InvalidOperationException(
- $"Could not instantiate auto data customization '{type.Name}'!", ex);
+ // Ignore assemblies that can't be loaded
}
}
+
return domainCustomizations.ToArray();
}
}
diff --git a/Tests/Settings/Testably.Abstractions.TestSettings/Helper.cs b/Tests/Settings/Testably.Abstractions.TestSettings/Helper.cs
index 9b01b87f3..086f91030 100644
--- a/Tests/Settings/Testably.Abstractions.TestSettings/Helper.cs
+++ b/Tests/Settings/Testably.Abstractions.TestSettings/Helper.cs
@@ -35,7 +35,7 @@ public static TestEnvironment ChangeTestSettings(
}
private static string GetTestSettingsPath() =>
- Path.GetFullPath(Path.Combine("..", "..", "..", "..", "test.settings.json"));
+ Path.GetFullPath(Path.Combine("..", "..", "..", "..", "..", "test.settings.json"));
private static TestEnvironment ReadTestSettings()
{
diff --git a/Tests/Testably.Abstractions.Parity.Tests/Net9ParityTests.cs b/Tests/Testably.Abstractions.Parity.Tests/Net9ParityTests.cs
new file mode 100644
index 000000000..80cab2232
--- /dev/null
+++ b/Tests/Testably.Abstractions.Parity.Tests/Net9ParityTests.cs
@@ -0,0 +1,17 @@
+#if NET9_0
+using System.IO;
+
+namespace Testably.Abstractions.Parity.Tests;
+
+// ReSharper disable once UnusedMember.Global
+public class Net9ParityTests : ParityTests
+{
+ public Net9ParityTests(ITestOutputHelper testOutputHelper)
+ : base(new TestHelpers.Parity(), testOutputHelper)
+ {
+ Parity.File.MissingMethods.Add(
+ typeof(File).GetMethod(nameof(File.OpenHandle)));
+ }
+}
+
+#endif
diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStatisticsTests.cs
index d671f34ff..b8bff1339 100644
--- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStatisticsTests.cs
+++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStatisticsTests.cs
@@ -17,6 +17,70 @@ namespace Testably.Abstractions.Testing.Tests.Statistics.FileSystem;
public sealed class FileStatisticsTests
{
+#if FEATURE_FILE_SPAN
+ [Fact]
+ public void Method_AppendAllBytes_String_ByteArray_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ string path = "foo";
+ byte[] bytes = "foo"u8.ToArray();
+
+ sut.File.AppendAllBytes(path, bytes);
+
+ sut.Statistics.File.ShouldOnlyContainMethodCall(nameof(IFile.AppendAllBytes),
+ path, bytes);
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ [Fact]
+ public void Method_AppendAllBytes_String_ReadOnlySpanByte_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ string path = "foo";
+ ReadOnlySpan bytes = new();
+
+ sut.File.AppendAllBytes(path, bytes);
+
+ sut.Statistics.File.ShouldOnlyContainMethodCall(nameof(IFile.AppendAllBytes),
+ path, bytes);
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ [Fact]
+ public async Task
+ Method_AppendAllBytesAsync_String_ByteArray_CancellationToken_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ string path = "foo";
+ byte[] bytes = "foo"u8.ToArray();
+ CancellationToken cancellationToken = CancellationToken.None;
+
+ await sut.File.AppendAllBytesAsync(path, bytes, cancellationToken);
+
+ sut.Statistics.File.ShouldOnlyContainMethodCall(nameof(IFile.AppendAllBytesAsync),
+ path, bytes, cancellationToken);
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ [Fact]
+ public async Task
+ Method_AppendAllBytesAsync_String_ReadOnlyMemoryByte_CancellationToken_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ string path = "foo";
+ ReadOnlyMemory bytes = new();
+ CancellationToken cancellationToken = CancellationToken.None;
+
+ await sut.File.AppendAllBytesAsync(path, bytes, cancellationToken);
+
+ sut.Statistics.File.ShouldOnlyContainMethodCall(nameof(IFile.AppendAllBytesAsync),
+ path, bytes, cancellationToken);
+ }
+#endif
+
[Fact]
public void Method_AppendAllLines_String_IEnumerableString_Encoding_ShouldRegisterCall()
{
@@ -83,6 +147,37 @@ public async Task
}
#endif
+#if FEATURE_FILE_SPAN
+ [Fact]
+ public void Method_AppendAllText_String_ReadOnlySpanChar_Encoding_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ string path = "foo";
+ ReadOnlySpan contents = new();
+ Encoding encoding = Encoding.UTF8;
+
+ sut.File.AppendAllText(path, contents, encoding);
+
+ sut.Statistics.File.ShouldOnlyContainMethodCall(nameof(IFile.AppendAllText),
+ path, contents, encoding);
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ [Fact]
+ public void Method_AppendAllText_String_ReadOnlySpanChar_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ string path = "foo";
+ ReadOnlySpan contents = new();
+
+ sut.File.AppendAllText(path, contents);
+
+ sut.Statistics.File.ShouldOnlyContainMethodCall(nameof(IFile.AppendAllText),
+ path, contents);
+ }
+#endif
+
[Fact]
public void Method_AppendAllText_String_String_Encoding_ShouldRegisterCall()
{
@@ -112,6 +207,41 @@ public void Method_AppendAllText_String_String_ShouldRegisterCall()
path, contents);
}
+#if FEATURE_FILE_SPAN
+ [Fact]
+ public async Task
+ Method_AppendAllTextAsync_String_ReadOnlyMemoryChar_CancellationToken_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ string path = "foo";
+ ReadOnlyMemory contents = new();
+ CancellationToken cancellationToken = CancellationToken.None;
+
+ await sut.File.AppendAllTextAsync(path, contents, cancellationToken);
+
+ sut.Statistics.File.ShouldOnlyContainMethodCall(nameof(IFile.AppendAllTextAsync),
+ path, contents, cancellationToken);
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ [Fact]
+ public async Task
+ Method_AppendAllTextAsync_String_ReadOnlyMemoryChar_Encoding_CancellationToken_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ string path = "foo";
+ ReadOnlyMemory contents = new();
+ Encoding encoding = Encoding.UTF8;
+ CancellationToken cancellationToken = CancellationToken.None;
+
+ await sut.File.AppendAllTextAsync(path, contents, encoding, cancellationToken);
+
+ sut.Statistics.File.ShouldOnlyContainMethodCall(nameof(IFile.AppendAllTextAsync),
+ path, contents, encoding, cancellationToken);
+ }
+#endif
+
#if FEATURE_FILESYSTEM_ASYNC
[Fact]
public async Task Method_AppendAllTextAsync_String_String_CancellationToken_ShouldRegisterCall()
@@ -1299,6 +1429,21 @@ public void Method_WriteAllBytes_String_ByteArray_ShouldRegisterCall()
path, bytes);
}
+#if FEATURE_FILE_SPAN
+ [Fact]
+ public void Method_WriteAllBytes_String_ReadOnlySpanByte_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ string path = "foo";
+ ReadOnlySpan bytes = new();
+
+ sut.File.WriteAllBytes(path, bytes);
+
+ sut.Statistics.File.ShouldOnlyContainMethodCall(nameof(IFile.WriteAllBytes),
+ path, bytes);
+ }
+#endif
+
#if FEATURE_FILESYSTEM_ASYNC
[Fact]
public async Task
@@ -1317,6 +1462,23 @@ public async Task
}
#endif
+#if FEATURE_FILE_SPAN
+ [Fact]
+ public async Task
+ Method_WriteAllBytesAsync_String_ReadOnlyMemoryByte_CancellationToken_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ string path = "foo";
+ ReadOnlyMemory bytes = new();
+ CancellationToken cancellationToken = CancellationToken.None;
+
+ await sut.File.WriteAllBytesAsync(path, bytes, cancellationToken);
+
+ sut.Statistics.File.ShouldOnlyContainMethodCall(nameof(IFile.WriteAllBytesAsync),
+ path, bytes, cancellationToken);
+ }
+#endif
+
[Fact]
public void Method_WriteAllLines_String_IEnumerableString_Encoding_ShouldRegisterCall()
{
@@ -1412,6 +1574,37 @@ public async Task
}
#endif
+#if FEATURE_FILE_SPAN
+ [Fact]
+ public void Method_WriteAllText_String_ReadOnlySpanChar_Encoding_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ string path = "foo";
+ ReadOnlySpan contents = new();
+ Encoding encoding = Encoding.UTF8;
+
+ sut.File.WriteAllText(path, contents, encoding);
+
+ sut.Statistics.File.ShouldOnlyContainMethodCall(nameof(IFile.WriteAllText),
+ path, contents, encoding);
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ [Fact]
+ public void Method_WriteAllText_String_ReadOnlySpanChar_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ string path = "foo";
+ ReadOnlySpan contents = new();
+
+ sut.File.WriteAllText(path, contents);
+
+ sut.Statistics.File.ShouldOnlyContainMethodCall(nameof(IFile.WriteAllText),
+ path, contents);
+ }
+#endif
+
[Fact]
public void Method_WriteAllText_String_String_Encoding_ShouldRegisterCall()
{
@@ -1441,6 +1634,41 @@ public void Method_WriteAllText_String_String_ShouldRegisterCall()
path, contents);
}
+#if FEATURE_FILE_SPAN
+ [Fact]
+ public async Task
+ Method_WriteAllTextAsync_String_ReadOnlyMemoryChar_CancellationToken_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ string path = "foo";
+ ReadOnlyMemory contents = new();
+ CancellationToken cancellationToken = CancellationToken.None;
+
+ await sut.File.WriteAllTextAsync(path, contents, cancellationToken);
+
+ sut.Statistics.File.ShouldOnlyContainMethodCall(nameof(IFile.WriteAllTextAsync),
+ path, contents, cancellationToken);
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ [Fact]
+ public async Task
+ Method_WriteAllTextAsync_String_ReadOnlyMemoryChar_Encoding_CancellationToken_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ string path = "foo";
+ ReadOnlyMemory contents = new();
+ Encoding encoding = Encoding.UTF8;
+ CancellationToken cancellationToken = CancellationToken.None;
+
+ await sut.File.WriteAllTextAsync(path, contents, encoding, cancellationToken);
+
+ sut.Statistics.File.ShouldOnlyContainMethodCall(nameof(IFile.WriteAllTextAsync),
+ path, contents, encoding, cancellationToken);
+ }
+#endif
+
#if FEATURE_FILESYSTEM_ASYNC
[Fact]
public async Task Method_WriteAllTextAsync_String_String_CancellationToken_ShouldRegisterCall()
diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/PathStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/PathStatisticsTests.cs
index 48a7be877..6c4562d38 100644
--- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/PathStatisticsTests.cs
+++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/PathStatisticsTests.cs
@@ -21,6 +21,19 @@ public void Method_ChangeExtension_String_String_ShouldRegisterCall()
sut.Statistics.Path.ShouldOnlyContainMethodCall(nameof(IPath.ChangeExtension),
path, extension);
}
+#if FEATURE_PATH_SPAN
+ [Fact]
+ public void Method_Combine_ReadOnlySpanString_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ ReadOnlySpan paths = new();
+
+ sut.Path.Combine(paths);
+
+ sut.Statistics.Path.ShouldOnlyContainMethodCall(nameof(IPath.Combine),
+ paths);
+ }
+#endif
[Fact]
public void Method_Combine_String_String_ShouldRegisterCall()
@@ -503,6 +516,20 @@ public void Method_Join_ReadOnlySpanChar_ReadOnlySpanChar_ShouldRegisterCall()
}
#endif
+#if FEATURE_PATH_SPAN
+ [Fact]
+ public void Method_Join_ReadOnlySpanString_ShouldRegisterCall()
+ {
+ MockFileSystem sut = new();
+ ReadOnlySpan paths = new();
+
+ sut.Path.Join(paths);
+
+ sut.Statistics.Path.ShouldOnlyContainMethodCall(nameof(IPath.Join),
+ paths);
+ }
+#endif
+
#if FEATURE_PATH_JOIN
[Fact]
public void Method_Join_String_String_ShouldRegisterCall()
diff --git a/Tests/Testably.Abstractions.Testing.Tests/TestHelpers/StatisticsTestHelpers.cs b/Tests/Testably.Abstractions.Testing.Tests/TestHelpers/StatisticsTestHelpers.cs
index 73f40f448..465c0ad2f 100644
--- a/Tests/Testably.Abstractions.Testing.Tests/TestHelpers/StatisticsTestHelpers.cs
+++ b/Tests/Testably.Abstractions.Testing.Tests/TestHelpers/StatisticsTestHelpers.cs
@@ -151,6 +151,35 @@ public static void ShouldOnlyContainMethodCall(this IStatist
}
#endif
+#if FEATURE_FILE_SPAN
+ public static void ShouldOnlyContainMethodCall(this IStatistics statistics,
+ string name,
+ T1 parameter1, ReadOnlySpan parameter2)
+ {
+ statistics.Methods.Length.Should().Be(1);
+ MethodStatistic? statistic = statistics.Methods.Should()
+ .ContainSingle(c => c.Name == name &&
+ c.Parameters.Length == 2).Which;
+ statistic.Parameters[0].Is(parameter1).Should().BeTrue();
+ statistic.Parameters[1].Is(parameter2).Should().BeTrue();
+ }
+#endif
+
+#if FEATURE_FILE_SPAN
+ public static void ShouldOnlyContainMethodCall(this IStatistics statistics,
+ string name,
+ T1 parameter1, ReadOnlySpan parameter2, T3 parameter3)
+ {
+ statistics.Methods.Length.Should().Be(1);
+ MethodStatistic? statistic = statistics.Methods.Should()
+ .ContainSingle(c => c.Name == name &&
+ c.Parameters.Length == 3).Which;
+ statistic.Parameters[0].Is(parameter1).Should().BeTrue();
+ statistic.Parameters[1].Is(parameter2).Should().BeTrue();
+ statistic.Parameters[2].Is(parameter3).Should().BeTrue();
+ }
+#endif
+
#if FEATURE_SPAN
public static void ShouldOnlyContainMethodCall(this IStatistics statistics, string name,
Span parameter1)
diff --git a/Tests/Testably.Abstractions.Tests/FileSystem/File/AppendAllBytesAsyncTests.cs b/Tests/Testably.Abstractions.Tests/FileSystem/File/AppendAllBytesAsyncTests.cs
new file mode 100644
index 000000000..985987735
--- /dev/null
+++ b/Tests/Testably.Abstractions.Tests/FileSystem/File/AppendAllBytesAsyncTests.cs
@@ -0,0 +1,174 @@
+#if FEATURE_FILE_SPAN
+using System.IO;
+using System.Threading;
+
+namespace Testably.Abstractions.Tests.FileSystem.File;
+
+// ReSharper disable MethodHasAsyncOverload
+[FileSystemTests]
+public partial class AppendAllBytesAsyncTests
+{
+ [Theory]
+ [AutoData]
+ public async Task AppendAllBytesAsync_Cancelled_ShouldThrowTaskCanceledException(
+ string path, byte[] bytes)
+ {
+ using CancellationTokenSource cts = new();
+ cts.Cancel();
+
+ Exception? exception = await Record.ExceptionAsync(() =>
+ FileSystem.File.AppendAllBytesAsync(path, bytes, cts.Token));
+
+ exception.Should().BeException(hResult: -2146233029);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task AppendAllBytesAsync_ExistingFile_ShouldAppendLinesToFile(
+ string path, byte[] previousBytes, byte[] bytes)
+ {
+ await FileSystem.File.AppendAllBytesAsync(path, previousBytes,
+ TestContext.Current.CancellationToken);
+
+ await FileSystem.File.AppendAllBytesAsync(path, bytes,
+ TestContext.Current.CancellationToken);
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent([..previousBytes, ..bytes]);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task AppendAllBytesAsync_MissingDirectory_ShouldThrowDirectoryNotFoundException(
+ string missingPath, string fileName, byte[] bytes)
+ {
+ string filePath = FileSystem.Path.Combine(missingPath, fileName);
+
+ async Task Act()
+ {
+ await FileSystem.File.AppendAllBytesAsync(filePath, bytes,
+ TestContext.Current.CancellationToken);
+ }
+
+ Exception? exception = await Record.ExceptionAsync(Act);
+
+ exception.Should().BeException(hResult: -2147024893);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task AppendAllBytesAsync_MissingFile_ShouldCreateFile(
+ string path, byte[] bytes)
+ {
+ await FileSystem.File.AppendAllBytesAsync(path, bytes,
+ TestContext.Current.CancellationToken);
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(bytes);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task AppendAllBytesAsync_ReadOnlyMemory_Cancelled_ShouldThrowTaskCanceledException(
+ string path, byte[] bytes)
+ {
+ using CancellationTokenSource cts = new();
+ cts.Cancel();
+
+ Exception? exception = await Record.ExceptionAsync(() =>
+ FileSystem.File.AppendAllBytesAsync(path, bytes.AsMemory(), cts.Token));
+
+ exception.Should().BeException(hResult: -2146233029);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task AppendAllBytesAsync_ReadOnlyMemory_ExistingFile_ShouldAppendLinesToFile(
+ string path, byte[] previousBytes, byte[] bytes)
+ {
+ await FileSystem.File.AppendAllBytesAsync(path, previousBytes,
+ TestContext.Current.CancellationToken);
+
+ await FileSystem.File.AppendAllBytesAsync(path, bytes.AsMemory(),
+ TestContext.Current.CancellationToken);
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent([..previousBytes, ..bytes]);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task
+ AppendAllBytesAsync_ReadOnlyMemory_MissingDirectory_ShouldThrowDirectoryNotFoundException(
+ string missingPath, string fileName, byte[] bytes)
+ {
+ string filePath = FileSystem.Path.Combine(missingPath, fileName);
+
+ async Task Act()
+ {
+ await FileSystem.File.AppendAllBytesAsync(filePath, bytes.AsMemory(),
+ TestContext.Current.CancellationToken);
+ }
+
+ Exception? exception = await Record.ExceptionAsync(Act);
+
+ exception.Should().BeException(hResult: -2147024893);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task AppendAllBytesAsync_ReadOnlyMemory_MissingFile_ShouldCreateFile(
+ string path, byte[] bytes)
+ {
+ await FileSystem.File.AppendAllBytesAsync(path, bytes.AsMemory(),
+ TestContext.Current.CancellationToken);
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(bytes);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task
+ AppendAllBytesAsync_ReadOnlyMemory_WhenDirectoryWithSameNameExists_ShouldThrowUnauthorizedAccessException(
+ string path, byte[] bytes)
+ {
+ FileSystem.Directory.CreateDirectory(path);
+
+ async Task Act()
+ {
+ await FileSystem.File.AppendAllBytesAsync(path, bytes.AsMemory(),
+ TestContext.Current.CancellationToken);
+ }
+
+ Exception? exception = await Record.ExceptionAsync(Act);
+
+ exception.Should().BeException(
+ hResult: -2147024891);
+ FileSystem.Should().HaveDirectory(path);
+ FileSystem.Should().NotHaveFile(path);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task
+ AppendAllBytesAsync_WhenDirectoryWithSameNameExists_ShouldThrowUnauthorizedAccessException(
+ string path, byte[] bytes)
+ {
+ FileSystem.Directory.CreateDirectory(path);
+
+ async Task Act()
+ {
+ await FileSystem.File.AppendAllBytesAsync(path, bytes,
+ TestContext.Current.CancellationToken);
+ }
+
+ Exception? exception = await Record.ExceptionAsync(Act);
+
+ exception.Should().BeException(
+ hResult: -2147024891);
+ FileSystem.Should().HaveDirectory(path);
+ FileSystem.Should().NotHaveFile(path);
+ }
+}
+#endif
diff --git a/Tests/Testably.Abstractions.Tests/FileSystem/File/AppendAllBytesTests.cs b/Tests/Testably.Abstractions.Tests/FileSystem/File/AppendAllBytesTests.cs
new file mode 100644
index 000000000..b20fb88b2
--- /dev/null
+++ b/Tests/Testably.Abstractions.Tests/FileSystem/File/AppendAllBytesTests.cs
@@ -0,0 +1,225 @@
+#if FEATURE_FILE_SPAN
+using System.IO;
+
+namespace Testably.Abstractions.Tests.FileSystem.File;
+
+[FileSystemTests]
+public partial class AppendAllBytesTests
+{
+ [Theory]
+ [AutoData]
+ public void AppendAllBytes_ExistingFile_ShouldAppendLinesToFile(
+ string path, byte[] previousBytes, byte[] bytes)
+ {
+ FileSystem.File.AppendAllBytes(path, previousBytes);
+
+ FileSystem.File.AppendAllBytes(path, bytes);
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent([..previousBytes, ..bytes]);
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllBytes_MissingDirectory_ShouldThrowDirectoryNotFoundException(
+ string missingPath, string fileName, byte[] bytes)
+ {
+ string filePath = FileSystem.Path.Combine(missingPath, fileName);
+ Exception? exception = Record.Exception(() =>
+ {
+ FileSystem.File.AppendAllBytes(filePath, bytes);
+ });
+
+ exception.Should().BeException(hResult: -2147024893);
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllBytes_MissingFile_ShouldCreateFile(
+ string path, byte[] bytes)
+ {
+ FileSystem.File.AppendAllBytes(path, bytes);
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(bytes);
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllBytes_ShouldAdjustTimes(string path, byte[] bytes)
+ {
+ SkipIfLongRunningTestsShouldBeSkipped();
+
+ DateTime creationTimeStart = TimeSystem.DateTime.UtcNow;
+ FileSystem.File.WriteAllText(path, "foo");
+ DateTime creationTimeEnd = TimeSystem.DateTime.UtcNow;
+ TimeSystem.Thread.Sleep(FileTestHelper.AdjustTimesDelay);
+ DateTime updateTime = TimeSystem.DateTime.UtcNow;
+
+ FileSystem.File.AppendAllBytes(path, bytes);
+
+ DateTime creationTime = FileSystem.File.GetCreationTimeUtc(path);
+ DateTime lastAccessTime = FileSystem.File.GetLastAccessTimeUtc(path);
+ DateTime lastWriteTime = FileSystem.File.GetLastWriteTimeUtc(path);
+
+ if (Test.RunsOnWindows)
+ {
+ creationTime.Should()
+ .BeBetween(creationTimeStart, creationTimeEnd);
+ lastAccessTime.Should()
+ .BeOnOrAfter(updateTime.ApplySystemClockTolerance());
+ }
+ else
+ {
+ lastAccessTime.Should()
+ .BeBetween(creationTimeStart, creationTimeEnd);
+ }
+
+ lastWriteTime.Should()
+ .BeOnOrAfter(updateTime.ApplySystemClockTolerance());
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllBytes_Span_ExistingFile_ShouldAppendLinesToFile(
+ string path, byte[] previousBytes, byte[] bytes)
+ {
+ FileSystem.File.AppendAllBytes(path, previousBytes);
+
+ FileSystem.File.AppendAllBytes(path, bytes.AsSpan());
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent([..previousBytes, ..bytes]);
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllBytes_Span_MissingDirectory_ShouldThrowDirectoryNotFoundException(
+ string missingPath, string fileName, byte[] bytes)
+ {
+ string filePath = FileSystem.Path.Combine(missingPath, fileName);
+ Exception? exception = Record.Exception(() =>
+ {
+ FileSystem.File.AppendAllBytes(filePath, bytes.AsSpan());
+ });
+
+ exception.Should().BeException(hResult: -2147024893);
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllBytes_Span_MissingFile_ShouldCreateFile(
+ string path, byte[] bytes)
+ {
+ FileSystem.File.AppendAllBytes(path, bytes.AsSpan());
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(bytes);
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllBytes_Span_ShouldAdjustTimes(string path, byte[] bytes)
+ {
+ SkipIfLongRunningTestsShouldBeSkipped();
+
+ DateTime creationTimeStart = TimeSystem.DateTime.UtcNow;
+ FileSystem.File.WriteAllText(path, "foo");
+ DateTime creationTimeEnd = TimeSystem.DateTime.UtcNow;
+ TimeSystem.Thread.Sleep(FileTestHelper.AdjustTimesDelay);
+ DateTime updateTime = TimeSystem.DateTime.UtcNow;
+
+ FileSystem.File.AppendAllBytes(path, bytes.AsSpan());
+
+ DateTime creationTime = FileSystem.File.GetCreationTimeUtc(path);
+ DateTime lastAccessTime = FileSystem.File.GetLastAccessTimeUtc(path);
+ DateTime lastWriteTime = FileSystem.File.GetLastWriteTimeUtc(path);
+
+ if (Test.RunsOnWindows)
+ {
+ creationTime.Should()
+ .BeBetween(creationTimeStart, creationTimeEnd);
+ lastAccessTime.Should()
+ .BeOnOrAfter(updateTime.ApplySystemClockTolerance());
+ }
+ else
+ {
+ lastAccessTime.Should()
+ .BeBetween(creationTimeStart, creationTimeEnd);
+ }
+
+ lastWriteTime.Should()
+ .BeOnOrAfter(updateTime.ApplySystemClockTolerance());
+ }
+
+ [Theory]
+ [AutoData]
+ public void
+ AppendAllBytes_Span_WhenDirectoryWithSameNameExists_ShouldThrowUnauthorizedAccessException(
+ string path)
+ {
+ FileSystem.Directory.CreateDirectory(path);
+
+ Exception? exception = Record.Exception(() =>
+ {
+ FileSystem.File.AppendAllBytes(path, Array.Empty().AsSpan());
+ });
+
+ exception.Should().BeException(
+ hResult: -2147024891);
+ FileSystem.Should().HaveDirectory(path);
+ FileSystem.Should().NotHaveFile(path);
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllBytes_Span_WhenFileIsHidden_ShouldNotThrowException(
+ string path, byte[] bytes)
+ {
+ FileSystem.File.WriteAllText(path, "some content");
+ FileSystem.File.SetAttributes(path, FileAttributes.Hidden);
+
+ Exception? exception = Record.Exception(() =>
+ {
+ FileSystem.File.AppendAllBytes(path, bytes.AsSpan());
+ });
+
+ exception.Should().BeNull();
+ }
+
+ [Theory]
+ [AutoData]
+ public void
+ AppendAllBytes_WhenDirectoryWithSameNameExists_ShouldThrowUnauthorizedAccessException(
+ string path)
+ {
+ FileSystem.Directory.CreateDirectory(path);
+
+ Exception? exception = Record.Exception(() =>
+ {
+ FileSystem.File.AppendAllBytes(path, Array.Empty());
+ });
+
+ exception.Should().BeException(
+ hResult: -2147024891);
+ FileSystem.Should().HaveDirectory(path);
+ FileSystem.Should().NotHaveFile(path);
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllBytes_WhenFileIsHidden_ShouldNotThrowException(
+ string path, byte[] bytes)
+ {
+ FileSystem.File.WriteAllText(path, "some content");
+ FileSystem.File.SetAttributes(path, FileAttributes.Hidden);
+
+ Exception? exception = Record.Exception(() =>
+ {
+ FileSystem.File.AppendAllBytes(path, bytes);
+ });
+
+ exception.Should().BeNull();
+ }
+}
+#endif
diff --git a/Tests/Testably.Abstractions.Tests/FileSystem/File/AppendAllTextAsyncTests.cs b/Tests/Testably.Abstractions.Tests/FileSystem/File/AppendAllTextAsyncTests.cs
index df8f1b0cd..543c6a775 100644
--- a/Tests/Testably.Abstractions.Tests/FileSystem/File/AppendAllTextAsyncTests.cs
+++ b/Tests/Testably.Abstractions.Tests/FileSystem/File/AppendAllTextAsyncTests.cs
@@ -3,7 +3,6 @@
using System.IO;
using System.Text;
using System.Threading;
-using System.Threading.Tasks;
namespace Testably.Abstractions.Tests.FileSystem.File;
@@ -127,5 +126,124 @@ public async Task AppendAllTextAsync_WithDifferentEncoding_ShouldNotReturnWritte
result.Should().NotBeEquivalentTo(contents,
$"{contents} should be different when encoding from {writeEncoding} to {readEncoding}.");
}
+
+#if FEATURE_FILE_SPAN
+ [Theory]
+ [AutoData]
+ public async Task AppendAllTextAsync_ReadOnlyMemory_Cancelled_ShouldThrowTaskCanceledException(
+ string path, string contents)
+ {
+ using CancellationTokenSource cts = new();
+ cts.Cancel();
+
+ Exception? exception = await Record.ExceptionAsync(() =>
+ FileSystem.File.AppendAllTextAsync(path, contents.AsMemory(), cts.Token));
+
+ exception.Should().BeException(hResult: -2146233029);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task
+ AppendAllTextAsync_ReadOnlyMemory_Cancelled_WithEncoding_ShouldThrowTaskCanceledException(
+ string path, string contents)
+ {
+ using CancellationTokenSource cts = new();
+ cts.Cancel();
+
+ Exception? exception = await Record.ExceptionAsync(() =>
+ FileSystem.File.AppendAllTextAsync(path, contents.AsMemory(), Encoding.UTF8, cts.Token));
+
+ exception.Should().BeException(hResult: -2146233029);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task AppendAllTextAsync_ReadOnlyMemory_ExistingFile_ShouldAppendLinesToFile(
+ string path, string previousContents, string contents)
+ {
+ await FileSystem.File.AppendAllTextAsync(path, previousContents, TestContext.Current.CancellationToken);
+
+ await FileSystem.File.AppendAllTextAsync(path, contents.AsMemory(), TestContext.Current.CancellationToken);
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(previousContents + contents);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task AppendAllTextAsync_ReadOnlyMemory_MissingDirectory_ShouldThrowDirectoryNotFoundException(
+ string missingPath, string fileName, string contents)
+ {
+ string filePath = FileSystem.Path.Combine(missingPath, fileName);
+
+ async Task Act()
+ {
+ await FileSystem.File.AppendAllTextAsync(filePath, contents.AsMemory(), TestContext.Current.CancellationToken);
+ }
+
+ Exception? exception = await Record.ExceptionAsync(Act);
+
+ exception.Should().BeException(hResult: -2147024893);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task AppendAllTextAsync_ReadOnlyMemory_MissingFile_ShouldCreateFile(
+ string path, string contents)
+ {
+ await FileSystem.File.AppendAllTextAsync(path, contents.AsMemory(), TestContext.Current.CancellationToken);
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(contents);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task AppendAllTextAsync_ReadOnlyMemory_ShouldNotEndWithNewline(string path)
+ {
+ string contents = "foo";
+
+ await FileSystem.File.AppendAllTextAsync(path, contents.AsMemory(), TestContext.Current.CancellationToken);
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(contents);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task
+ AppendAllTextAsync_ReadOnlyMemory_WhenDirectoryWithSameNameExists_ShouldThrowUnauthorizedAccessException(
+ string path, string contents)
+ {
+ FileSystem.Directory.CreateDirectory(path);
+
+ async Task Act()
+ {
+ await FileSystem.File.AppendAllTextAsync(path, contents.AsMemory(), TestContext.Current.CancellationToken);
+ }
+
+ Exception? exception = await Record.ExceptionAsync(Act);
+
+ exception.Should().BeException(
+ hResult: -2147024891);
+ FileSystem.Should().HaveDirectory(path);
+ FileSystem.Should().NotHaveFile(path);
+ }
+
+ [Theory]
+ [ClassData(typeof(TestDataGetEncodingDifference))]
+ public async Task AppendAllTextAsync_ReadOnlyMemory_WithDifferentEncoding_ShouldNotReturnWrittenText(
+ string contents, Encoding writeEncoding, Encoding readEncoding)
+ {
+ string path = new Fixture().Create();
+ await FileSystem.File.AppendAllTextAsync(path, contents.AsMemory(), writeEncoding, TestContext.Current.CancellationToken);
+
+ string[] result = FileSystem.File.ReadAllLines(path, readEncoding);
+
+ result.Should().NotBeEquivalentTo(contents,
+ $"{contents} should be different when encoding from {writeEncoding} to {readEncoding}.");
+ }
+#endif
}
#endif
diff --git a/Tests/Testably.Abstractions.Tests/FileSystem/File/AppendAllTextTests.cs b/Tests/Testably.Abstractions.Tests/FileSystem/File/AppendAllTextTests.cs
index 9ceb472c6..5b838e465 100644
--- a/Tests/Testably.Abstractions.Tests/FileSystem/File/AppendAllTextTests.cs
+++ b/Tests/Testably.Abstractions.Tests/FileSystem/File/AppendAllTextTests.cs
@@ -153,4 +153,153 @@ public void AppendAllText_WithDifferentEncoding_ShouldNotReturnWrittenText(
result.Should().NotBeEquivalentTo(contents,
$"{contents} should be different when encoding from {writeEncoding} to {readEncoding}.");
}
+
+#if FEATURE_FILE_SPAN
+ [Theory]
+ [AutoData]
+ public void AppendAllText_Span_ExistingFile_ShouldAppendLinesToFile(
+ string path, string previousContents, string contents)
+ {
+ FileSystem.File.AppendAllText(path, previousContents);
+
+ FileSystem.File.AppendAllText(path, contents.AsSpan());
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(previousContents + contents);
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllText_Span_MissingDirectory_ShouldThrowDirectoryNotFoundException(
+ string missingPath, string fileName, string contents)
+ {
+ string filePath = FileSystem.Path.Combine(missingPath, fileName);
+ Exception? exception = Record.Exception(() =>
+ {
+ FileSystem.File.AppendAllText(filePath, contents.AsSpan());
+ });
+
+ exception.Should().BeException(hResult: -2147024893);
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllText_Span_MissingFile_ShouldCreateFile(
+ string path, string contents)
+ {
+ FileSystem.File.AppendAllText(path, contents.AsSpan());
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(contents);
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllText_Span_MissingFile_ShouldCreateFileWithByteOrderMark(
+ string path)
+ {
+ byte[] expectedBytes = [255, 254, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0];
+
+ FileSystem.File.AppendAllText(path, "AA".AsSpan(), Encoding.UTF32);
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(expectedBytes);
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllText_Span_ShouldAdjustTimes(string path, string contents)
+ {
+ SkipIfLongRunningTestsShouldBeSkipped();
+
+ DateTime creationTimeStart = TimeSystem.DateTime.UtcNow;
+ FileSystem.File.WriteAllText(path, "foo");
+ DateTime creationTimeEnd = TimeSystem.DateTime.UtcNow;
+ TimeSystem.Thread.Sleep(FileTestHelper.AdjustTimesDelay);
+ DateTime updateTime = TimeSystem.DateTime.UtcNow;
+
+ FileSystem.File.AppendAllText(path, contents.AsSpan());
+
+ DateTime creationTime = FileSystem.File.GetCreationTimeUtc(path);
+ DateTime lastAccessTime = FileSystem.File.GetLastAccessTimeUtc(path);
+ DateTime lastWriteTime = FileSystem.File.GetLastWriteTimeUtc(path);
+
+ if (Test.RunsOnWindows)
+ {
+ creationTime.Should()
+ .BeBetween(creationTimeStart, creationTimeEnd);
+ lastAccessTime.Should()
+ .BeOnOrAfter(updateTime.ApplySystemClockTolerance());
+ }
+ else
+ {
+ lastAccessTime.Should()
+ .BeBetween(creationTimeStart, creationTimeEnd);
+ }
+
+ lastWriteTime.Should()
+ .BeOnOrAfter(updateTime.ApplySystemClockTolerance());
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllText_Span_ShouldNotEndWithNewline(string path)
+ {
+ string contents = "foo";
+
+ FileSystem.File.AppendAllText(path, contents.AsSpan());
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(contents);
+ }
+
+ [Theory]
+ [AutoData]
+ public void
+ AppendAllText_Span_WhenDirectoryWithSameNameExists_ShouldThrowUnauthorizedAccessException(
+ string path)
+ {
+ FileSystem.Directory.CreateDirectory(path);
+
+ Exception? exception = Record.Exception(() =>
+ {
+ FileSystem.File.AppendAllText(path, "".AsSpan());
+ });
+
+ exception.Should().BeException(
+ hResult: -2147024891);
+ FileSystem.Should().HaveDirectory(path);
+ FileSystem.Should().NotHaveFile(path);
+ }
+
+ [Theory]
+ [AutoData]
+ public void AppendAllText_Span_WhenFileIsHidden_ShouldNotThrowException(
+ string path, string contents)
+ {
+ FileSystem.File.WriteAllText(path, "some content");
+ FileSystem.File.SetAttributes(path, FileAttributes.Hidden);
+
+ Exception? exception = Record.Exception(() =>
+ {
+ FileSystem.File.AppendAllText(path, contents.AsSpan());
+ });
+
+ exception.Should().BeNull();
+ }
+
+ [Theory]
+ [ClassData(typeof(TestDataGetEncodingDifference))]
+ public void AppendAllText_Span_WithDifferentEncoding_ShouldNotReturnWrittenText(
+ string contents, Encoding writeEncoding, Encoding readEncoding)
+ {
+ string path = new Fixture().Create();
+ FileSystem.File.AppendAllText(path, contents.AsSpan(), writeEncoding);
+
+ string[] result = FileSystem.File.ReadAllLines(path, readEncoding);
+
+ result.Should().NotBeEquivalentTo(contents,
+ $"{contents} should be different when encoding from {writeEncoding} to {readEncoding}.");
+ }
+#endif
}
diff --git a/Tests/Testably.Abstractions.Tests/FileSystem/File/OpenReadTests.cs b/Tests/Testably.Abstractions.Tests/FileSystem/File/OpenReadTests.cs
index 7a49f1a2f..858a5e7e3 100644
--- a/Tests/Testably.Abstractions.Tests/FileSystem/File/OpenReadTests.cs
+++ b/Tests/Testably.Abstractions.Tests/FileSystem/File/OpenReadTests.cs
@@ -94,7 +94,7 @@ async Task Act()
public async Task OpenRead_WriteAsyncWithMemory_ShouldThrowNotSupportedException(
string path, byte[] bytes)
{
- await FileSystem.File.WriteAllTextAsync(path, null, TestContext.Current.CancellationToken);
+ await FileSystem.File.WriteAllTextAsync(path, "", TestContext.Current.CancellationToken);
async Task Act()
{
diff --git a/Tests/Testably.Abstractions.Tests/FileSystem/File/WriteAllBytesAsyncTests.cs b/Tests/Testably.Abstractions.Tests/FileSystem/File/WriteAllBytesAsyncTests.cs
index ac0ecb5c3..841a05063 100644
--- a/Tests/Testably.Abstractions.Tests/FileSystem/File/WriteAllBytesAsyncTests.cs
+++ b/Tests/Testably.Abstractions.Tests/FileSystem/File/WriteAllBytesAsyncTests.cs
@@ -92,7 +92,7 @@ public async Task
{
Skip.IfNot(Test.RunsOnWindows);
- await FileSystem.File.WriteAllTextAsync(path, null, TestContext.Current.CancellationToken);
+ await FileSystem.File.WriteAllTextAsync(path, "", TestContext.Current.CancellationToken);
FileSystem.File.SetAttributes(path, FileAttributes.Hidden);
async Task Act()
@@ -104,5 +104,87 @@ async Task Act()
exception.Should().BeException(hResult: -2147024891);
}
+
+#if FEATURE_FILE_SPAN
+ [Theory]
+ [AutoData]
+ public async Task WriteAllBytesAsync_ReadOnlyMemory_Cancelled_ShouldThrowTaskCanceledException(
+ string path, byte[] bytes)
+ {
+ using CancellationTokenSource cts = new();
+ cts.Cancel();
+
+ Exception? exception = await Record.ExceptionAsync(() =>
+ FileSystem.File.WriteAllBytesAsync(path, bytes.AsMemory(), cts.Token));
+
+ exception.Should().BeException(hResult: -2146233029);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task WriteAllBytesAsync_ReadOnlyMemory_PreviousFile_ShouldOverwriteFileWithBytes(
+ string path, byte[] bytes)
+ {
+ await FileSystem.File.WriteAllBytesAsync(path, Encoding.UTF8.GetBytes("foo"), TestContext.Current.CancellationToken);
+
+ await FileSystem.File.WriteAllBytesAsync(path, bytes.AsMemory(), TestContext.Current.CancellationToken);
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(bytes);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task WriteAllBytesAsync_ReadOnlyMemory_ShouldCreateFileWithBytes(
+ string path, byte[] bytes)
+ {
+ await FileSystem.File.WriteAllBytesAsync(path, bytes.AsMemory(), TestContext.Current.CancellationToken);
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(bytes);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task
+ WriteAllBytesAsync_ReadOnlyMemory_WhenDirectoryWithSameNameExists_ShouldThrowUnauthorizedAccessException(
+ string path, byte[] bytes)
+ {
+ FileSystem.Directory.CreateDirectory(path);
+
+ async Task Act()
+ {
+ await FileSystem.File.WriteAllBytesAsync(path, bytes.AsMemory(), TestContext.Current.CancellationToken);
+ }
+
+ Exception? exception = await Record.ExceptionAsync(Act);
+
+ exception.Should().BeException(
+ hResult: -2147024891);
+ FileSystem.Should().HaveDirectory(path);
+ FileSystem.Should().NotHaveFile(path);
+ }
+
+ [Theory]
+ [AutoData]
+ public async Task
+ WriteAllTextAsync_ReadOnlyMemory_WhenFileIsHidden_ShouldThrowUnauthorizedAccessException_OnWindows(
+ string path, byte[] bytes)
+ {
+ Skip.IfNot(Test.RunsOnWindows);
+
+ await FileSystem.File.WriteAllTextAsync(path, "", TestContext.Current.CancellationToken);
+ FileSystem.File.SetAttributes(path, FileAttributes.Hidden);
+
+ async Task Act()
+ {
+ await FileSystem.File.WriteAllBytesAsync(path, bytes.AsMemory(), TestContext.Current.CancellationToken);
+ }
+
+ Exception? exception = await Record.ExceptionAsync(Act);
+
+ exception.Should().BeException(hResult: -2147024891);
+ }
+#endif
}
#endif
diff --git a/Tests/Testably.Abstractions.Tests/FileSystem/File/WriteAllBytesTests.cs b/Tests/Testably.Abstractions.Tests/FileSystem/File/WriteAllBytesTests.cs
index b58d1e686..b1746d5e7 100644
--- a/Tests/Testably.Abstractions.Tests/FileSystem/File/WriteAllBytesTests.cs
+++ b/Tests/Testably.Abstractions.Tests/FileSystem/File/WriteAllBytesTests.cs
@@ -77,4 +77,66 @@ public void WriteAllBytes_WhenFileIsHidden_ShouldThrowUnauthorizedAccessExceptio
exception.Should().BeException(hResult: -2147024891);
}
+
+#if FEATURE_FILE_SPAN
+ [Theory]
+ [AutoData]
+ public void WriteAllBytes_Span_PreviousFile_ShouldOverwriteFileWithBytes(
+ string path, byte[] bytes)
+ {
+ FileSystem.File.WriteAllBytes(path, Encoding.UTF8.GetBytes("foo"));
+
+ FileSystem.File.WriteAllBytes(path, bytes.AsSpan());
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(bytes);
+ }
+
+ [Theory]
+ [AutoData]
+ public void WriteAllBytes_Span_ShouldCreateFileWithBytes(string path, byte[] bytes)
+ {
+ FileSystem.File.WriteAllBytes(path, bytes.AsSpan());
+
+ FileSystem.Should().HaveFile(path)
+ .Which.HasContent(bytes);
+ }
+
+ [Theory]
+ [AutoData]
+ public void
+ WriteAllBytes_Span_WhenDirectoryWithSameNameExists_ShouldThrowUnauthorizedAccessException(
+ string path, byte[] bytes)
+ {
+ FileSystem.Directory.CreateDirectory(path);
+
+ Exception? exception = Record.Exception(() =>
+ {
+ FileSystem.File.WriteAllBytes(path, bytes.AsSpan());
+ });
+
+ exception.Should().BeException