brainfuck_test.gno

6.04 Kb ยท 282 lines
  1package brainfuck
  2
  3import (
  4	"bytes"
  5	"testing"
  6)
  7
  8func TestBasicOperations(t *testing.T) {
  9	tests := []struct {
 10		name     string
 11		code     string
 12		input    string
 13		expected string
 14	}{
 15		{
 16			name:     "Increment and Output",
 17			code:     "+++.",
 18			input:    "",
 19			expected: "\x03",
 20		},
 21		{
 22			name:     "Decrement and Output",
 23			code:     "+++--.",
 24			input:    "",
 25			expected: "\x01",
 26		},
 27		{
 28			name:     "Pointer Movement",
 29			code:     ">+++>++>+<<<.>.>.>.",
 30			input:    "",
 31			expected: "\x00\x03\x02\x01",
 32		},
 33		{
 34			name:     "Pointer at Zero Boundary",
 35			code:     "<<<+++.",
 36			input:    "",
 37			expected: "\x03",
 38		},
 39	}
 40
 41	for _, tc := range tests {
 42		t.Run(tc.name, func(t *testing.T) {
 43			output := Run([]byte(tc.code), []byte(tc.input))
 44			if !bytes.Equal(output, []byte(tc.expected)) {
 45				t.Errorf("Expected %v, got %v", []byte(tc.expected), output)
 46			}
 47		})
 48	}
 49}
 50
 51func TestLoops(t *testing.T) {
 52	tests := []struct {
 53		name     string
 54		code     string
 55		input    string
 56		expected string
 57	}{
 58		{
 59			name:     "Simple Loop",
 60			code:     "+++[>+<-]>.",
 61			input:    "",
 62			expected: "\x03",
 63		},
 64		{
 65			name:     "Nested Loops",
 66			code:     "++[>++[>++<-]<-]>>.",
 67			input:    "",
 68			expected: "\x08",
 69		},
 70		{
 71			name:     "Skip Loop if Zero",
 72			code:     "[>+++<-]>.",
 73			input:    "",
 74			expected: "\x00",
 75		},
 76		{
 77			name:     "Unmatched Opening Bracket",
 78			code:     "[.",
 79			input:    "",
 80			expected: "",
 81		},
 82		{
 83			name:     "Unmatched Closing Bracket",
 84			code:     "].",
 85			input:    "",
 86			expected: "\x00",
 87		},
 88	}
 89
 90	for _, tc := range tests {
 91		t.Run(tc.name, func(t *testing.T) {
 92			output := Run([]byte(tc.code), []byte(tc.input))
 93			if !bytes.Equal(output, []byte(tc.expected)) {
 94				t.Errorf("Expected %v, got %v", []byte(tc.expected), output)
 95			}
 96		})
 97	}
 98}
 99
100func TestInput(t *testing.T) {
101	tests := []struct {
102		name     string
103		code     string
104		input    string
105		expected string
106	}{
107		{
108			name:     "Read Single Input",
109			code:     ",.",
110			input:    "A",
111			expected: "A",
112		},
113		{
114			name:     "Read Multiple Inputs",
115			code:     ",>,>,.",
116			input:    "ABC",
117			expected: "C",
118		},
119		{
120			name:     "Input Modification",
121			code:     ",+.",
122			input:    "A",
123			expected: "B",
124		},
125		{
126			name:     "Input Exhaustion",
127			code:     ",.,.,.,..",
128			input:    "AB",
129			expected: "AB\x00\x00\x00",
130		},
131		{
132			name:     "Output Input Stream",
133			code:     ",[.,]",
134			input:    "hello, world!\n",
135			expected: "hello, world!\n",
136		},
137	}
138
139	for _, tc := range tests {
140		t.Run(tc.name, func(t *testing.T) {
141			output := Run([]byte(tc.code), []byte(tc.input))
142			if !bytes.Equal(output, []byte(tc.expected)) {
143				t.Errorf("Expected %v, got %v", []byte(tc.expected), output)
144			}
145		})
146	}
147}
148
149func TestBsort(t *testing.T) {
150	// [bsort.b -- bubble sort
151	// (c) 2016 Daniel B. Cristofani
152	// http://brainfuck.org/]
153	// [This program sorts the bytes of its input by bubble sort.]
154	code := `
155		>>,[>>,]<<[
156		[<<]>>>>[
157		<<[>+<<+>-]
158		>>[>+<<<<[->]>[<]>>-]
159		<<<[[-]>>[>+<-]>>[<<<+>>>-]]
160		>>[[<+>-]>>]<
161		]<<[>>+<<-]<<
162		]>>>>[.>>]`
163	input := "ckduwcomaz"
164	expected := "accdkmouwz"
165
166	output := Run([]byte(code), []byte(input))
167	if string(output) != expected {
168		t.Errorf("Hello World test failed. Expected '%s', got '%s'", expected, string(output))
169	}
170}
171
172func TestHelloWorld(t *testing.T) {
173	// Classic "Hello World!" program from wikipedia
174	code := `
175+++++ +++++             initialize counter (cell #0) to 10
176[                       use loop to set 70/100/30/10
177    > +++++ ++              add  7 to cell #1
178    > +++++ +++++           add 10 to cell #2
179    > +++                   add  3 to cell #3
180    > +                     add  1 to cell #4
181<<<< -                  decrement counter (cell #0)
182]
183> ++ .                  print 'H'
184> + .                   print 'e'
185+++++ ++ .              print 'l'
186.                       print 'l'
187+++ .                   print 'o'
188> ++ .                  print ' '
189<< +++++ +++++ +++++ .  print 'W'
190> .                     print 'o'
191+++ .                   print 'r'
192----- - .               print 'l'
193----- --- .             print 'd'
194> + .                   print '!'
195> .                     print 'eol'`
196	expected := "Hello World!\n"
197
198	output := Run([]byte(code), []byte{})
199	if string(output) != expected {
200		t.Errorf("Hello World test failed. Expected '%s', got '%s'", expected, string(output))
201	}
202}
203
204func TestEnsureMemory(t *testing.T) {
205	tests := []struct {
206		name        string
207		initialMem  []byte
208		pointer     int
209		expectedLen int
210	}{
211		{
212			name:        "Already Sufficient",
213			initialMem:  []byte{0, 0, 0},
214			pointer:     2,
215			expectedLen: 3,
216		},
217		{
218			name:        "Extend By One",
219			initialMem:  []byte{0, 0, 0},
220			pointer:     3,
221			expectedLen: 4,
222		},
223		{
224			name:        "Extend By Many",
225			initialMem:  []byte{},
226			pointer:     10,
227			expectedLen: 11,
228		},
229	}
230
231	for _, tc := range tests {
232		t.Run(tc.name, func(t *testing.T) {
233			memory := tc.initialMem
234			ensureMemory(&memory, tc.pointer)
235
236			if len(memory) != tc.expectedLen {
237				t.Errorf("Expected memory length %d, got %d", tc.expectedLen, len(memory))
238			}
239
240			// Check that we can access the pointer without panic
241			_ = memory[tc.pointer]
242		})
243	}
244}
245
246// Test various complex programs to ensure the interpreter works correctly
247func TestComplexPrograms(t *testing.T) {
248	tests := []struct {
249		name     string
250		code     string
251		input    string
252		expected string
253	}{
254		{
255			name:     "Multiply Two Numbers",
256			code:     ",>,<[>[->+>+<<]>>[-<<+>>]<<<-]>>.",
257			input:    "\x03\x04", // 3 * 4 = 12
258			expected: "\x0c",     // 12 in ASCII
259		},
260		{
261			name:     "Cat Program",
262			code:     ",[.,]",
263			input:    "Hello!",
264			expected: "Hello!",
265		},
266		{
267			name:     "ASCII to Decimal",
268			code:     ",>++++++[<-------->-]<.", // ASCII value minus 48
269			input:    "5",                       // ASCII 53
270			expected: "\x05",                    // 5 in decimal
271		},
272	}
273
274	for _, tc := range tests {
275		t.Run(tc.name, func(t *testing.T) {
276			output := Run([]byte(tc.code), []byte(tc.input))
277			if !bytes.Equal(output, []byte(tc.expected)) {
278				t.Errorf("Expected %v, got %v", []byte(tc.expected), output)
279			}
280		})
281	}
282}