package creature import "testing" func runMachineTest( program []int, memory []int, test *testing.T, ) ( machine *Machine[int], ) { machine = &Machine[int]{} machine.LoadProgram(program) if memory != nil { machine.LoadMemory(memory) } err := machine.Execute(0) if err != nil { test.Log("machine exited with error:", err) test.Fail() } return } func TestPush(test *testing.T) { machine := runMachineTest([]int{ PUSH, 3, POP, PUSH, 654, }, nil, test) result := machine.Pop() test.Log("popped:", result) if result != 654 { test.Log("result should be", 654) test.Fail() } } func TestArithmetic(test *testing.T) { machine := runMachineTest([]int{ PUSH, 3, PUSH, 2, ADD, PUSH, 10, PUSH, 4, SUB, PUSH, 2, PUSH, 7, MUL, PUSH, 12, PUSH, 3, DIV, PUSH, 8, PUSH, 6, MOD, }, nil, test) modResult := machine.Pop() divResult := machine.Pop() mulResult := machine.Pop() subResult := machine.Pop() addResult := machine.Pop() test.Log("add:", addResult) test.Log("sub:", subResult) test.Log("mul:", mulResult) test.Log("div:", divResult) test.Log("mod:", modResult) if addResult != 5 { test.Log("add result should be", 5) test.Fail() } if subResult != 6 { test.Log("sub result should be", 6) test.Fail() } if mulResult != 14 { test.Log("mul result should be", 14) test.Fail() } if divResult != 4 { test.Log("div result should be", 4) test.Fail() } if modResult != 2 { test.Log("mod result should be", 2) test.Fail() } } func TestComparison(test *testing.T) { machine := runMachineTest([]int{ PUSH, 6, PUSH, 6, EQ, PUSH, 324, PUSH, 4, GT, PUSH, 4, PUSH, 324, LT, PUSH, 54, PUSH, 6, NEQ, }, nil, test) neqResult := machine.Pop() ltResult := machine.Pop() gtResult := machine.Pop() eqResult := machine.Pop() test.Log("eq:", eqResult) test.Log("gt:", gtResult) test.Log("lt:", ltResult) test.Log("neq:", neqResult) if eqResult != 1 { test.Log("eq result should be", 1) test.Fail() } if gtResult != 1 { test.Log("gt result should be", 1) test.Fail() } if ltResult != 1 { test.Log("lt result should be", 1) test.Fail() } if neqResult != 1 { test.Log("neq result should be", 1) test.Fail() } } func TestPeekPoke(test *testing.T) { machine := runMachineTest([]int{ PUSH, 0, PEEK, PUSH, 29, PUSH, 1, POKE, PUSH, 1, PEEK, }, []int{ 632, 13, }, test) secondResult := machine.Pop() firstResult := machine.Pop() test.Log("first:", firstResult) test.Log("second:", secondResult) if firstResult != 632 { test.Log("first result should be", 632) test.Fail() } if secondResult != 29 { test.Log("second result should be", 29) test.Fail() } } func TestHalt(test *testing.T) { machine := runMachineTest([]int{ PUSH, 32, HALT, PUSH, 3, }, nil, test) result := machine.Pop() test.Log("popped:", result) if result != 32 { test.Log("result should be", 32) test.Fail() } } func TestJump(test *testing.T) { machine := runMachineTest([]int{ PUSH, 1, PUSH, 8, JMP, PUSH, 3, HALT, PUSH, 0, PUSH, 16, JMP, PUSH, 4, HALT, PUSH, 5, }, nil, test) result := machine.Pop() test.Log("popped:", result) if result != 4 { test.Log("result should be", 4) test.Fail() } } func TestRegister(test *testing.T) { output := "" machine := &Machine[int]{} machine.LoadProgram([]int{ PUSH, int('h'), PUSH, 4, CAL, PUSH, int('e'), PUSH, 4, CAL, PUSH, int('l'), PUSH, 4, CAL, PUSH, int('l'), PUSH, 4, CAL, PUSH, int('o'), PUSH, 4, CAL, PUSH, int('r'), PUSH, 4, CAL, PUSH, int('l'), PUSH, 4, CAL, PUSH, int('d'), PUSH, 4, CAL, PUSH, int('!'), PUSH, 4, CAL, }) machine.Register(4, func(machine *Machine[int]) (stop bool) { output += string(rune(machine.Pop())) return }) err := machine.Execute(0) if err != nil { test.Log("machine exited with error:", err) test.Fail() } test.Log("printed:", output) if output != "hellorld!" { test.Log("result should be", "hellorld!") test.Fail() } }