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

172 lines
7.5 KiB
C#

using Explorer.Application;
using Explorer.Domain;
using Explorer.Domain.Abstractions;
using Explorer.Windows;
namespace Explorer.Application.Tests;
public class GitCommandIntegrationTests : IDisposable
{
private readonly string _root;
private readonly WindowsGitStatusProvider _git;
public GitCommandIntegrationTests()
{
_root = Path.Combine(Path.GetTempPath(), "ew-git", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(_root);
_git = new WindowsGitStatusProvider(new UiPreferencesStore(new GitTestEnv(_root)));
}
public void Dispose()
{
try { Directory.Delete(_root, true); } catch { /* ignore */ }
}
[Fact]
public async Task Diff_stage_commit_and_merge_resolution()
{
if (GitLocator.Find(null) is null)
{
return;
}
var repo = Path.Combine(_root, "repo");
Directory.CreateDirectory(repo);
await Git(repo, "init", "-b", "main").ConfigureAwait(true);
await Git(repo, "config", "user.email", "test@example.com").ConfigureAwait(true);
await Git(repo, "config", "user.name", "Test").ConfigureAwait(true);
await Git(repo, "config", "core.autocrlf", "false").ConfigureAwait(true);
File.WriteAllText(Path.Combine(repo, "note.txt"), "base\n");
await Git(repo, "add", "note.txt").ConfigureAwait(true);
await Git(repo, "commit", "-m", "base").ConfigureAwait(true);
File.WriteAllText(Path.Combine(repo, "note.txt"), "base\nedited\n");
var status = await _git.StatusAsync(repo).ConfigureAwait(true);
Assert.NotNull(status);
var unstaged = Assert.Single(status.Changes, c => c.State == GitChangeState.Unstaged);
var diff = await _git.DiffAsync(repo, unstaged).ConfigureAwait(true);
Assert.Null(diff.Error);
Assert.Contains(diff.Lines, l => l.Kind == GitDiffLineKind.Added && l.Text.Contains("edited"));
var staged = await _git.StageAsync(repo, "note.txt").ConfigureAwait(true);
Assert.True(staged.Succeeded, staged.DisplayMessage);
var committed = await _git.CommitAsync(repo, "edit", ["note.txt"]).ConfigureAwait(true);
Assert.True(committed.Succeeded, committed.DisplayMessage);
await Git(repo, "checkout", "-b", "topic").ConfigureAwait(true);
File.WriteAllText(Path.Combine(repo, "note.txt"), "base\nedited\ntopic\n");
await Git(repo, "add", "note.txt").ConfigureAwait(true);
await Git(repo, "commit", "-m", "topic").ConfigureAwait(true);
await Git(repo, "checkout", "main").ConfigureAwait(true);
File.WriteAllText(Path.Combine(repo, "note.txt"), "base\nedited\nmain\n");
await Git(repo, "add", "note.txt").ConfigureAwait(true);
await Git(repo, "commit", "-m", "main").ConfigureAwait(true);
var merge = await GitExpectFail(repo, "merge", "topic").ConfigureAwait(true);
Assert.False(string.IsNullOrWhiteSpace(merge));
status = await _git.StatusAsync(repo).ConfigureAwait(true);
Assert.NotNull(status);
Assert.Equal(GitOperationKind.Merge, status.Operation);
Assert.Contains(status.Changes, c => c.State == GitChangeState.Unmerged);
var ours = await _git.CheckoutConflictAsync(repo, "note.txt", GitConflictSide.Ours).ConfigureAwait(true);
Assert.True(ours.Succeeded, ours.DisplayMessage);
status = await _git.StatusAsync(repo).ConfigureAwait(true);
Assert.NotNull(status);
Assert.False(status.HasUnmerged);
var continued = await _git.ContinueOperationAsync(repo).ConfigureAwait(true);
Assert.True(continued.Succeeded, continued.DisplayMessage);
status = await _git.StatusAsync(repo).ConfigureAwait(true);
Assert.NotNull(status);
Assert.Equal(GitOperationKind.None, status.Operation);
Assert.True(status.WorkingTreeClean);
}
[Fact]
public async Task Abort_restores_the_pre_merge_tree()
{
if (GitLocator.Find(null) is null)
{
return;
}
var repo = Path.Combine(_root, "abort");
Directory.CreateDirectory(repo);
await Git(repo, "init", "-b", "main").ConfigureAwait(true);
await Git(repo, "config", "user.email", "test@example.com").ConfigureAwait(true);
await Git(repo, "config", "user.name", "Test").ConfigureAwait(true);
await Git(repo, "config", "core.autocrlf", "false").ConfigureAwait(true);
File.WriteAllText(Path.Combine(repo, "a.txt"), "one\n");
await Git(repo, "add", "a.txt").ConfigureAwait(true);
await Git(repo, "commit", "-m", "one").ConfigureAwait(true);
await Git(repo, "checkout", "-b", "other").ConfigureAwait(true);
File.WriteAllText(Path.Combine(repo, "a.txt"), "two\n");
await Git(repo, "add", "a.txt").ConfigureAwait(true);
await Git(repo, "commit", "-m", "two").ConfigureAwait(true);
await Git(repo, "checkout", "main").ConfigureAwait(true);
File.WriteAllText(Path.Combine(repo, "a.txt"), "three\n");
await Git(repo, "add", "a.txt").ConfigureAwait(true);
await Git(repo, "commit", "-m", "three").ConfigureAwait(true);
await GitExpectFail(repo, "merge", "other").ConfigureAwait(true);
var aborted = await _git.AbortOperationAsync(repo).ConfigureAwait(true);
Assert.True(aborted.Succeeded, aborted.DisplayMessage);
var status = await _git.StatusAsync(repo).ConfigureAwait(true);
Assert.NotNull(status);
Assert.Equal(GitOperationKind.None, status.Operation);
Assert.Equal("three\n", File.ReadAllText(Path.Combine(repo, "a.txt")).Replace("\r\n", "\n"));
}
private static async Task Git(string repo, params string[] args)
{
var result = await RunGit(repo, args).ConfigureAwait(true);
Assert.True(result.Exit == 0, result.Text);
}
private static async Task<string> GitExpectFail(string repo, params string[] args)
{
var result = await RunGit(repo, args).ConfigureAwait(true);
Assert.NotEqual(0, result.Exit);
return result.Text;
}
private static async Task<(int Exit, string Text)> RunGit(string repo, string[] args)
{
var git = GitLocator.Find(null) ?? throw new InvalidOperationException("git.exe missing");
using var process = new System.Diagnostics.Process();
process.StartInfo.FileName = git;
process.StartInfo.WorkingDirectory = repo;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
foreach (var arg in args)
{
process.StartInfo.ArgumentList.Add(arg);
}
process.Start();
var stdout = await process.StandardOutput.ReadToEndAsync().ConfigureAwait(true);
var stderr = await process.StandardError.ReadToEndAsync().ConfigureAwait(true);
await process.WaitForExitAsync().ConfigureAwait(true);
return (process.ExitCode, stdout + stderr);
}
}
file sealed class GitTestEnv : IAppEnvironment
{
public GitTestEnv(string dir)
{
DataDirectory = Path.Combine(dir, "data");
Directory.CreateDirectory(DataDirectory);
DatabasePath = Path.Combine(DataDirectory, "index.db");
LogDirectory = Path.Combine(DataDirectory, "logs");
Directory.CreateDirectory(LogDirectory);
}
public string DataDirectory { get; }
public string DatabasePath { get; }
public string LogDirectory { get; }
}