A Golang runtime and compilation backend for Delta Interaction Nets.
at main 192 lines 4.9 kB view raw
1package compiler 2 3import ( 4 "os" 5 "os/exec" 6 "path/filepath" 7 "strings" 8 "testing" 9) 10 11func TestCompileIdentity(t *testing.T) { 12 testCompile(t, "identity", "(x: x) a", "a") 13} 14 15func TestCompileKCombinator(t *testing.T) { 16 testCompile(t, "k_combinator", "(x: y: x) a b", "a") 17} 18 19func TestCompileChurchZero(t *testing.T) { 20 testCompile(t, "church_zero", "f: x: x", "(x0: (x1: x1))") 21} 22 23func TestCompileChurchSucc(t *testing.T) { 24 testCompile(t, "church_succ", 25 "let succ = n: f: x: f (n f x); zero = f: x: x in succ zero", 26 "(x0: (x1: (x0") 27} 28 29func TestCompileFreeVariable(t *testing.T) { 30 testCompile(t, "free_var", "x: y", "(x0: y)") 31} 32 33func TestCompileNestedApp(t *testing.T) { 34 testCompile(t, "nested_app", "((x: y: z: x) a) b c", "a") 35} 36 37func TestCompileSCombinator(t *testing.T) { 38 testCompile(t, "s_combinator", 39 "(x: y: z: (x z) (y z)) (a: a) (b: b) d", 40 "(d d)") 41} 42 43func testCompile(t *testing.T, name string, source string, expected string) { 44 t.Helper() 45 46 // Create temp directory in project root for module support 47 cwd, _ := os.Getwd() 48 projectRoot := filepath.Join(cwd, "../..") 49 tmpDir, err := os.MkdirTemp(projectRoot, "test_build_*") 50 if err != nil { 51 t.Fatalf("Failed to create temp dir: %v", err) 52 } 53 defer os.RemoveAll(tmpDir) 54 55 // Write source file 56 sourceFile := filepath.Join(tmpDir, name+".lam") 57 if err := os.WriteFile(sourceFile, []byte(source), 0644); err != nil { 58 t.Fatalf("Failed to write source file: %v", err) 59 } 60 61 // Compile with absolute output path 62 outputFile := filepath.Join(tmpDir, name) 63 c := Compiler{ 64 SourceFile: sourceFile, 65 OutputName: outputFile, 66 KeepTemp: false, 67 } 68 69 builtFile, err := c.Compile() 70 if err != nil { 71 t.Fatalf("Compilation failed: %v", err) 72 } 73 74 if builtFile != outputFile { 75 t.Fatalf("Output file mismatch: expected %s, got %s", outputFile, builtFile) 76 } 77 78 // Make sure binary exists 79 if _, err := os.Stat(outputFile); os.IsNotExist(err) { 80 t.Fatalf("Output binary not found: %s", outputFile) 81 } 82 defer os.Remove(outputFile) 83 84 // Run the binary 85 cmd := exec.Command(outputFile) 86 output, err := cmd.Output() 87 if err != nil { 88 if exitErr, ok := err.(*exec.ExitError); ok { 89 t.Fatalf("Binary execution failed: %v\nStderr: %s", err, exitErr.Stderr) 90 } 91 t.Fatalf("Binary execution failed: %v", err) 92 } 93 94 // Check result 95 result := strings.TrimSpace(string(output)) 96 if !strings.HasPrefix(result, expected) { 97 t.Errorf("Expected output to start with:\n%s\nGot:\n%s", expected, result) 98 } 99} 100 101func TestCompileWithFlags(t *testing.T) { 102 cwd, _ := os.Getwd() 103 projectRoot := filepath.Join(cwd, "../..") 104 tmpDir, err := os.MkdirTemp(projectRoot, "test_build_*") 105 if err != nil { 106 t.Fatalf("Failed to create temp dir: %v", err) 107 } 108 defer os.RemoveAll(tmpDir) 109 110 sourceFile := filepath.Join(tmpDir, "test.lam") 111 if err := os.WriteFile(sourceFile, []byte("x: x"), 0644); err != nil { 112 t.Fatalf("Failed to write source file: %v", err) 113 } 114 115 // Set custom output name 116 customOut := filepath.Join(tmpDir, "custom_name") 117 118 c := Compiler{ 119 SourceFile: sourceFile, 120 OutputName: customOut, 121 GoFlags: []string{"-v"}, // verbose go build 122 } 123 124 outputFile, err := c.Compile() 125 if err != nil { 126 t.Fatalf("Compilation with flags failed: %v", err) 127 } 128 129 if outputFile != customOut { 130 t.Errorf("Expected output name %s, got %s", customOut, outputFile) 131 } 132 133 if _, err := os.Stat(outputFile); os.IsNotExist(err) { 134 t.Errorf("Custom output file not created: %s", outputFile) 135 } 136} 137 138func TestCompileKeepTemp(t *testing.T) { 139 cwd, _ := os.Getwd() 140 projectRoot := filepath.Join(cwd, "../..") 141 tmpDir, err := os.MkdirTemp(projectRoot, "test_build_*") 142 if err != nil { 143 t.Fatalf("Failed to create temp dir: %v", err) 144 } 145 defer os.RemoveAll(tmpDir) 146 147 sourceFile := filepath.Join(tmpDir, "test.lam") 148 if err := os.WriteFile(sourceFile, []byte("x: x"), 0644); err != nil { 149 t.Fatalf("Failed to write source file: %v", err) 150 } 151 152 outputFile := filepath.Join(tmpDir, "test_keeptemp") 153 c := Compiler{ 154 SourceFile: sourceFile, 155 OutputName: outputFile, 156 KeepTemp: true, 157 } 158 159 builtFile, err := c.Compile() 160 if err != nil { 161 t.Fatalf("Compilation failed: %v", err) 162 } 163 defer os.Remove(builtFile) 164 165 // Note: The temp file is created in /tmp, not next to source 166 // We just verify KeepTemp was respected (stderr message printed) 167 // Actual temp file cleanup is handled by OS 168} 169 170func TestCompileInvalidSource(t *testing.T) { 171 cwd, _ := os.Getwd() 172 projectRoot := filepath.Join(cwd, "../..") 173 tmpDir, err := os.MkdirTemp(projectRoot, "test_build_*") 174 if err != nil { 175 t.Fatalf("Failed to create temp dir: %v", err) 176 } 177 defer os.RemoveAll(tmpDir) 178 179 sourceFile := filepath.Join(tmpDir, "invalid.lam") 180 if err := os.WriteFile(sourceFile, []byte("((("), 0644); err != nil { 181 t.Fatalf("Failed to write source file: %v", err) 182 } 183 184 c := Compiler{ 185 SourceFile: sourceFile, 186 } 187 188 _, err = c.Compile() 189 if err == nil { 190 t.Error("Expected compilation to fail for invalid syntax") 191 } 192}