package emit import ( "strings" "testing" ) func TestParseCompileErrors(t *testing.T) { output := `./main.go:10:2: undefined: Spore ./main.go:15:5: undefined: cfg ./main.go:20:2: "fmt" imported and not used ./main.go:25:2: Node redeclared in this block ` fixes := parseCompileErrors(output) want := map[string]string{ "Spore": "undefined_type", "cfg": "undefined_var", "fmt": "unused_import", "Node": "redeclared", } if len(fixes) != len(want) { t.Fatalf("got %d fixes, want %d", len(fixes), len(want)) } for _, f := range fixes { expectedKind, ok := want[f.name] if !ok { t.Errorf("unexpected fix: %s %s", f.kind, f.name) continue } if f.kind != expectedKind { t.Errorf("fix %s: got kind %q, want %q", f.name, f.kind, expectedKind) } } } func TestParseCompileErrorsDedup(t *testing.T) { output := `./main.go:10:2: undefined: Foo ./main.go:15:2: undefined: Foo ./main.go:20:2: undefined: Foo ` fixes := parseCompileErrors(output) if len(fixes) != 1 { t.Fatalf("got %d fixes, want 1 (deduplication failed)", len(fixes)) } } func TestAddTypeStub(t *testing.T) { source := `package main import "fmt" func main() { var s Spore fmt.Println(s) } ` result := addTypeStub(source, "Spore") if !strings.Contains(result, "type Spore struct{}") { t.Error("type stub not added") } // Verify it's after the import block. importIdx := strings.Index(result, `import "fmt"`) stubIdx := strings.Index(result, "type Spore struct{}") if stubIdx < importIdx { t.Error("stub added before import block") } } func TestAddTypeStubNoDuplicate(t *testing.T) { source := `package main type Spore struct{} func main() {} ` result := addTypeStub(source, "Spore") if strings.Count(result, "Spore") != strings.Count(source, "Spore") { t.Error("duplicate type stub added when type already exists") } } func TestAddVarStub(t *testing.T) { source := `package main func main() { _ = cfg } ` result := addVarStub(source, "cfg") if !strings.Contains(result, "var cfg interface{}") { t.Error("var stub not added") } } func TestRemoveImport(t *testing.T) { source := `package main import ( "fmt" "os" ) func main() { os.Exit(0) } ` result := removeImport(source, "fmt") if strings.Contains(result, `"fmt"`) { t.Error("unused import not removed") } if !strings.Contains(result, `"os"`) { t.Error("used import was incorrectly removed") } } func TestRemoveRedeclaration(t *testing.T) { source := `package main type Foo struct{} type Foo struct{ X int } func main() {} ` result := removeRedeclaration(source, "Foo") count := strings.Count(result, "type Foo ") if count != 1 { t.Errorf("expected 1 declaration of Foo, got %d", count) } } func TestApplyFixes(t *testing.T) { source := `package main import ( "fmt" "os" ) func main() { var s Spore _ = cfg _ = s os.Exit(0) } ` fixes := []fix{ {kind: "undefined_type", name: "Spore"}, {kind: "undefined_var", name: "cfg"}, {kind: "unused_import", name: "fmt"}, } result := applyFixes(source, fixes) if !strings.Contains(result, "type Spore struct{}") { t.Error("type stub not added") } if !strings.Contains(result, "var cfg interface{}") { t.Error("var stub not added") } if strings.Contains(result, `"fmt"`) { t.Error("unused import not removed") } } func TestStubNames(t *testing.T) { source := `package main type Foo struct{} var bar interface{} type Baz struct{ X int } func main() {} ` names := StubNames(source) if len(names) != 2 { t.Fatalf("got %d stubs, want 2: %v", len(names), names) } if names[0] != "Foo" || names[1] != "bar" { t.Errorf("got stubs %v, want [Foo bar]", names) } } func TestIsTypeName(t *testing.T) { tests := []struct { name string want bool }{ {"Spore", true}, {"Node", true}, {"cfg", false}, {"maxSize", false}, {"", false}, } for _, tt := range tests { got := isTypeName(tt.name) if got != tt.want { t.Errorf("isTypeName(%q) = %v, want %v", tt.name, got, tt.want) } } } func TestFindReceiverTypes(t *testing.T) { source := `package main func (x marketSignal) confidence() float64 { return 0 } func (x *Block) Marshal() ([]byte, error) { return nil, nil } func standalone() {} func (x Node) ID() string { return "" } ` types := findReceiverTypes(source) want := map[string]bool{"marketSignal": true, "Block": true, "Node": true} for name := range want { if !types[name] { t.Errorf("expected receiver type %q not found", name) } } if types["standalone"] { t.Error("standalone function incorrectly detected as receiver type") } } func TestEnsureMain(t *testing.T) { // Source without main — should add it. source := "package main\n\nfunc init() {}\n" result := ensureMain(source) if !strings.Contains(result, "func main()") { t.Error("ensureMain did not add main()") } // Source with main — should not duplicate. source2 := "package main\n\nfunc main() {\n\tfmt.Println(\"hello\")\n}\n" result2 := ensureMain(source2) if strings.Count(result2, "func main()") != 1 { t.Error("ensureMain duplicated main()") } } func TestPromoteReceiverFixes(t *testing.T) { fixes := []fix{ {kind: "undefined_var", name: "marketSignal"}, {kind: "undefined_var", name: "cfg"}, {kind: "undefined_type", name: "Block"}, } receivers := map[string]bool{"marketSignal": true} promoteReceiverFixes(fixes, receivers) if fixes[0].kind != "undefined_type" { t.Errorf("marketSignal not promoted: got %s", fixes[0].kind) } if fixes[1].kind != "undefined_var" { t.Errorf("cfg incorrectly promoted: got %s", fixes[1].kind) } if fixes[2].kind != "undefined_type" { t.Errorf("Block changed: got %s", fixes[2].kind) } } func TestInsertAfterImports(t *testing.T) { source := `package main import ( "fmt" ) func main() { fmt.Println("hello") } ` result := insertAfterImports(source, "// INSERTED\n") lines := strings.Split(result, "\n") foundInsert := false for i, line := range lines { if strings.TrimSpace(line) == "// INSERTED" { // Should be after the closing ")" of import. if i > 0 && strings.TrimSpace(lines[i-1]) == ")" { foundInsert = true } break } } if !foundInsert { t.Error("text not inserted after import block") } }