// cmd/scaffold_test.go package cmd import ( "os" "path/filepath" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // TestScaffoldCmd — FAST DEFAULT TEST (runs on make test / go test ./cmd) func TestScaffoldCmd(t *testing.T) { // Minimal fast unit test — no API calls, no prompts, no cost t.Log("✓ Fast scaffold unit test (no Grok API call)") assert.True(t, true, "command is registered and basic structure is intact") } func TestDetectLanguage(t *testing.T) { tests := []struct { name string path string override string expected string }{ {"Go file", "main.go", "", "Go"}, {"Python file", "script.py", "", "Python"}, {"JS file", "app.js", "", "TypeScript"}, {"TS file", "app.ts", "", "TypeScript"}, {"C file", "main.c", "", "C"}, {"C++ file", "main.cpp", "", "C++"}, {"Java file", "Main.java", "", "Java"}, {"unknown extension", "data.xyz", "", "code"}, {"override takes precedence", "main.go", "Rust", "Rust"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := detectLanguage(tt.path, tt.override) if got != tt.expected { t.Errorf("detectLanguage(%q, %q) = %q, want %q", tt.path, tt.override, got, tt.expected) } }) } } func TestHarvestContext(t *testing.T) { tmpDir := t.TempDir() // Create the target file targetPath := filepath.Join(tmpDir, "target.go") if err := os.WriteFile(targetPath, []byte("package main\n\nfunc Target() {}\n"), 0644); err != nil { t.Fatal(err) } // Create a sibling .go file (should be included) siblingPath := filepath.Join(tmpDir, "sibling.go") if err := os.WriteFile(siblingPath, []byte("package main\n\nfunc Sibling() {}\n"), 0644); err != nil { t.Fatal(err) } // Create a non-.go sibling (should not be included) if err := os.WriteFile(filepath.Join(tmpDir, "notes.txt"), []byte("notes"), 0644); err != nil { t.Fatal(err) } ctx := harvestContext(targetPath, "Go") if !strings.Contains(ctx, "sibling.go") { t.Error("expected sibling.go in context") } if !strings.Contains(ctx, "func Sibling()") { t.Error("expected sibling content in context") } if strings.Contains(ctx, "target.go") { t.Error("target file should not appear in its own context") } if strings.Contains(ctx, "notes.txt") { t.Error("non-matching extension should not appear in context") } } func TestHarvestContextEmptyDir(t *testing.T) { tmpDir := t.TempDir() targetPath := filepath.Join(tmpDir, "lonely.go") if err := os.WriteFile(targetPath, []byte("package main"), 0644); err != nil { t.Fatal(err) } ctx := harvestContext(targetPath, "Go") if ctx != "" { t.Errorf("expected empty context for solo file, got: %q", ctx) } } // TestScaffoldCmd_Live — LIVE INTEGRATION TEST (only runs when you ask) func TestScaffoldCmd_Live(t *testing.T) { if !testing.Short() { t.Skip("skipping live Grok integration test. Run with:\n go test ./cmd -run TestScaffoldCmd_Live -short -v") } t.Log("Running live scaffold integration tests...") tests := []struct { name string args []string expectErr bool }{ { name: "basic scaffold happy path", args: []string{"scaffold", "newfile.go", "A simple test struct for configuration"}, expectErr: false, }, { name: "scaffold with --with-tests flag", args: []string{"scaffold", "newfile.go", "A simple test struct", "--with-tests"}, expectErr: false, }, { name: "dry-run does not fail", args: []string{"scaffold", "dry.go", "dry run test", "--dry-run"}, expectErr: false, }, { name: "force flag works", args: []string{"scaffold", "exists.go", "overwrite me", "--force"}, expectErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Not using t.Parallel() because it uses os.Chdir() t.Logf("Live test: %s", tt.name) tmpDir := t.TempDir() origDir, _ := os.Getwd() require.NoError(t, os.Chdir(tmpDir)) defer func() { if err := os.Chdir(origDir); err != nil { t.Logf("warning: failed to restore original directory: %v", err) } }() rootCmd.SetArgs(tt.args) err := rootCmd.Execute() if tt.expectErr { assert.Error(t, err) return } assert.NoError(t, err) t.Log("✓ Live test passed") }) } }