Files
Explorer-Workbench/tests/Explorer.Application.Tests/ReorganizePlannerTests.cs

167 lines
6.5 KiB
C#

using Explorer.Application;
using Explorer.Domain;
using Explorer.Domain.Abstractions;
namespace Explorer.Application.Tests;
public class ReorganizePlannerTests
{
private static readonly DateTimeOffset T0 = DateTimeOffset.Parse("2024-06-01T12:00:00Z");
[Fact]
public void Proposes_moves_and_leaves_unknown_and_build_output()
{
var fs = Tree()
.Dir(@"C:\Downloads")
.File(@"C:\Downloads\setup.exe", 10, T0)
.File(@"C:\Downloads\photo.jpg", 20, T0)
.File(@"C:\Downloads\clip.mkv", 30, T0)
.File(@"C:\Downloads\notes.pdf", 8, T0)
.File(@"C:\Downloads\pack.zip", 4, T0)
.File(@"C:\Downloads\weird.bin", 1, T0)
.Dir(@"C:\Downloads\node_modules")
.File(@"C:\Downloads\node_modules\pkg.js", 1, T0)
.Dir(@"C:\Software")
.Dir(@"C:\Pictures")
.Dir(@"C:\Videos")
.Dir(@"C:\Docs")
.Dir(@"C:\Archive");
var plan = Build(fs);
Assert.True(plan.CanEnqueue);
Assert.Contains(plan.Operations, o => o.Op == TransferOp.Move && o.SourcePath.EndsWith("setup.exe") && o.DestinationPath == @"C:\Software\setup.exe");
Assert.Contains(plan.Operations, o => o.DestinationPath == @"C:\Pictures\photo.jpg");
Assert.Contains(plan.Operations, o => o.DestinationPath == @"C:\Videos\clip.mkv");
Assert.Contains(plan.Operations, o => o.DestinationPath == @"C:\Docs\notes.pdf");
Assert.Contains(plan.Operations, o => o.DestinationPath == @"C:\Archive\pack.zip");
Assert.DoesNotContain(plan.Operations, o => o.SourcePath.Contains("weird.bin", StringComparison.OrdinalIgnoreCase));
Assert.DoesNotContain(plan.Operations, o => o.SourcePath.Contains("node_modules", StringComparison.OrdinalIgnoreCase));
Assert.Contains(plan.OrganizePreview, r => r.Name == "weird.bin" && r.Action == "Skip");
Assert.Contains(plan.OrganizePreview, r => r.Name == "node_modules" && r.Action == "Skip");
}
[Fact]
public void Git_repo_moves_as_a_unit_to_development()
{
var fs = Tree()
.Dir(@"C:\Downloads")
.Dir(@"C:\Downloads\Explorer")
.File(@"C:\Downloads\Explorer\README.md", 1, T0)
.Dir(@"C:\Dev");
var plan = Build(fs, dest => dest.Development = @"C:\Dev", isRepoRoot: path => path.EndsWith(@"\Explorer", StringComparison.OrdinalIgnoreCase));
Assert.Contains(plan.Operations, o => o.SourcePath == @"C:\Downloads\Explorer" && o.DestinationPath == @"C:\Dev\Explorer");
Assert.DoesNotContain(plan.Operations, o => o.SourcePath.Contains("README", StringComparison.OrdinalIgnoreCase));
}
[Fact]
public void Missing_destination_skips_that_category()
{
var fs = Tree()
.Dir(@"C:\Downloads")
.File(@"C:\Downloads\setup.exe", 10, T0)
.File(@"C:\Downloads\photo.jpg", 20, T0)
.Dir(@"C:\Pictures");
var plan = Build(fs, dest => dest.Installers = "");
Assert.Contains(plan.Operations, o => o.DestinationPath == @"C:\Pictures\photo.jpg");
Assert.DoesNotContain(plan.Operations, o => o.SourcePath.EndsWith("setup.exe"));
Assert.Contains(plan.OrganizePreview, r => r.Name == "setup.exe" && r.Action == "Skip");
}
[Fact]
public void Old_installer_is_a_warning_still_proposed()
{
var old = T0.AddYears(-2);
var fs = Tree()
.Dir(@"C:\Downloads")
.File(@"C:\Downloads\old.msi", 10, old)
.Dir(@"C:\Software");
var plan = Build(fs, now: T0);
Assert.True(plan.CanEnqueue);
Assert.Contains(plan.Operations, o => o.SourcePath.EndsWith("old.msi"));
Assert.Contains(plan.Issues, i => i.Severity == PlanIssueSeverity.Warning && i.Message.Contains("Old", StringComparison.OrdinalIgnoreCase));
Assert.Contains(plan.OrganizePreview, r => r.Name == "old.msi" && r.Detail == "Older than 1 year.");
}
[Fact]
public void Offline_destination_is_an_error_and_does_not_enqueue()
{
var fs = Tree()
.Dir(@"C:\Downloads")
.File(@"C:\Downloads\photo.jpg", 20, T0)
.Dir(@"Z:\Pictures");
var plan = new ReorganizePlanner().Build(
@"C:\Downloads",
Map(d => d.Pictures = @"Z:\Pictures"),
fs,
path => path.StartsWith(@"C:\", StringComparison.OrdinalIgnoreCase),
_ => false);
Assert.False(plan.CanEnqueue);
Assert.Empty(plan.Operations);
Assert.Contains(plan.Issues, i => i.Message == "Destination is not available.");
}
[Fact]
public void Destination_inside_the_source_is_allowed()
{
var fs = Tree()
.Dir(@"C:\Downloads")
.File(@"C:\Downloads\setup.exe", 10, T0)
.Dir(@"C:\Downloads\Software");
var plan = Build(fs, dest => dest.Installers = @"C:\Downloads\Software");
Assert.True(plan.CanEnqueue);
Assert.Contains(plan.Operations, o => o.DestinationPath == @"C:\Downloads\Software\setup.exe");
Assert.DoesNotContain(plan.Operations, o => o.SourcePath == @"C:\Downloads\Software");
}
[Fact]
public void Planner_does_not_move_files_itself()
{
var fs = Tree()
.Dir(@"C:\Downloads")
.File(@"C:\Downloads\photo.jpg", 20, T0)
.Dir(@"C:\Pictures");
var plan = Build(fs);
Assert.NotEmpty(plan.Operations);
Assert.NotNull(fs.GetItem(@"C:\Downloads\photo.jpg"));
Assert.Null(fs.GetItem(@"C:\Pictures\photo.jpg"));
}
private static OperationPlan Build(
IFileSystemEnumerator fs,
Action<OrganizeDestinations>? configure = null,
Func<string, bool>? isRepoRoot = null,
DateTimeOffset? now = null)
=> new ReorganizePlanner().Build(
@"C:\Downloads",
Map(configure),
fs,
_ => true,
isRepoRoot ?? (_ => false),
now: now ?? T0,
pathExists: _ => false);
private static OrganizeDestinations Map(Action<OrganizeDestinations>? configure = null)
{
var dest = new OrganizeDestinations
{
Pictures = @"C:\Pictures",
Videos = @"C:\Videos",
Audio = @"C:\Music",
Documents = @"C:\Docs",
Installers = @"C:\Software",
Archives = @"C:\Archive",
Development = @"C:\Dev"
};
configure?.Invoke(dest);
return dest;
}
private static TreeEnumerator Tree() => new();
}