187 lines
5.0 KiB
Go
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")
|
|
}
|
|
}
|