Files
superwork/tui/internal/tui/gitactions_test.go
T
2026-06-23 05:02:15 +08:00

187 lines
5.0 KiB
Go

package tui
import (
"fmt"
"strings"
"testing"
"superwork-tui/internal/config"
"superwork-tui/internal/git"
"superwork-tui/internal/issue"
)
func TestCommitRun_ConfirmGate(t *testing.T) {
m := Model{
state: stateLoaded,
issues: []issue.Issue{{Number: 1}},
buckets: [4][]issue.Issue{{{Number: 1}}},
}
next, _ := m.Update(keyMsg("C"))
nm := next.(Model)
if nm.confirmPend == nil {
t.Fatal("expected confirmPend to be set after C")
}
if nm.confirmPend.action != confirmCommitRun {
t.Errorf("expected confirmCommitRun, got %v", nm.confirmPend.action)
}
}
func TestCommitRun_ConfirmGate_EmptyBoard(t *testing.T) {
// C should work even with no issues selected.
m := Model{state: stateLoaded}
next, _ := m.Update(keyMsg("C"))
nm := next.(Model)
if nm.confirmPend == nil {
t.Fatal("expected confirmPend after C even with empty board")
}
if nm.confirmPend.action != confirmCommitRun {
t.Errorf("expected confirmCommitRun, got %v", nm.confirmPend.action)
}
}
func TestStatusBar_CommitRunConfirm(t *testing.T) {
m := Model{
state: stateLoaded,
confirmPend: &confirmPending{action: confirmCommitRun},
}
bar := m.statusBar()
if bar == "" {
t.Error("expected non-empty status bar for commitRun confirm")
}
if !strings.Contains(bar, "提交") {
t.Errorf("expected '提交' in status bar, got: %s", bar)
}
}
func TestHasChangesIndicator_Visible(t *testing.T) {
m := Model{
state: stateLoaded,
hasChanges: true,
width: 120,
height: 40,
}
view := m.boardView()
if !strings.Contains(view, "未提交") {
t.Error("expected '未提交' indicator in boardView when hasChanges=true")
}
}
func TestHasChangesIndicator_Hidden(t *testing.T) {
m := Model{
state: stateLoaded,
hasChanges: false,
width: 120,
height: 40,
}
view := m.boardView()
if strings.Contains(view, "未提交") {
t.Error("expected no '未提交' indicator when hasChanges=false")
}
}
func TestMergePreview_MKey_WithBranch(t *testing.T) {
iss := issue.Issue{Number: 5, Branch: "feature/test"}
m := Model{
state: stateDetail,
detailIss: &iss,
settings: &config.Settings{DevBranch: "main"},
}
_, cmd := m.Update(keyMsg("M"))
if cmd == nil {
t.Error("expected a cmd from M key with branch set")
}
}
func TestMergePreview_MKey_NoBranch(t *testing.T) {
iss := issue.Issue{Number: 5, Branch: ""}
m := Model{
state: stateDetail,
detailIss: &iss,
settings: &config.Settings{DevBranch: "main"},
}
next, cmd := m.Update(keyMsg("M"))
nm := next.(Model)
if cmd != nil {
t.Error("expected no cmd when no branch")
}
if nm.statusMsg == "" {
t.Error("expected statusMsg set when no branch")
}
}
func TestMergePreviewResultMsg_Clean(t *testing.T) {
m := Model{state: stateLoaded}
msg := mergePreviewResultMsg{
issueNumber: 3,
result: git.MergePreviewResult{Clean: true, Output: "Merge made"},
}
next, _ := m.Update(msg)
nm := next.(Model)
if nm.statusMsg == "" {
t.Error("expected statusMsg from clean merge preview result")
}
if !strings.Contains(nm.statusMsg, "干净") && !strings.Contains(nm.statusMsg, "可") {
t.Errorf("expected positive status message, got: %s", nm.statusMsg)
}
}
func TestMergePreviewResultMsg_Conflict(t *testing.T) {
m := Model{state: stateLoaded}
msg := mergePreviewResultMsg{
issueNumber: 3,
result: git.MergePreviewResult{
Clean: false,
Conflicts: []string{"CONFLICT (content): Merge conflict in file.txt"},
},
err: fmt.Errorf("merge failed"),
}
next, _ := m.Update(msg)
nm := next.(Model)
if nm.statusMsg == "" {
t.Error("expected statusMsg from conflict merge preview result")
}
if !strings.Contains(nm.statusMsg, "冲突") {
t.Errorf("expected '冲突' in statusMsg, got: %s", nm.statusMsg)
}
}
func TestCommitRunMsg_Success(t *testing.T) {
m := Model{state: stateLoaded}
next, _ := m.Update(commitRunMsg{})
nm := next.(Model)
if !strings.Contains(nm.statusMsg, "提交完成") {
t.Errorf("expected '提交完成' in statusMsg, got: %s", nm.statusMsg)
}
}
func TestCommitRunMsg_Error(t *testing.T) {
m := Model{state: stateLoaded}
next, _ := m.Update(commitRunMsg{err: fmt.Errorf("claude failed")})
nm := next.(Model)
if !strings.Contains(nm.statusMsg, "提交失败") {
t.Errorf("expected '提交失败' in statusMsg, got: %s", nm.statusMsg)
}
}
func TestCommitRun_InFlightGuard(t *testing.T) {
// While a commit is running, pressing C must not arm a second confirm.
m := Model{state: stateLoaded, commitRunning: true}
next, _ := m.Update(keyMsg("C"))
if next.(Model).confirmPend != nil {
t.Fatal("C must be a no-op while commitRunning")
}
// Confirming sets the in-flight flag.
m = Model{state: stateLoaded, confirmPend: &confirmPending{action: confirmCommitRun}}
next, _ = m.Update(keyMsg("y"))
if !next.(Model).commitRunning {
t.Fatal("confirming commit/run must set commitRunning")
}
// The result clears the in-flight flag.
cleared, _ := next.(Model).Update(commitRunMsg{})
if cleared.(Model).commitRunning {
t.Fatal("commitRunMsg must clear commitRunning")
}
}