blob: 1c902b1651de6dcd0104324aecdf5aaa159ed340 [file] [log] [blame]
Sketch🕴️cd59d222026-02-28 19:28:26 +04001package repl
2
3import (
4 "bytes"
5 "strings"
6 "testing"
7)
8
9func TestRun_SingleExpression(t *testing.T) {
10 in := strings.NewReader("1 + 2\n")
11 var out bytes.Buffer
12
13 Run(in, &out)
14
15 got := out.String()
16 if !strings.Contains(got, "3") {
17 t.Errorf("expected output to contain '3', got %q", got)
18 }
19}
20
21func TestRun_MultipleExpressions(t *testing.T) {
22 in := strings.NewReader("1 + 2\n3 * 4\n")
23 var out bytes.Buffer
24
25 Run(in, &out)
26
27 got := out.String()
28 if !strings.Contains(got, "3") {
29 t.Errorf("expected output to contain '3', got %q", got)
30 }
31 if !strings.Contains(got, "12") {
32 t.Errorf("expected output to contain '12', got %q", got)
33 }
34}
35
36func TestRun_ErrorContinues(t *testing.T) {
37 // First line has error, second is valid.
38 in := strings.NewReader("1 +\n2 + 3\n")
39 var out bytes.Buffer
40
41 Run(in, &out)
42
43 got := out.String()
44 if !strings.Contains(got, "error:") {
45 t.Errorf("expected output to contain 'error:', got %q", got)
46 }
47 if !strings.Contains(got, "5") {
48 t.Errorf("expected output to contain '5' after error recovery, got %q", got)
49 }
50}
51
52func TestRun_DivisionByZero(t *testing.T) {
53 in := strings.NewReader("1 / 0\n")
54 var out bytes.Buffer
55
56 Run(in, &out)
57
58 got := out.String()
59 if !strings.Contains(got, "error:") {
60 t.Errorf("expected output to contain 'error:', got %q", got)
61 }
62 if !strings.Contains(got, "division by zero") {
63 t.Errorf("expected 'division by zero' in output, got %q", got)
64 }
65}
66
67func TestRun_EmptyLine(t *testing.T) {
68 // Empty lines should be skipped, not cause errors.
69 in := strings.NewReader("\n1 + 1\n")
70 var out bytes.Buffer
71
72 Run(in, &out)
73
74 got := out.String()
75 if !strings.Contains(got, "2") {
76 t.Errorf("expected output to contain '2', got %q", got)
77 }
78 // Should not contain any error.
79 if strings.Contains(got, "error:") {
80 t.Errorf("empty line should not produce error, got %q", got)
81 }
82}
83
84func TestRun_Prompt(t *testing.T) {
85 in := strings.NewReader("42\n")
86 var out bytes.Buffer
87
88 Run(in, &out)
89
90 got := out.String()
91 if !strings.Contains(got, ">> ") {
92 t.Errorf("expected prompt '>> ' in output, got %q", got)
93 }
94}
95
96func TestRun_FloatResult(t *testing.T) {
97 in := strings.NewReader("7 / 2\n")
98 var out bytes.Buffer
99
100 Run(in, &out)
101
102 got := out.String()
103 if !strings.Contains(got, "3.5") {
104 t.Errorf("expected output to contain '3.5', got %q", got)
105 }
106}
107
108func TestRun_InvalidCharacter(t *testing.T) {
109 in := strings.NewReader("1 @ 2\n")
110 var out bytes.Buffer
111
112 Run(in, &out)
113
114 got := out.String()
115 if !strings.Contains(got, "error:") {
116 t.Errorf("expected output to contain 'error:', got %q", got)
117 }
118}
119
120func TestRun_EmptyInput(t *testing.T) {
121 // No input at all — just EOF.
122 in := strings.NewReader("")
123 var out bytes.Buffer
124
125 Run(in, &out)
126
127 got := out.String()
128 // Should just show the prompt and exit gracefully.
129 if !strings.Contains(got, ">> ") {
130 t.Errorf("expected at least one prompt, got %q", got)
131 }
132}
133
134func TestRun_WholeIntegerNoTrailingZeros(t *testing.T) {
135 // 2 + 3 = 5, should print "5" not "5.000000".
136 in := strings.NewReader("2 + 3\n")
137 var out bytes.Buffer
138
139 Run(in, &out)
140
141 got := out.String()
142 // Result line is "5\n" (between prompts).
143 if !strings.Contains(got, "5\n") {
144 t.Errorf("expected '5\\n' in output, got %q", got)
145 }
146 // Should not contain "5.0"
147 if strings.Contains(got, "5.0") {
148 t.Errorf("expected no trailing zeros, got %q", got)
149 }
150}