ajhahn.de
← eeco
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)
			}
		})
	}
}