@@ -20,6 +20,97 @@ import (
2020
2121var updateGolden = flag .Bool ("update" , false , "update golden files" )
2222
23+ const testHarnessCode = `package main
24+
25+ import (
26+ "fmt"
27+ "io/ioutil"
28+ "os"
29+ "path/filepath"
30+ "strings"
31+
32+ _ "github.com/glojurelang/glojure/pkg/codegen/testdata/codegen/test"
33+ "github.com/glojurelang/glojure/pkg/lang"
34+ )
35+
36+ func main() {
37+ // Find all .glj files in testdata directory
38+ // Get the testdata path relative to GOPATH or module root
39+ testdataDir := os.Args[1]
40+ var namespaces []string
41+
42+ err := filepath.Walk(testdataDir, func(path string, info os.FileInfo, err error) error {
43+ if err != nil {
44+ return err
45+ }
46+ if strings.HasSuffix(path, ".glj") {
47+ // Read first line to get namespace
48+ content, err := ioutil.ReadFile(path)
49+ if err != nil {
50+ return err
51+ }
52+ lines := strings.Split(string(content), "\n")
53+ if len(lines) > 0 && strings.HasPrefix(lines[0], "(ns ") {
54+ // Extract namespace name
55+ nsLine := lines[0]
56+ nsLine = strings.TrimPrefix(nsLine, "(ns ")
57+ nsLine = strings.TrimSuffix(nsLine, ")")
58+ parts := strings.Fields(nsLine)
59+ if len(parts) > 0 {
60+ namespaces = append(namespaces, parts[0])
61+ }
62+ }
63+ }
64+ return nil
65+ })
66+ if err != nil {
67+ fmt.Printf("Error walking testdata: %v\n", err)
68+ os.Exit(1)
69+ }
70+
71+ failed := false
72+ for _, nsName := range namespaces {
73+ ns := lang.FindNamespace(lang.NewSymbol(nsName))
74+ if ns == nil {
75+ fmt.Printf("SKIP: namespace %s not found\n", nsName)
76+ continue
77+ }
78+
79+ mainVar := ns.FindInternedVar(lang.NewSymbol("-main"))
80+ if mainVar == nil {
81+ fmt.Printf("SKIP: %s/-main not found\n", nsName)
82+ continue
83+ }
84+
85+ // Check if -main has :expected-output metadata
86+ meta := mainVar.Meta()
87+ if meta == nil {
88+ fmt.Printf("SKIP: %s/-main has no metadata\n", nsName)
89+ continue
90+ }
91+
92+ expected := meta.ValAt(lang.NewKeyword("expected-output"))
93+ if expected == nil {
94+ fmt.Printf("SKIP: %s/-main has no :expected-output\n", nsName)
95+ continue
96+ }
97+
98+ // Run -main and check the result
99+ result := mainVar.Invoke()
100+ if !lang.Equals(result, expected) {
101+ fmt.Printf("FAIL: %s/-main returned %v, expected %v\n", nsName, result, expected)
102+ failed = true
103+ } else {
104+ fmt.Printf("PASS: %s/-main\n", nsName)
105+ }
106+ }
107+
108+ if failed {
109+ os.Exit(1)
110+ }
111+ }
112+ `
113+
23114func TestCodegen (t * testing.T ) {
24115 var testFiles []string
25116 err := filepath .Walk ("testdata" , func (path string , info os.FileInfo , err error ) error {
@@ -93,8 +184,8 @@ func TestCodegen(t *testing.T) {
93184 t .Errorf ("go vet failed for %s: %v\n Stderr:\n %s" , goldenFile , err , stderr .String ())
94185 }
95186
96- // TODO: Compile and run the generated code to verify behavior
97- // This will be added once we have more complete code generation
187+ // Check if namespace has -main function with expected output
188+ testMainFunction ( t , ns )
98189 })
99190 }
100191}
@@ -131,8 +222,61 @@ func getNamespaceFromFile(t *testing.T, filename string) string {
131222 panic ("expected namespace declaration in " + filename )
132223}
133224
134- // TestBehavior verifies that generated code produces the same results as interpreted code
135- func TestBehavior (t * testing.T ) {
136- // This test will be implemented once we can compile and run generated code
137- t .Skip ("Behavioral testing not yet implemented" )
225+ // testMainFunction tests the -main function if it exists and has :expected-output metadata
226+ func testMainFunction (t * testing.T , ns * lang.Namespace ) {
227+ // Look for -main var in the namespace
228+ mainVar := ns .FindInternedVar (lang .NewSymbol ("-main" ))
229+ if mainVar == nil {
230+ // No -main function, nothing to test
231+ return
232+ }
233+
234+ // Check if -main has :expected-output metadata
235+ meta := mainVar .Meta ()
236+ if meta == nil {
237+ return
238+ }
239+
240+ expectedOutput := meta .ValAt (lang .NewKeyword ("expected-output" ))
241+ if expectedOutput == nil {
242+ return
243+ }
244+
245+ // Run -main and check the result
246+ result := mainVar .Invoke ()
247+ if ! lang .Equals (result , expectedOutput ) {
248+ t .Errorf ("-main returned %v, expected %v" , result , expectedOutput )
249+ }
250+ }
251+
252+ // TestGeneratedCode compiles and runs the generated code to verify behavior
253+ func TestGeneratedCode (t * testing.T ) {
254+ // Write the test harness in a temporary directory
255+ tmpDir , err := ioutil .TempDir ("" , "glojure_test_harness" )
256+ if err != nil {
257+ t .Fatal (err )
258+ }
259+ defer os .RemoveAll (tmpDir )
260+
261+ harnessPath := filepath .Join (tmpDir , "harness_main.go" )
262+ if err := ioutil .WriteFile (harnessPath , []byte (testHarnessCode ), 0644 ); err != nil {
263+ t .Fatal (err )
264+ }
265+
266+ // Get absolute path to testdata directory
267+ testdataPath , err := filepath .Abs ("testdata" )
268+ if err != nil {
269+ t .Fatal (err )
270+ }
271+
272+ // Compile and run the test harness
273+ cmd := exec .Command ("go" , "run" , harnessPath , testdataPath )
274+ cmd .Dir = "."
275+ output , err := cmd .CombinedOutput ()
276+ if err != nil {
277+ t .Fatalf ("Test harness failed: %v\n Output:\n %s" , err , output )
278+ }
279+
280+ // Print the output for visibility
281+ t .Logf ("Test harness output:\n %s" , output )
138282}
0 commit comments