package lox import ( "bytes" "fmt" "io" "os" "testing" ) func TestRun(t *testing.T) { old := os.Stdout // keep backup of the real stdout r, w, err := os.Pipe() if err != nil { t.Fatal(err) } os.Stdout = w outC := make(chan string) // copy the output in a separate goroutine so printing can't block indefinitely go func() { var buf bytes.Buffer io.Copy(&buf, r) outC <- buf.String() }() source := "print('Hello, World!');" l := New() l.run(source) // back to normal state w.Close() os.Stdout = old // restoring the real stdout out := <-outC // reading our temp stdout expected := source + "\n" if out != expected { t.Errorf("run() = %v; want %v", out, expected) } } func TestRunFile(t *testing.T) { old := os.Stdout // keep backup of the real stdout r, w, err := os.Pipe() if err != nil { t.Fatal(err) } os.Stdout = w outC := make(chan string) // copy the output in a separate goroutine so printing can't block indefinitely go func() { var buf bytes.Buffer io.Copy(&buf, r) outC <- buf.String() }() // Create a temporary file with some content tmpfile, err := os.CreateTemp("", "example.*.txt") if err != nil { t.Fatal(err) } defer os.Remove(tmpfile.Name()) content := "print('Hello, World!');" if _, err := tmpfile.Write([]byte(content)); err != nil { t.Fatal(err) } if err := tmpfile.Close(); err != nil { t.Fatal(err) } l := New() l.RunFile(tmpfile.Name()) // back to normal state w.Close() os.Stdout = old // restoring the real stdout out := <-outC // reading our temp stdout expected := "print('Hello, World!');\n" if out != expected { t.Errorf("RunFile() = %v; want %v", out, expected) } } func TestError(t *testing.T) { old := os.Stdout // keep backup of the real stdout r, w, err := os.Pipe() if err != nil { t.Fatal(err) } os.Stdout = w outC := make(chan string) // copy the output in a separate goroutine so printing can't block indefinitely go func() { var buf bytes.Buffer io.Copy(&buf, r) outC <- buf.String() }() line := 1 message := "Unexpected character." l := New() l.Error(line, message) // back to normal state w.Close() os.Stdout = old // restoring the real stdout out := <-outC // reading our temp stdout expected := fmt.Sprintf("[line %d] Error : %s\n", line, message) if out != expected { t.Errorf("Error() = %v; want %v", out, expected) } } func TestReport(t *testing.T) { old := os.Stdout // keep backup of the real stdout r, w, err := os.Pipe() if err != nil { t.Fatal(err) } os.Stdout = w outC := make(chan string) // copy the output in a separate goroutine so printing can't block indefinitely go func() { var buf bytes.Buffer io.Copy(&buf, r) outC <- buf.String() }() line := 1 where := "at 'foo'" message := "Unexpected character." l := New() l.report(line, where, message) // back to normal state w.Close() os.Stdout = old // restoring the real stdout out := <-outC // reading our temp stdout expected := fmt.Sprintf("[line %d] Error %s: %s\n", line, where, message) if out != expected { t.Errorf("report() = %v; want %v", out, expected) } } func TestRunPrompt(t *testing.T) { oldStdin := os.Stdin oldStdout := os.Stdout rIn, wIn, _ := os.Pipe() rOut, wOut, _ := os.Pipe() os.Stdin = rIn os.Stdout = wOut outC := make(chan string) go func() { var buf bytes.Buffer io.Copy(&buf, rOut) outC <- buf.String() }() input := "print('Hello, World!');\n\n" wIn.Write([]byte(input)) wIn.Close() l := New() l.RunPrompt() wOut.Close() os.Stdin = oldStdin os.Stdout = oldStdout out := <-outC expected := "> print('Hello, World!');\n\n> " if out != expected { t.Errorf("RunPrompt() = %v; want %v", out, expected) } }