package golang import ( "fmt" "os" "path/filepath" "strings" "testing" ) func TestGolang(t *testing.T) { // Create a new Golang stack instance golangStack := &Golang{} // Test the Name method expectedName := "Golang" if golangStack.Name() != expectedName { t.Errorf("Expected name %s, got %s", expectedName, golangStack.Name()) } } func TestAnalyze(t *testing.T) { golangStack := &Golang{} tests := []struct { name string setup func() string cleanup func(string) expected bool wantErr bool }{ { name: "valid go project with go.mod", setup: func() string { tempDir, _ := os.MkdirTemp("", "test-go-project-") os.WriteFile(filepath.Join(tempDir, "go.mod"), []byte("module test\ngo 1.21\n"), 0644) os.WriteFile(filepath.Join(tempDir, "main.go"), []byte("package main\nfunc main() {}\n"), 0644) return tempDir }, cleanup: func(dir string) { os.RemoveAll(dir) }, expected: true, wantErr: false, }, { name: "valid go project with main.go only", setup: func() string { tempDir, _ := os.MkdirTemp("", "test-go-project-") os.WriteFile(filepath.Join(tempDir, "main.go"), []byte("package main\nfunc main() {}\n"), 0644) return tempDir }, cleanup: func(dir string) { os.RemoveAll(dir) }, expected: true, wantErr: false, }, { name: "non-go project", setup: func() string { tempDir, _ := os.MkdirTemp("", "test-non-go-project-") os.WriteFile(filepath.Join(tempDir, "package.json"), []byte("{}"), 0644) return tempDir }, cleanup: func(dir string) { os.RemoveAll(dir) }, expected: false, wantErr: false, }, { name: "empty directory", setup: func() string { tempDir, _ := os.MkdirTemp("", "test-empty-") return tempDir }, cleanup: func(dir string) { os.RemoveAll(dir) }, expected: false, wantErr: false, }, { name: "non-existent directory", setup: func() string { return "/non/existent/path" }, cleanup: func(dir string) {}, expected: false, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { codebasePath := tt.setup() defer tt.cleanup(codebasePath) isGo, err := golangStack.Analyze(codebasePath) if tt.wantErr && err == nil { t.Errorf("Expected error but got none") } if !tt.wantErr && err != nil { t.Errorf("Unexpected error: %v", err) } if isGo != tt.expected { t.Errorf("Expected %v, got %v", tt.expected, isGo) } }) } } func TestFindMainPackage(t *testing.T) { golangStack := &Golang{} tests := []struct { name string setup func() string cleanup func(string) expected string }{ { name: "main.go in root", setup: func() string { tempDir, _ := os.MkdirTemp("", "test-main-root-") os.WriteFile(filepath.Join(tempDir, "main.go"), []byte("package main\nfunc main() {}\n"), 0644) return tempDir }, cleanup: func(dir string) { os.RemoveAll(dir) }, expected: ".", }, { name: "main.go in cmd/server", setup: func() string { tempDir, _ := os.MkdirTemp("", "test-cmd-server-") cmdDir := filepath.Join(tempDir, "cmd", "server") os.MkdirAll(cmdDir, 0755) os.WriteFile(filepath.Join(cmdDir, "main.go"), []byte("package main\nfunc main() {}\n"), 0644) return tempDir }, cleanup: func(dir string) { os.RemoveAll(dir) }, expected: "./cmd/server", }, { name: "main function in cmd/web-server/app.go", setup: func() string { tempDir, _ := os.MkdirTemp("", "test-cmd-web-server-") cmdDir := filepath.Join(tempDir, "cmd", "web-server") os.MkdirAll(cmdDir, 0755) os.WriteFile(filepath.Join(cmdDir, "app.go"), []byte("package main\nfunc main() {}\n"), 0644) return tempDir }, cleanup: func(dir string) { os.RemoveAll(dir) }, expected: "./cmd/web-server", }, { name: "no main package found", setup: func() string { tempDir, _ := os.MkdirTemp("", "test-no-main-") libDir := filepath.Join(tempDir, "lib") os.MkdirAll(libDir, 0755) os.WriteFile(filepath.Join(libDir, "helper.go"), []byte("package lib\nfunc Helper() {}\n"), 0644) return tempDir }, cleanup: func(dir string) { os.RemoveAll(dir) }, expected: ".", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { codebasePath := tt.setup() defer tt.cleanup(codebasePath) result := golangStack.findMainPackage(codebasePath) if result != tt.expected { t.Errorf("Expected %q, got %q", tt.expected, result) } }) } } func TestAnalyzeGoProject(t *testing.T) { golangStack := &Golang{} // Create a test project structure tempDir, err := os.MkdirTemp("", "test-analyze-project-") if err != nil { t.Fatal(err) } defer os.RemoveAll(tempDir) // Create go.mod goMod := `module github.com/example/web-server go 1.21 require ( github.com/gin-gonic/gin v1.9.1 ) ` os.WriteFile(filepath.Join(tempDir, "go.mod"), []byte(goMod), 0644) // Create cmd/web-server/main.go cmdDir := filepath.Join(tempDir, "cmd", "web-server") os.MkdirAll(cmdDir, 0755) mainGo := `package main import ( "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "Hello World"}) }) r.Run(":8080") } ` os.WriteFile(filepath.Join(cmdDir, "main.go"), []byte(mainGo), 0644) // Run analysis analysis, err := golangStack.analyzeGoProject(tempDir) if err != nil { t.Fatalf("Analysis failed: %v", err) } // Verify results if analysis.GoVersion != "1.21" { t.Errorf("Expected Go version 1.21, got %s", analysis.GoVersion) } if analysis.AppName != "web-server" { t.Errorf("Expected app name 'web-server', got %s", analysis.AppName) } if analysis.MainPackage != "./cmd/web-server" { t.Errorf("Expected main package './cmd/web-server', got %s", analysis.MainPackage) } if analysis.Port != 8080 { t.Errorf("Expected port 8080, got %d", analysis.Port) } if !analysis.RequiresCACerts { t.Error("Expected RequiresCACerts to be true (due to net/http import)") } if !contains(analysis.Modules, "gin") { t.Error("Expected gin module to be detected") } } func TestWebServerProjectStructure(t *testing.T) { // This test specifically replicates the structure from the failed build golangStack := &Golang{} tempDir, err := os.MkdirTemp("", "test-web-server-structure-") if err != nil { t.Fatal(err) } defer os.RemoveAll(tempDir) // Create the directory structure that was failing os.MkdirAll(filepath.Join(tempDir, ".vscode"), 0755) os.MkdirAll(filepath.Join(tempDir, "cmd", "web-server"), 0755) os.MkdirAll(filepath.Join(tempDir, "configs"), 0755) os.MkdirAll(filepath.Join(tempDir, "pkg", "mhttp"), 0755) os.MkdirAll(filepath.Join(tempDir, "scripts"), 0755) os.MkdirAll(filepath.Join(tempDir, "tests"), 0755) os.MkdirAll(filepath.Join(tempDir, "web"), 0755) // Create files os.WriteFile(filepath.Join(tempDir, "LICENSE"), []byte("MIT License"), 0644) os.WriteFile(filepath.Join(tempDir, "go.mod"), []byte("module golang-web-server\ngo 1.18\n"), 0644) // Create the main file in cmd/web-server (this should be detected) os.WriteFile(filepath.Join(tempDir, "cmd", "web-server", "golang-web-server.go"), []byte("package main\nfunc main() {}\n"), 0644) // Create other Go files that should NOT be chosen as main os.WriteFile(filepath.Join(tempDir, "pkg", "mhttp", "server.go"), []byte("package mhttp\nfunc StartServer() {}\n"), 0644) os.WriteFile(filepath.Join(tempDir, "pkg", "mhttp", "functions.go"), []byte("package mhttp\nfunc Handler() {}\n"), 0644) os.WriteFile(filepath.Join(tempDir, "configs", "server-config.go"), []byte("package configs\nvar Config = map[string]string{}\n"), 0644) // Test main package detection mainPackage := golangStack.findMainPackage(tempDir) if mainPackage != "./cmd/web-server" { t.Errorf("Expected main package './cmd/web-server', got '%s'", mainPackage) } // Test full analysis analysis, err := golangStack.analyzeGoProject(tempDir) if err != nil { t.Fatalf("Analysis failed: %v", err) } if analysis.MainPackage != "./cmd/web-server" { t.Errorf("Expected main package './cmd/web-server', got '%s'", analysis.MainPackage) } if analysis.AppName != "golang-web-server" { t.Errorf("Expected app name 'golang-web-server', got '%s'", analysis.AppName) } t.Logf("✅ Correctly detected main package: %s", analysis.MainPackage) t.Logf("✅ Correctly detected app name: %s", analysis.AppName) } func TestBuildCommandGeneration(t *testing.T) { tests := []struct { name string mainPackage string cgoEnabled bool expectedCommand string }{ { name: "root package", mainPackage: ".", cgoEnabled: false, expectedCommand: "go build -ldflags='-w -s -extldflags \"-static\"' -a -installsuffix cgo -o testapp .", }, { name: "cmd subdirectory", mainPackage: "cmd/server", cgoEnabled: false, expectedCommand: "go build -ldflags='-w -s -extldflags \"-static\"' -a -installsuffix cgo -o testapp ./cmd/server", }, { name: "cmd subdirectory with CGO", mainPackage: "cmd/web-server", cgoEnabled: true, expectedCommand: "go build -ldflags='-w -s' -a -installsuffix cgo -o testapp ./cmd/web-server", }, { name: "already has ./ prefix", mainPackage: "./cmd/api", cgoEnabled: false, expectedCommand: "go build -ldflags='-w -s -extldflags \"-static\"' -a -installsuffix cgo -o testapp ./cmd/api", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create test project tempDir, err := os.MkdirTemp("", "build-cmd-test-") if err != nil { t.Fatal(err) } defer os.RemoveAll(tempDir) // Create minimal structure os.WriteFile(filepath.Join(tempDir, "go.mod"), []byte("module testapp\ngo 1.21\n"), 0644) // Mock the analysis result analysis := &GoProjectAnalysis{ AppName: "testapp", MainPackage: tt.mainPackage, CGOEnabled: tt.cgoEnabled, } // Generate build command (simulate the logic from GenerateLLBAdvanced) appName := analysis.AppName if appName == "" { appName = "app" } var buildCmd string mainPackagePath := analysis.MainPackage if mainPackagePath != "." && !strings.HasPrefix(mainPackagePath, "./") { mainPackagePath = "./" + mainPackagePath } if analysis.CGOEnabled { buildCmd = fmt.Sprintf("go build -ldflags='-w -s' -a -installsuffix cgo -o %s %s", appName, mainPackagePath) } else { buildCmd = fmt.Sprintf("go build -ldflags='-w -s -extldflags \"-static\"' -a -installsuffix cgo -o %s %s", appName, mainPackagePath) } if buildCmd != tt.expectedCommand { t.Errorf("Expected command:\n%s\nGot:\n%s", tt.expectedCommand, buildCmd) } t.Logf("✅ Build command: %s", buildCmd) }) } } // Helper function func contains(slice []string, item string) bool { for _, s := range slice { if s == item { return true } } return false }