From 664006b1c42aae84a3c749d9b71c1047e0b8ffcf Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Thu, 2 Mar 2023 20:03:52 -0800 Subject: Initial commit. --- vm/test/vm_test.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 vm/test/vm_test.c (limited to 'vm/test/vm_test.c') diff --git a/vm/test/vm_test.c b/vm/test/vm_test.c new file mode 100644 index 0000000..2d1a91f --- /dev/null +++ b/vm/test/vm_test.c @@ -0,0 +1,182 @@ +#include "vm.h" + +#include "test.h" + +#include + +/// Create and destroy a vm. +TEST_CASE(vm_create_destroy) { + Vm* vm = vm_new(); + TEST_TRUE(vm != 0); + vm_del(&vm); +} + +// Exit with an implicit 0 exit code. +TEST_CASE(vm_exit_implicit) { + // clang-format off + const Inst instructions[] = { + vmExit(), + }; + // clang-format on + + Vm* vm = vm_new(); + TEST_TRUE(vm != 0); + const int exit_code = + vm_run(vm, instructions, sizeof(instructions) / sizeof(Inst)); + TEST_TRUE(exit_code == 0); + vm_del(&vm); +} + +// Exit with an explicit exit code. +TEST_CASE(vm_exit_explicit) { + const int32_t expected = 17; + + // clang-format off + const Inst instructions[] = { + vmPushI32(expected), + vmExit(), + }; + // clang-format on + + Vm* vm = vm_new(); + TEST_TRUE(vm != 0); + const int exit_code = + vm_run(vm, instructions, sizeof(instructions) / sizeof(Inst)); + TEST_TRUE(exit_code == expected); + vm_del(&vm); +} + +/// Add two i32 numbers. +TEST_CASE(vm_add_i32) { + const int n1 = 2; + const int n2 = 3; + + // clang-format off + const Inst instructions[] = { + vmPushI32(n1), + vmPushI32(n2), + vmAdd(I32), + vmExit(), + }; + // clang-format on + + Vm* vm = vm_new(); + TEST_TRUE(vm != 0); + const int exit_code = + vm_run(vm, instructions, sizeof(instructions) / sizeof(Inst)); + TEST_EQUAL(exit_code, n1 + n2); + vm_del(&vm); +} + +/// Sum an array of numbers with 4 add instructions. +TEST_CASE(vm_sum_array_i32_explicit) { + const int vals[5] = {1, 2, 3, 4, 5}; + + // clang-format off + const Inst instructions[] = { + vmPushI32(vals[0]), + vmPushI32(vals[1]), + vmPushI32(vals[2]), + vmPushI32(vals[3]), + vmPushI32(vals[4]), + vmAdd(I32), + vmAdd(I32), + vmAdd(I32), + vmAdd(I32), + vmExit(), + }; + // clang-format on + + int sum = 0; + for (size_t i = 0; i < sizeof(vals) / sizeof(vals[0]); ++i) { + sum += vals[i]; + } + + Vm* vm = vm_new(); + TEST_TRUE(vm != 0); + const int exit_code = + vm_run(vm, instructions, sizeof(instructions) / sizeof(Inst)); + TEST_EQUAL(exit_code, sum); + vm_del(&vm); +} + +/// Sum an array of numbers with a loop. +TEST_CASE(vm_sum_array_i32_loop) { + const int vals[5] = {1, 2, 3, 4, 5}; + + const Label loop_label = 0; + const Label counter_index = 0; + + // clang-format off + const Inst instructions[] = { + vmPushI32(vals[0]), + vmPushI32(vals[1]), + vmPushI32(vals[2]), + vmPushI32(vals[3]), + vmPushI32(vals[4]), + vmLocal(I32, counter_index), + vmPushI32(sizeof(vals) / sizeof(vals[0]) - 1), + vmLocalWr(I32, counter_index), + vmLoop(loop_label), + vmAdd(I32), + vmLocalRd(I32, counter_index), + vmDec(I32), + // TODO: Could be useful to have a function that writes the local but + // leaves its value on the stack. + vmLocalWr(I32, counter_index), + vmLocalRd(I32, counter_index), + // TODO: Perhaps we should expect the comparison value to also be pushed + // to the stack. + vmCmpI32(0), + vmBr_if(false, loop_label), + vmEnd(), + vmExit(), + }; + // clang-format on + + int sum = 0; + for (size_t i = 0; i < sizeof(vals) / sizeof(vals[0]); ++i) { + sum += vals[i]; + } + + Vm* vm = vm_new(); + TEST_TRUE(vm != 0); + const int exit_code = + vm_run(vm, instructions, sizeof(instructions) / sizeof(Inst)); + TEST_EQUAL(exit_code, sum); + vm_del(&vm); +} + +// Call a function to add two numbers. +TEST_CASE(vm_function_call) { + const Label func = 0; + const Label a = 0; + const Label b = 1; + const int32_t a_val = 3; + const int32_t b_val = 5; + const int32_t expected = a + b; + + // clang-format off + const Inst instructions[] = { + /* Function definition */ + vmFunc(func), + vmArg(I32, b), + vmArg(I32, a), + vmAdd(I32), + vmEnd(), + /* Main program */ + vmPushI32(a_val), + vmPushI32(b_val), + vmCall(func), + vmExit(), + }; + // clang-format on + + Vm* vm = vm_new(); + TEST_TRUE(vm != 0); + // const int exit_code = + // vm_run(vm, instructions, sizeof(instructions) / sizeof(Inst)); + vm_del(&vm); +} + +int main() { return 0; } -- cgit v1.2.3