writeonce/runtime/test/test_wobbuild.c
shoney.arickathil 631d277e0c feat(runtime): wovm VM core (Iteration 2)
- 16 tasks complete: arena, object model, borrow word, containers,
  RC + budgeted cycle collector, wob_build, validating loader,
  interpreter core (dual dispatch), object opcodes, drop-map unwinding,
  builtins + DB_STUB + TRAP, ICALL, wovm CLI + just recipes
- 13 test suites × 2 dispatch flavors (ASan+UBSan) + CLI smoke, all green
- .wob v1 format pinned in src/wob.h + docs/plan/oop-vm/00-wob-format.md
- wo-rt.c reference event-loop preserved for sub-project 2

This is Iteration 2 of the OOP milestone; compiler front (Iteration 3)
is in progress on this branch. They meet at Iteration 4 (emitter+e2e).
2026-08-10 09:35:55 +02:00

69 lines
2.1 KiB
C

/* test_wobbuild — the in-memory .wob assembler emits exactly the format:
* raw header bytes, section offsets, first constant at its stated offset. */
#include <stdlib.h>
#include "t.h"
#include "wob_build.h"
static uint32_t rd_u32(const uint8_t *p, size_t off) {
uint32_t v;
memcpy(&v, p + off, 4);
return v;
}
int main(void) {
wb_t *b = wb_new();
uint32_t k_int = wb_const_int(b, 42);
uint32_t k_name = wb_const_text(b, "main");
T_EQ(k_int, 0);
T_EQ(k_name, 1);
uint32_t code[] = {
wo_ins_abx(WOP_LOADK, 0, (uint16_t)k_int),
wo_ins_abc(WOP_RET, 0, 0, 0),
};
uint32_t m = wb_method(b, k_name, WOB_NONE, 0, 1, code, 2, NULL, 0, NULL, 0);
T_EQ(m, 0);
wb_entry(b, m);
size_t len = 0;
uint8_t *img = wb_finish(b, &len);
T_CHECK(img != NULL);
T_CHECK(len > WOB_HDR_SIZE);
/* header */
T_EQ(rd_u32(img, WOB_OFF_MAGIC), WOB_MAGIC);
T_EQ(rd_u32(img, WOB_OFF_VERSION), WOB_VERSION);
uint32_t const_off = rd_u32(img, WOB_OFF_CONST);
T_EQ(const_off, WOB_HDR_SIZE); /* constants sit right after the header */
T_EQ(rd_u32(img, WOB_OFF_CONST + 4), 2); /* const count */
T_EQ(rd_u32(img, WOB_OFF_CLASS + 4), 0);
T_EQ(rd_u32(img, WOB_OFF_IFACE + 4), 0);
T_EQ(rd_u32(img, WOB_OFF_METHOD + 4), 1);
T_EQ(rd_u32(img, WOB_OFF_ENTRY), 0);
/* first constant: tag 0 (int), i64 42 */
T_EQ(img[const_off], WOB_K_INT);
int64_t iv;
memcpy(&iv, img + const_off + 1, 8);
T_EQ(iv, 42);
/* second constant: tag 1 (text), len 4, "main" */
size_t t2 = const_off + 1 + 8;
T_EQ(img[t2], WOB_K_TEXT);
T_EQ(rd_u32(img, t2 + 1), 4);
T_CHECK(memcmp(img + t2 + 5, "main", 4) == 0);
/* method section: name, class, argc/regc, code length */
uint32_t moff = rd_u32(img, WOB_OFF_METHOD);
T_EQ(rd_u32(img, moff), k_name);
T_EQ(rd_u32(img, moff + 4), WOB_NONE);
T_EQ(img[moff + 8], 0); /* argc */
T_EQ(img[moff + 9], 1); /* regc */
T_EQ(rd_u32(img, moff + 12), 8); /* code_len bytes */
T_EQ(rd_u32(img, moff + 16), code[0]);
T_EQ(rd_u32(img, moff + 20), code[1]);
free(img);
return t_report("test_wobbuild");
}