package sdlc import ( "os" "path/filepath" "testing" ) func setupTestSDLC(t *testing.T) string { t.Helper() root := t.TempDir() if err := Init(root, "test-project"); err != nil { t.Fatalf("init failed: %v", err) } return root } func TestCreateBranch(t *testing.T) { root := setupTestSDLC(t) cfg := DefaultConfig("test") // Create a feature and transition to planned phase (branch creation requires planned or later) f, err := CreateFeature(root, "auth-flow", "Auth Flow") if err != nil { t.Fatalf("create feature: %v", err) } f.Phase = PhasePlanned if err := f.Save(root); err != nil { t.Fatalf("save feature: %v", err) } manifest, err := CreateBranch(root, "auth-flow", cfg) if err != nil { t.Fatalf("create branch: %v", err) } if manifest.Name != "feature/auth-flow" { t.Errorf("Name = %q, want feature/auth-flow", manifest.Name) } if manifest.Feature != "auth-flow" { t.Errorf("Feature = %q, want auth-flow", manifest.Feature) } if manifest.BaseBranch != "main" { t.Errorf("BaseBranch = %q, want main", manifest.BaseBranch) } // Verify feature was updated with branch reference f, err = LoadFeature(root, "auth-flow") if err != nil { t.Fatalf("load feature: %v", err) } if f.Branch != "feature/auth-flow" { t.Errorf("Feature.Branch = %q, want feature/auth-flow", f.Branch) } } func TestCreateBranch_AlreadyExists(t *testing.T) { root := setupTestSDLC(t) cfg := DefaultConfig("test") f, err := CreateFeature(root, "auth-flow", "Auth Flow") if err != nil { t.Fatalf("create feature: %v", err) } f.Phase = PhasePlanned if err := f.Save(root); err != nil { t.Fatalf("save feature: %v", err) } if _, err := CreateBranch(root, "auth-flow", cfg); err != nil { t.Fatalf("create branch: %v", err) } _, err = CreateBranch(root, "auth-flow", cfg) if err != ErrBranchExists { t.Errorf("err = %v, want ErrBranchExists", err) } } func TestCreateBranch_FeatureNotFound(t *testing.T) { root := setupTestSDLC(t) cfg := DefaultConfig("test") _, err := CreateBranch(root, "nonexistent", cfg) if err != ErrFeatureNotFound { t.Errorf("err = %v, want ErrFeatureNotFound", err) } } func TestLoadBranch(t *testing.T) { root := setupTestSDLC(t) cfg := DefaultConfig("test") f, err := CreateFeature(root, "auth-flow", "Auth Flow") if err != nil { t.Fatalf("create feature: %v", err) } f.Phase = PhasePlanned if err := f.Save(root); err != nil { t.Fatalf("save feature: %v", err) } _, err = CreateBranch(root, "auth-flow", cfg) if err != nil { t.Fatalf("create branch: %v", err) } manifest, err := LoadBranch(root, "feature/auth-flow") if err != nil { t.Fatalf("load branch: %v", err) } if manifest.Name != "feature/auth-flow" { t.Errorf("Name = %q, want feature/auth-flow", manifest.Name) } } func TestLoadBranch_NotFound(t *testing.T) { root := setupTestSDLC(t) _, err := LoadBranch(root, "nonexistent") if err != ErrBranchNotFound { t.Errorf("err = %v, want ErrBranchNotFound", err) } } func TestSaveBranch(t *testing.T) { root := setupTestSDLC(t) manifest := &BranchManifest{ Name: "feature/test", Feature: "test", BaseBranch: "main", } if err := SaveBranch(root, manifest); err != nil { t.Fatalf("save branch: %v", err) } // Verify file exists path := filepath.Join(root, SDLCDir, BranchesDir, "feature/test.yaml") if _, err := os.Stat(path); os.IsNotExist(err) { t.Error("branch manifest file not created") } } func TestMergeChecklist_NotReady(t *testing.T) { root := setupTestSDLC(t) _, err := CreateFeature(root, "auth-flow", "Auth Flow") if err != nil { t.Fatalf("create feature: %v", err) } unmet, err := MergeChecklist(root, "auth-flow") if err != nil { t.Fatalf("merge checklist: %v", err) } if len(unmet) == 0 { t.Error("expected unmet gates, got none") } } func TestMergeChecklist_Ready(t *testing.T) { root := setupTestSDLC(t) f, err := CreateFeature(root, "auth-flow", "Auth Flow") if err != nil { t.Fatalf("create feature: %v", err) } // Set up all gates as passed and transition to merge phase f.Phase = PhaseMerge f.GetArtifact(ArtifactReview).MarkPassed() f.GetArtifact(ArtifactAudit).MarkPassed() f.GetArtifact(ArtifactQAResults).MarkPassed() if err := f.Save(root); err != nil { t.Fatalf("save feature: %v", err) } unmet, err := MergeChecklist(root, "auth-flow") if err != nil { t.Fatalf("merge checklist: %v", err) } if len(unmet) != 0 { t.Errorf("expected 0 unmet gates, got %d: %v", len(unmet), unmet) } } func TestMergeChecklist_FeatureNotFound(t *testing.T) { root := setupTestSDLC(t) _, err := MergeChecklist(root, "nonexistent") if err != ErrFeatureNotFound { t.Errorf("err = %v, want ErrFeatureNotFound", err) } }