package workflow import ( "os" "path/filepath" "runtime" "strings" "testing" "github.com/ajhahnde/eeco/internal/config" ) func TestScaffold_CreatesRunnableWorkflow(t *testing.T) { cfg := newCfg(t) dir, err := Scaffold(cfg, "my-check") if err != nil { t.Fatal(err) } want := filepath.Join(cfg.Workspace, "workflows", "my-check") if dir != want { t.Errorf("dir = %q, want %q", dir, want) } entry := filepath.Join(dir, EntryName) info, err := os.Stat(entry) if err != nil { t.Fatalf("entry missing: %v", err) } if runtime.GOOS != "windows" && info.Mode().Perm()&0o100 == 0 { t.Errorf("entry not executable: mode %v", info.Mode()) } body, _ := os.ReadFile(entry) if strings.Contains(string(body), namePlaceholder) { t.Error("placeholder not substituted in run") } if !strings.Contains(string(body), "my-check") { t.Error("workflow name not substituted into run") } readme, err := os.ReadFile(filepath.Join(dir, "README.md")) if err != nil || !strings.Contains(string(readme), "my-check") { t.Errorf("README missing or not substituted: %v", err) } } func TestScaffold_RefusesDuplicate(t *testing.T) { cfg := newCfg(t) if _, err := Scaffold(cfg, "dup"); err != nil { t.Fatal(err) } if _, err := Scaffold(cfg, "dup"); err == nil { t.Error("second scaffold of same name must fail") } } func TestScaffold_RejectsBadNames(t *testing.T) { cfg := newCfg(t) for _, bad := range []string{"", ".", "..", "a/b", "../escape", "Bad_Name", "-leading", "white space"} { if _, err := Scaffold(cfg, bad); err == nil { t.Errorf("name %q should be rejected", bad) } } // Nothing leaked outside the workflows dir. entries, _ := os.ReadDir(filepath.Join(cfg.Workspace, "workflows")) if len(entries) != 0 { t.Errorf("rejected names created entries: %v", entries) } } func TestScaffold_StaysInWorkspace(t *testing.T) { cfg := newCfg(t) if _, err := Scaffold(cfg, "ok-name"); err != nil { t.Fatal(err) } // The only thing created must be under /workflows. if _, err := os.Stat(filepath.Join(cfg.RepoRoot, "ok-name")); !os.IsNotExist(err) { t.Error("scaffold wrote outside the workspace") } } func TestScaffold_ProfileGo_PicksGoTemplate(t *testing.T) { cfg := newCfgWithProfile(t, config.ProfileGo) dir, err := Scaffold(cfg, "go-check") if err != nil { t.Fatal(err) } body, err := os.ReadFile(filepath.Join(dir, EntryName)) if err != nil { t.Fatal(err) } if !strings.Contains(string(body), "go vet ./...") { t.Errorf("go-profile run missing go-specific marker; got:\n%s", body) } if !strings.Contains(string(body), "go-check") { t.Error("workflow name not substituted into go-profile run") } } func TestScaffold_ProfilePython_PicksPythonTemplate(t *testing.T) { cfg := newCfgWithProfile(t, config.ProfilePython) dir, err := Scaffold(cfg, "py-check") if err != nil { t.Fatal(err) } body, err := os.ReadFile(filepath.Join(dir, EntryName)) if err != nil { t.Fatal(err) } if !strings.Contains(string(body), "python3 -m compileall") { t.Errorf("python-profile run missing python-specific marker; got:\n%s", body) } if !strings.Contains(string(body), "py-check") { t.Error("workflow name not substituted into python-profile run") } } func TestScaffold_DeferredProfile_FallsBackToGeneric(t *testing.T) { for _, p := range []config.Profile{config.ProfileZig, config.ProfileRust, config.ProfileNode} { t.Run(string(p), func(t *testing.T) { cfg := newCfgWithProfile(t, p) dir, err := Scaffold(cfg, "fallback-check") if err != nil { t.Fatal(err) } body, err := os.ReadFile(filepath.Join(dir, EntryName)) if err != nil { t.Fatal(err) } s := string(body) if strings.Contains(s, "go vet ./...") || strings.Contains(s, "python3 -m compileall") { t.Errorf("deferred profile %q got a per-language template; want generic stub. body:\n%s", p, s) } if !strings.Contains(s, "passing clean") { t.Errorf("deferred profile %q did not get the generic stub; body:\n%s", p, s) } }) } }