using Explorer.Application; using Explorer.Domain; namespace Explorer.Application.Tests; public class GitPorcelainParserTests { [Fact] public void Parses_branch_counts_and_ahead_behind() { var status = GitPorcelainParser.Parse(""" # branch.oid abcdef1234567890 # branch.head main # branch.upstream origin/main # branch.ab +2 -1 1 .M N... 100644 100644 100644 a a src/App.cs 1 M. N... 100644 100644 100644 b b README.md 2 R. N... 100644 100644 100644 c c R100 old.txt new.txt ? bin/out.dll ? notes.md ! ignore.me """, @"C:\src"); Assert.NotNull(status); Assert.Equal("main", status.Branch); Assert.Equal(3, status.ModifiedCount); Assert.Equal(2, status.UntrackedCount); Assert.Equal(2, status.Ahead); Assert.Equal(1, status.Behind); Assert.False(status.WorkingTreeClean); Assert.Equal("main · 3 modified · 2 untracked · 2 ahead · 1 behind", status.Badge); } [Fact] public void Clean_tree_uses_detached_oid_prefix() { var status = GitPorcelainParser.Parse(""" # branch.oid 0123456789abcdef # branch.head (detached) """, @"F:\repo"); Assert.NotNull(status); Assert.Equal("0123456", status.Branch); Assert.True(status.WorkingTreeClean); Assert.Equal("0123456 · clean", status.Badge); } [Fact] public void Empty_output_is_null() => Assert.Null(GitPorcelainParser.Parse("", @"C:\src")); } public class GitLocatorTests { [Fact] public void Prefers_the_configured_path_when_it_exists() { var path = @"C:\Tools\git.exe"; Assert.Equal(path, GitLocator.Find(path, fileExists: p => p == path, pathVariable: "")); } [Fact] public void Finds_git_on_PATH() { var found = GitLocator.Find( null, fileExists: p => p.Equals(@"D:\bin\git.exe", StringComparison.OrdinalIgnoreCase), pathVariable: @"C:\Windows;D:\bin"); Assert.Equal(@"D:\bin\git.exe", found); } [Fact] public void Returns_null_when_git_is_missing() => Assert.Null(GitLocator.Find(null, fileExists: _ => false, pathVariable: @"C:\none")); } public class GitRepoDetectorTests { [Fact] public void Finds_the_repo_root_from_a_nested_path() { var dirs = new HashSet(StringComparer.OrdinalIgnoreCase) { @"C:\src", @"C:\src\.git", @"C:\src\app" }; var files = new HashSet(StringComparer.OrdinalIgnoreCase); Assert.Equal(@"C:\src", GitRepoDetector.FindRoot(@"C:\src\app\Main.cs", dirs.Contains, files.Contains)); Assert.True(GitRepoDetector.IsRepoRoot(@"C:\src", dirs.Contains, files.Contains)); Assert.False(GitRepoDetector.IsRepoRoot(@"C:\src\app", dirs.Contains, files.Contains)); } [Fact] public void Treats_a_gitfile_as_a_worktree_root() { var dirs = new HashSet(StringComparer.OrdinalIgnoreCase) { @"C:\work" }; var files = new HashSet(StringComparer.OrdinalIgnoreCase) { @"C:\work\.git" }; Assert.Equal(@"C:\work", GitRepoDetector.FindRoot(@"C:\work", dirs.Contains, files.Contains)); } [Fact] public void Virtual_roots_are_not_repos() => Assert.Null(GitRepoDetector.FindRoot(LocationRoots.ThisPc, _ => true, _ => true)); }