Go 138 lines
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 <workspace>/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)
}
})
}
}