test(04-04): close scaffold and CLI command boundary coverage
- Compile and vet every generated artifact in a copied hello workspace - Reject malformed names, traversal, and duplicates through public Make* - Cover CLI argument forms, --no-migration, and one-arg make inside a plugin Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -25,17 +25,41 @@ func TestToolCommandNames(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
helpWants := map[string][]string{
|
||||
"make:plugin": {"vendor.plugin"},
|
||||
"make:model": {"[plugin] [name]", "no-migration"},
|
||||
"make:migration": {"[plugin] [name]"},
|
||||
"make:command": {"[plugin] [name]"},
|
||||
"make:job": {"[plugin] [name]"},
|
||||
"make:admin-controller": {"[plugin] [name]"},
|
||||
}
|
||||
for cmd, wants := range helpWants {
|
||||
var buf bytes.Buffer
|
||||
root, err := bonfire.NewRoot("summer", toolCommands(), &buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root.SetArgs([]string{cmd, "--help"})
|
||||
if err := root.Execute(); err != nil {
|
||||
t.Fatalf("%s --help: %v", cmd, err)
|
||||
}
|
||||
out := buf.String()
|
||||
for _, want := range wants {
|
||||
if !strings.Contains(out, want) {
|
||||
t.Fatalf("%s help missing %q:\n%s", cmd, want, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
root, err := bonfire.NewRoot("summer", toolCommands(), &buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root.SetArgs([]string{"make:plugin", "--help"})
|
||||
if err := root.Execute(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(buf.String(), "vendor.plugin") {
|
||||
t.Fatalf("make:plugin help missing argument text:\n%s", buf.String())
|
||||
root.SetArgs([]string{"make:model"})
|
||||
err = root.Execute()
|
||||
if err == nil || !strings.Contains(err.Error(), "vendor.plugin") || !strings.Contains(err.Error(), "Name") {
|
||||
t.Fatalf("make:model missing args error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,3 +92,121 @@ func TestToolDoesNotImportExamplePlugins(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeCommandsViaCLI(t *testing.T) {
|
||||
dir := copyHelloApp(t)
|
||||
t.Chdir(dir)
|
||||
|
||||
runSummer := func(args ...string) string {
|
||||
t.Helper()
|
||||
var buf bytes.Buffer
|
||||
root, err := bonfire.NewRoot("summer", toolCommands(), &buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root.SetArgs(args)
|
||||
if err := root.Execute(); err != nil {
|
||||
t.Fatalf("%v: %v\n%s", args, err, buf.String())
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
out := runSummer("make:plugin", "golem15.demo")
|
||||
if !strings.Contains(out, filepath.Join("plugins", "demo")) {
|
||||
t.Fatalf("make:plugin output missing plugin dir:\n%s", out)
|
||||
}
|
||||
pluginDir := filepath.Join(dir, "plugins", "demo")
|
||||
if _, err := os.Stat(filepath.Join(pluginDir, "plugin.go")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
out = runSummer("make:model", "golem15.demo", "Album", "--no-migration")
|
||||
if !strings.Contains(out, filepath.Join("models", "album.go")) {
|
||||
t.Fatalf("make:model output missing album.go:\n%s", out)
|
||||
}
|
||||
if strings.Contains(out, "create_golem15_demo_albums") {
|
||||
t.Fatalf("--no-migration still printed a migration:\n%s", out)
|
||||
}
|
||||
|
||||
out = runSummer("make:job", "golem15.demo", "Reindex")
|
||||
if !strings.Contains(out, filepath.Join("jobs", "reindex.go")) {
|
||||
t.Fatalf("make:job output missing reindex.go:\n%s", out)
|
||||
}
|
||||
|
||||
t.Chdir(pluginDir)
|
||||
out = runSummer("make:command", "Purge")
|
||||
if !strings.Contains(out, filepath.Join("console", "purge.go")) {
|
||||
t.Fatalf("one-arg make:command output missing purge.go:\n%s", out)
|
||||
}
|
||||
|
||||
pluginGo, err := os.ReadFile(filepath.Join(pluginDir, "plugin.go"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Contains(pluginGo, []byte("generatedJobs()")) {
|
||||
t.Fatal("scaffold plugin.go should already call generated accessors")
|
||||
}
|
||||
}
|
||||
|
||||
func copyHelloApp(t *testing.T) string {
|
||||
t.Helper()
|
||||
src, err := filepath.Abs(filepath.Join("..", "..", "examples", "hello"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
framework, err := filepath.Abs(filepath.Join("..", ".."))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dst := t.TempDir()
|
||||
if err := filepath.WalkDir(src, func(path string, d os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rel, err := filepath.Rel(src, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rel == "bin" || strings.HasPrefix(rel, "bin"+string(os.PathSeparator)) {
|
||||
if d.IsDir() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
target := filepath.Join(dst, rel)
|
||||
if d.IsDir() {
|
||||
return os.MkdirAll(target, 0o755)
|
||||
}
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if filepath.Base(path) == "go.mod" {
|
||||
data = rewriteFrameworkReplace(data, framework)
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(target, data, 0o644)
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func rewriteFrameworkReplace(data []byte, framework string) []byte {
|
||||
const module = "git.golem15.com/golem15/summercms"
|
||||
lines := strings.Split(string(data), "\n")
|
||||
for i, line := range lines {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
switch {
|
||||
case strings.HasPrefix(trimmed, "replace "+module+" =>"):
|
||||
indent := line[:len(line)-len(strings.TrimLeft(line, " \t"))]
|
||||
lines[i] = indent + "replace " + module + " => " + framework
|
||||
case strings.HasPrefix(trimmed, module+" =>"):
|
||||
indent := line[:len(line)-len(strings.TrimLeft(line, " \t"))]
|
||||
lines[i] = indent + module + " => " + framework
|
||||
}
|
||||
}
|
||||
return []byte(strings.Join(lines, "\n"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user