package engineeringdashboard import ( "context" "errors" "strings" "testing" "time" ) func TestGit_AheadDoesNotClaimRemoteAvailable(t *testing.T) { now := time.Now().UTC() fake := &FakeRunner{Map: map[string]FakeResult{ "git rev-parse --abbrev-ref HEAD": {Stdout: "dev\n"}, "git rev-parse HEAD": {Stdout: "abc123\n"}, "git status --porcelain=v2 --branch": {Stdout: "# branch.head dev\n"}, "git for-each-ref --format=%(refname:short)|%(objectname:short)|%(upstream:short) refs/heads": { Stdout: "dev|abc123|origin/dev\n", }, "git rev-list --left-right --count origin/dev...dev": {Stdout: "0\t3\n"}, "git worktree list --porcelain": {Stdout: "worktree /repo\nHEAD abc123\nbranch refs/heads/dev\n"}, }} res := CollectGit(context.Background(), "/repo", fake, now) if res.Source.Status != SourceOK { t.Fatalf("git source: %+v", res.Source) } if len(res.Branches) != 1 || res.Branches[0].Ahead != 3 { t.Fatalf("expected ahead=3: %+v", res.Branches) } if !strings.Contains(res.Branches[0].RemoteNote, "not network-refreshed") { t.Fatalf("missing remote disclaimer: %+v", res.Branches[0]) } fake.AssertNoForbidden(t) } func TestGit_WorktreeBranchMismatchSurfaced(t *testing.T) { now := time.Now().UTC() fake := &FakeRunner{Map: map[string]FakeResult{ "git rev-parse --abbrev-ref HEAD": {Stdout: "feature/a\n"}, "git rev-parse HEAD": {Stdout: "def\n"}, "git status --porcelain=v2 --branch": {Stdout: "1 .M N... file\n"}, "git for-each-ref --format=%(refname:short)|%(objectname:short)|%(upstream:short) refs/heads": { Stdout: "feature/a|def|\nfeature/b|ghi|\n", }, "git worktree list --porcelain": { Stdout: "worktree /repo\nHEAD def\nbranch refs/heads/feature/a\n\nworktree /repo-wt\nHEAD ghi\nbranch refs/heads/feature/b\n", }, }} res := CollectGit(context.Background(), "/repo", fake, now) var foundB bool for _, b := range res.Branches { if b.Name == "feature/b" && b.Worktree == "/repo-wt" { foundB = true } } if !foundB { t.Fatalf("worktree mapping missing: %+v", res.Branches) } if !res.Repository.Dirty { t.Fatal("expected dirty") } } func TestGit_TimeoutDegradesSource(t *testing.T) { fake := &FakeRunner{Map: map[string]FakeResult{ "git rev-parse --abbrev-ref HEAD": {Err: errors.New("command timed out: git")}, }} res := CollectGit(context.Background(), "/repo", fake, time.Now().UTC()) if res.Source.Status != SourceError { t.Fatalf("expected error source: %+v", res.Source) } } func TestGit_RunnerDeniesFetch(t *testing.T) { r := ExecRunner{} _, _, err := r.Run(context.Background(), "/tmp", "git", "fetch", "origin") if err == nil || !strings.Contains(err.Error(), "denied") { t.Fatalf("expected deny, got %v", err) } }