ludic/packages/ludic.lab/tests/lab_test.ludic
2026-09-29 22:08:22 +03:00

90 lines
3.7 KiB
Text

# lab_test.ludic - what the lab computes without a window: the PNGs it writes (a shot, raw pixels), the cameras
# a scene names, and the scenes a program adds
import "ludic.lab"
program LabTest {
numbers float
friend module lab_test of ludic_lab
function nothing() -> void { }
def LabScenes one { setup: fn nothing }
def LabScenes two { setup: fn nothing }
function ppm(path: string) -> void {
let hdr = "P6\n2 2\n255\n"
let b = buffer(len(hdr) + 12)
for i in 0 .. len(hdr) { b[i] = hdr[i] }
for i in 0 .. 12 { b[len(hdr) + i] = i * 20 }
Fs.write_bytes(path, b, len(hdr) + 12)
}
test "a PPM becomes a PNG with its signature, its size and a valid IEND" (lab_st: mut LabState) {
let dir = Os.temp_dir()
ppm(`{dir}/lab_test.ppm`)
expect(lab_ppm_to_png(lab_st, `{dir}/lab_test.ppm`, `{dir}/lab_test.png`))
let p = Fs.read_bytes(`{dir}/lab_test.png`)
expect(p != null)
expect_eq(p[0], 137)
expect_eq(p[1], 80)
expect_eq(p[19], 2) # IHDR width, low byte
expect_eq(p[23], 2) # height
let n = len(p)
# the IEND chunk's CRC is always AE 42 60 82
expect_eq(p[n - 4], 174)
expect_eq(p[n - 3], 66)
expect_eq(p[n - 2], 96)
expect_eq(p[n - 1], 130)
expect(not Fs.exists(`{dir}/lab_test.ppm`))
}
test "raw pixels become a PNG of their channel count" (lab_png_st: LabPngState) {
let dir = Os.temp_dir()
let px = buffer(3 * 2 * 4)
for i in 0 .. 24 { px[i] = i * 10 }
expect(lab_png_write(lab_png_st, `{dir}/lab_test_rgba.png`, 3, 2, 4, px))
let p = Fs.read_bytes(`{dir}/lab_test_rgba.png`)
expect_eq(p[19], 3) # width
expect_eq(p[25], 6) # colour type RGBA
expect_eq(len(p), lp_png_size(3, 2, 4))
expect(not lab_png_write(lab_png_st, `{dir}/lab_test_short.png`, 9, 9, 4, px))
}
test "16-bit samples become a 16-bit PNG, two bytes a sample" (lab_png_st: LabPngState) {
let dir = Os.temp_dir()
let px = buffer(3 * 2 * 2)
for i in 0 .. 12 { px[i] = i * 20 }
expect(lab_png_write16_from(lab_png_st, `{dir}/lab_test_r16.png`, 3, 2, 1, px, 0))
let p = Fs.read_bytes(`{dir}/lab_test_r16.png`)
expect_eq(p[24], 16) # bit depth
expect_eq(p[25], 0) # colour type grey
expect_eq(len(p), lp_png_bytes(3 * 2, 2))
expect(not lab_png_write16_from(lab_png_st, `{dir}/lab_test_r16_short.png`, 3, 3, 1, px, 0))
}
test "a half float and a float read as the numbers they store" {
let b = buffer(8)
b[0] = 0; b[1] = 60 # half 1.0 = 0x3C00
b[2] = 0; b[3] = 192 # half -2.0 = 0xC000
b[4] = 0; b[5] = 0; b[6] = 128; b[7] = 63 # float 1.0 = 0x3F800000
expect_near(lab_f16_at(b, 0), 1.0, 0.0001)
expect_near(lab_f16_at(b, 2), -2.0, 0.0001)
expect_near(lab_f32_at(b, 4), 1.0, 0.0001)
let g = lab_px_rgba16f_hdr(b, 0, 1) # 1.0 -> 0.5 -> sRGB 188
expect_eq(g[0] & 255, 188)
}
test "a camera at a point looks back at it" (lab_st: mut LabState) {
lab_shots_reset(lab_st)
lab_shot_at(lab_st, "front", 0.0, 1.0, 0.0, 10.0, 0.0, 0.0)
lab_shot_at(lab_st, "side", 0.0, 1.0, 0.0, 10.0, 90.0, 30.0)
expect_eq(lab_shot_count(lab_st), 2)
expect_near(lab_st.lb_shot_pose[2], 10.0, 0.001) # front: 10 m out along +z
expect_near(lab_st.lb_shot_pose[5 + 0], 8.660, 0.01) # side: along +x, 30 degrees up
expect_near(lab_st.lb_shot_pose[5 + 1], 6.0, 0.01)
expect_near(lab_st.lb_shot_pose[5 + 4], -30.0, 0.001)
}
test "scenes are what the program added, in its order" {
expect_eq(LAB_COUNT, 2)
expect(lab_scene_names() == "one, two")
expect_eq(labscenes_find("two"), LAB_TWO)
}
}