Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: foundation for simulated tests #565

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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions Source/Testably.Abstractions.Testing/Helpers/Execute.MacPath.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
namespace Testably.Abstractions.Testing.Helpers;
using System.Linq;

namespace Testably.Abstractions.Testing.Helpers;

internal partial class Execute
{
private sealed class MacPath(MockFileSystem fileSystem) : LinuxPath(fileSystem);
private sealed class MacPath(MockFileSystem fileSystem) : LinuxPath(fileSystem)
{
private readonly MockFileSystem _fileSystem = fileSystem;

private string? _tempPath;

/// <inheritdoc cref="IPath.GetTempPath()" />
public override string GetTempPath()
{
_tempPath ??= $"/var/folders/{RandomString(2)}/{RandomString(2)}_{RandomString(27)}/T/";
return _tempPath;
}

private string RandomString(int length)
{
const string chars = "abcdefghijklmnopqrstuvwxyz0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[_fileSystem.RandomSystem.Random.Shared.Next(s.Length)]).ToArray());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Testably.Abstractions.Testing.Helpers;
using System;

namespace Testably.Abstractions.Testing.Helpers;

internal partial class Execute
{
Expand All @@ -19,7 +21,7 @@ private sealed class WindowsPath(MockFileSystem fileSystem) : SimulatedPath(file
/// <inheritdoc cref="IPath.GetInvalidFileNameChars()" />
public override char[] GetInvalidFileNameChars() =>
[
'|', '\0',
'\"', '<', '>', '|', '\0',
(char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9,
(char)10, (char)11, (char)12, (char)13, (char)14, (char)15, (char)16, (char)17,
(char)18, (char)19, (char)20, (char)21, (char)22, (char)23, (char)24, (char)25,
Expand All @@ -45,13 +47,13 @@ public override char[] GetInvalidPathChars() =>
}

return IsPathRooted(path)
? path.Substring(0,3)
? path.Substring(0, Math.Min(3, path.Length))
: string.Empty;
}

/// <inheritdoc cref="IPath.GetTempPath()" />
public override string GetTempPath()
=> @"C:\Windows\Temp";
=> @"C:\Windows\Temp\";

/// <inheritdoc cref="IPath.IsPathRooted(string)" />
public override bool IsPathRooted(string? path)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>Testably.Abstractions.Testing.Tests</_Parameter1>
</AssemblyAttribute>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>Testably.Abstractions.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[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.CompilerServices.InternalsVisibleTo("Testably.Abstractions.Tests")]
[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName=".NET 6.0")]
namespace Testably.Abstractions.Testing.FileSystem
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[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.CompilerServices.InternalsVisibleTo("Testably.Abstractions.Tests")]
[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v7.0", FrameworkDisplayName=".NET 7.0")]
namespace Testably.Abstractions.Testing.FileSystem
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[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.CompilerServices.InternalsVisibleTo("Testably.Abstractions.Tests")]
[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v8.0", FrameworkDisplayName=".NET 8.0")]
namespace Testably.Abstractions.Testing.FileSystem
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[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.CompilerServices.InternalsVisibleTo("Testably.Abstractions.Tests")]
[assembly: System.Runtime.Versioning.TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName=".NET Standard 2.0")]
namespace Testably.Abstractions.Testing.FileSystem
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[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.CompilerServices.InternalsVisibleTo("Testably.Abstractions.Tests")]
[assembly: System.Runtime.Versioning.TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName=".NET Standard 2.1")]
namespace Testably.Abstractions.Testing.FileSystem
{
Expand Down
8 changes: 8 additions & 0 deletions Tests/Helpers/Testably.Abstractions.TestHelpers/Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,12 @@ public Test()
IsNetFramework = RuntimeInformation.FrameworkDescription
.StartsWith(".NET Framework", StringComparison.OrdinalIgnoreCase);
}

public Test(OSPlatform osPlatform)
{
RunsOnLinux = osPlatform == OSPlatform.Linux;
RunsOnMac = osPlatform == OSPlatform.OSX;
RunsOnWindows = osPlatform == OSPlatform.Windows;
IsNetFramework = false;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Text;
using System;
using System.Linq;
using System.Text;
using Testably.Abstractions.Tests.SourceGenerator.Model;
// ReSharper disable StringLiteralTypo

Expand All @@ -12,7 +14,9 @@ public override string Marker

/// <inheritdoc cref="ClassGeneratorBase.GenerateSource(StringBuilder, ClassModel)" />
protected override void GenerateSource(StringBuilder sourceBuilder, ClassModel @class)
=> sourceBuilder.Append(@$"
{
sourceBuilder.Append(@$"
using System.Runtime.InteropServices;
using Testably.Abstractions.Testing.Initializer;
using Testably.Abstractions.TestHelpers;
using Testably.Abstractions.TestHelpers.Settings;
Expand Down Expand Up @@ -130,4 +134,104 @@ public override void SkipIfLongRunningTestsShouldBeSkipped()
#endif
}}
}}");
if (IncludeSimulatedTests(@class))
{
sourceBuilder.Append(@$"
#if !NETFRAMEWORK
namespace {@class.Namespace}.{@class.Name}
{{
// ReSharper disable once UnusedMember.Global
public sealed class LinuxFileSystemTests : {@class.Name}<MockFileSystem>
{{
/// <inheritdoc cref=""{@class.Name}{{TFileSystem}}.BasePath"" />
public override string BasePath => ""/"";
public LinuxFileSystemTests() : this(new MockFileSystem(i =>
i.SimulatingOperatingSystem(SimulationMode.Linux)))
{{
}}
private LinuxFileSystemTests(MockFileSystem mockFileSystem) : base(
new Test(OSPlatform.Linux),
mockFileSystem,
mockFileSystem.TimeSystem)
{{
}}
/// <inheritdoc cref=""{@class.Name}{{TFileSystem}}.SkipIfBrittleTestsShouldBeSkipped(bool)"" />
public override void SkipIfBrittleTestsShouldBeSkipped(bool condition = true)
{{
// Brittle tests are never skipped against the mock file system!
}}
/// <inheritdoc cref=""{@class.Name}{{TFileSystem}}.LongRunningTestsShouldBeSkipped()"" />
public override void SkipIfLongRunningTestsShouldBeSkipped()
{{
// Long-running tests are never skipped against the mock file system!
}}
}}
#endif
#if !NETFRAMEWORK
// ReSharper disable once UnusedMember.Global
public sealed class MacFileSystemTests : {@class.Name}<MockFileSystem>
{{
/// <inheritdoc cref=""{@class.Name}{{TFileSystem}}.BasePath"" />
public override string BasePath => ""/"";
public MacFileSystemTests() : this(new MockFileSystem(i =>
i.SimulatingOperatingSystem(SimulationMode.MacOS)))
{{
}}
private MacFileSystemTests(MockFileSystem mockFileSystem) : base(
new Test(OSPlatform.OSX),
mockFileSystem,
mockFileSystem.TimeSystem)
{{
}}
/// <inheritdoc cref=""{@class.Name}{{TFileSystem}}.SkipIfBrittleTestsShouldBeSkipped(bool)"" />
public override void SkipIfBrittleTestsShouldBeSkipped(bool condition = true)
{{
// Brittle tests are never skipped against the mock file system!
}}
/// <inheritdoc cref=""{@class.Name}{{TFileSystem}}.LongRunningTestsShouldBeSkipped()"" />
public override void SkipIfLongRunningTestsShouldBeSkipped()
{{
// Long-running tests are never skipped against the mock file system!
}}
}}
#endif
#if !NETFRAMEWORK
// ReSharper disable once UnusedMember.Global
public sealed class WindowsFileSystemTests : {@class.Name}<MockFileSystem>
{{
/// <inheritdoc cref=""{@class.Name}{{TFileSystem}}.BasePath"" />
public override string BasePath => ""C:\\"";
public WindowsFileSystemTests() : this(new MockFileSystem(i =>
i.SimulatingOperatingSystem(SimulationMode.Windows)))
{{
}}
private WindowsFileSystemTests(MockFileSystem mockFileSystem) : base(
new Test(OSPlatform.Windows),
mockFileSystem,
mockFileSystem.TimeSystem)
{{
}}
/// <inheritdoc cref=""{@class.Name}{{TFileSystem}}.SkipIfBrittleTestsShouldBeSkipped(bool)"" />
public override void SkipIfBrittleTestsShouldBeSkipped(bool condition = true)
{{
// Brittle tests are never skipped against the mock file system!
}}
/// <inheritdoc cref=""{@class.Name}{{TFileSystem}}.LongRunningTestsShouldBeSkipped()"" />
public override void SkipIfLongRunningTestsShouldBeSkipped()
{{
// Long-running tests are never skipped against the mock file system!
}}
}}
}}
#endif");
}
}

private bool IncludeSimulatedTests(ClassModel @class)
{
string[] supportedPathTests = ["Tests", "GetRandomFileNameTests", "GetPathRootTests", "GetTempPathTests", "IsPathRootedTests"];
return @class.Namespace
.StartsWith("Testably.Abstractions.Tests.FileSystem.Path", StringComparison.Ordinal)
&& supportedPathTests.Contains(@class.Name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,7 @@ public void
string currentDirectory = FileSystem.Directory.GetCurrentDirectory();
int directoryCount = currentDirectory.Length -
currentDirectory
.Replace($"{FileSystem.Path.DirectorySeparatorChar}", "",
StringComparison.Ordinal)
.Replace($"{FileSystem.Path.DirectorySeparatorChar}", "")
.Length;

StringBuilder sb = new();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
namespace Testably.Abstractions.Tests.FileSystem.Path;

// ReSharper disable once PartialTypeWithSinglePart
public abstract partial class GetPathRootTests<TFileSystem>
: FileSystemTestBase<TFileSystem>
where TFileSystem : IFileSystem
{
[SkippableFact]
public void GetPathRoot_Null_ShouldReturnNull()
{
string? result = FileSystem.Path.GetPathRoot(null);

result.Should().BeNull();
}

[SkippableTheory]
[InlineData("D:")]
[InlineData("D:\\")]
public void GetPathRoot_RootedDrive_ShouldReturnDriveOnWindows(string path)
{
Skip.IfNot(Test.RunsOnWindows);

string? result = FileSystem.Path.GetPathRoot(path);

result.Should().Be(path);
}

[SkippableTheory]
[AutoData]
public void GetPathRoot_ShouldReturnDefaultValue(string path)
{
string? result = FileSystem.Path.GetPathRoot(path);

result.Should().Be(System.IO.Path.GetPathRoot(path));
}

#if FEATURE_SPAN
[SkippableTheory]
[AutoData]
public void GetPathRoot_Span_ShouldReturnDefaultValue(string path)
{
ReadOnlySpan<char> result = FileSystem.Path.GetPathRoot(path.AsSpan());

result.ToArray().Should().BeEquivalentTo(
System.IO.Path.GetPathRoot(path.AsSpan()).ToArray());
}
#endif
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
namespace Testably.Abstractions.Tests.FileSystem.Path;

// ReSharper disable once PartialTypeWithSinglePart
public abstract partial class GetTempPathTests<TFileSystem>
: FileSystemTestBase<TFileSystem>
where TFileSystem : IFileSystem
{
[SkippableFact]
public void GetTempPath_Linux_ShouldBeTmp()
{
Skip.IfNot(Test.RunsOnLinux);

string result = FileSystem.Path.GetTempPath();

result.Should().Be("/tmp/");
}

[SkippableFact]
public void GetTempPath_MacOs_ShouldBeTmp()
{
Skip.IfNot(Test.RunsOnMac);

string result = FileSystem.Path.GetTempPath();

result.Should().Match("/var/folders/??/*/T/");
}

[SkippableFact]
public void GetTempPath_ShouldRemainTheSame()
{
string result1 = FileSystem.Path.GetTempPath();
string result2 = FileSystem.Path.GetTempPath();

result1.Should().Be(result2);
}

[SkippableFact]
public void GetTempPath_Windows_ShouldBeOnDriveC()
{
Skip.IfNot(Test.RunsOnWindows);

string result = FileSystem.Path.GetTempPath();

result.Should().StartWith(@"C:\").And.EndWith(@"\Temp\");
}
}
Loading
Loading