Show the window before slow location probes and wrap git.exe for commit, diff, and merge.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
171
tests/Explorer.Application.Tests/GitCommandIntegrationTests.cs
Normal file
171
tests/Explorer.Application.Tests/GitCommandIntegrationTests.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
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; }
|
||||
}
|
||||
Reference in New Issue
Block a user