mcap/src/test/import_tests.jai

910 lines
46 KiB
Plaintext

// The importer's pieces on their own (app/import.jai, modules/Image_Decode): what kind of file bytes
// are, EXIF, turning an image by its orientation, the dates found in EXIF and in file names, and the
// folder: search; videos and animations, and the .mcap file read and written with its original left on disk.
#scope_file
checks_run := 0;
checks_failed := 0;
MAX_GROUPS :: 16;
group_names : [MAX_GROUPS] string;
group_checks : [MAX_GROUPS] int;
group_fails : [MAX_GROUPS] int;
group_count := 0;
output_builder: *String_Builder;
emit :: (format_string: string, args: ..Any) {
if output_builder print_to_builder(output_builder, format_string, ..args);
else print(format_string, ..args);
} @PrintLike
group :: (name: string) {
assert(group_count < MAX_GROUPS, "raise MAX_GROUPS");
group_names[group_count] = name;
group_count += 1;
emit("\n-- % --\n", name);
}
expect :: (condition: bool, format: string, args: ..Any, loc := #caller_location) {
checks_run += 1;
if group_count group_checks[group_count-1] += 1;
if condition return;
checks_failed += 1;
if group_count group_fails[group_count-1] += 1;
emit(" FAIL [%:%] %\n", group_names[max(group_count-1, 0)], loc.line_number, tprint(format, ..args));
}
report :: () -> bool {
emit("\n");
for 0..group_count-1 {
if group_fails[it] emit(" % -- % checks, % FAILED\n", group_names[it], group_checks[it], group_fails[it]);
else emit(" % -- % checks\n", group_names[it], group_checks[it]);
}
if checks_failed emit("\n% OF % IMPORT CHECKS FAILED\n", checks_failed, checks_run);
else emit("\nALL IMPORT TESTS PASSED (% checks over % groups)\n", checks_run, group_count);
return checks_failed == 0;
}
kind_tests :: () {
group("kind");
kind :: (bytes: string) -> Image_Kind { return image_kind(cast([] u8) bytes); }
expect(kind("\x89PNG\r\n\x1A\n....") == .PNG, "PNG");
expect(kind("\xFF\xD8\xFF\xE1") == .JPEG, "JPEG");
expect(kind("GIF89a......") == .GIF, "GIF");
expect(kind("RIFF\0\0\0\0WEBPVP8 ") == .WEBP, "WebP");
expect(kind("II*\0\x08\0\0\0") == .TIFF, "TIFF, little-endian");
expect(kind("MM\0*\0\0\0\x08") == .TIFF, "TIFF, big-endian");
expect(kind("\0\0\0\x18ftypheic\0\0\0\0mif1heic") == .HEIF, "HEIC");
expect(kind("\0\0\0\x1Cftypmif1\0\0\0\0mif1avifmiaf") == .AVIF, "AVIF under the general mif1 brand");
expect(kind("\0\0\0\x18ftypisom\0\0\0\0isommp41") == .VIDEO, "MP4");
expect(kind("\0\0\0\x14ftypqt \0\0\0\0qt ") == .VIDEO, "QuickTime");
expect(kind("\0\0\0\x18ftypcrx \0\0\0\x01crx isom") == .RAW, "Canon CR3");
expect(kind("\x1A\x45\xDF\xA3\x01\0\0\0") == .VIDEO, "Matroska / WebM");
expect(kind("RIFF\0\0\0\0AVI LIST") == .VIDEO, "AVI");
expect(kind("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9") == .VIDEO, "WMV");
expect(kind("\0\0\x01\xBA\x44\0\x04") == .VIDEO, "MPEG program stream");
expect(kind("\0\0\0\x08wide\0\0\0\0mdat") == .VIDEO, "old QuickTime");
expect(video_format_name(cast([] u8) "\0\0\0\x14ftypqt \0\0\0\0qt ", "IMG_7011.MOV") == "QuickTime", "MOV's format");
expect(video_format_name(cast([] u8) "\0\0\0\x18ftypisom\0\0\0\0isommp41", "a.mp4") == "MP4", "MP4's format");
expect(video_format_name(cast([] u8) "\x1A\x45\xDF\xA3", "clip.webm") == "WebM", "WebM's format, by its name");
expect(video_format_name(cast([] u8) "\x1A\x45\xDF\xA3", "clip.mkv") == "Matroska", "Matroska's format");
expect(kind("hello") == .UNKNOWN, "text");
expect(kind("") == .UNKNOWN, "nothing");
expect(image_kind_from_name(.TIFF, "IMG_0001.DNG") == .RAW, "a DNG is RAW");
expect(image_kind_from_name(.TIFF, "scan.tif") == .TIFF, "a .tif stays TIFF");
expect(image_kind_from_name(.UNKNOWN, "x.tga") == .TGA, "TGA by its name");
}
// A TIFF block with Orientation, Make, Model, an Exif directory with DateTimeOriginal, and GPS.
make_tiff :: (little: bool) -> [] u8 {
out: [..] u8;
out.allocator = temp;
u16_ :: (out: *[..] u8, v: u16, little: bool) {
if little { array_add(out, cast(u8) (v & 0xFF)); array_add(out, cast(u8) (v >> 8)); }
else { array_add(out, cast(u8) (v >> 8)); array_add(out, cast(u8) (v & 0xFF)); }
}
u32_ :: (out: *[..] u8, v: u32, little: bool) {
if little { u16_(out, cast(u16) (v & 0xFFFF), little); u16_(out, cast(u16) (v >> 16), little); }
else { u16_(out, cast(u16) (v >> 16), little); u16_(out, cast(u16) (v & 0xFFFF), little); }
}
entry :: (out: *[..] u8, tag: u16, type: u16, count: u32, value: u32, little: bool) {
u16_(out, tag, little); u16_(out, type, little); u32_(out, count, little);
if type == 3 && count == 1 { u16_(out, cast(u16) value, little); u16_(out, 0, little); }
else u32_(out, value, little);
}
// Layout: header 8; IFD0 at 8 (5 entries: 2 + 60 + 4 = 66) ends at 74; strings at 74 ("Pixel\0" 6, "Pixel 8 Pro\0" 12);
// Exif IFD at 92 (1 entry, 18) ends at 110; date at 110 (20); GPS IFD at 130 (4 entries, 54) ends at 184; rationals at 184 (48).
array_add(*out, ..cast([] u8) ifx little then "II" else "MM");
u16_(*out, 42, little);
u32_(*out, 8, little);
u16_(*out, 5, little);
entry(*out, 0x010F, 2, 6, 74, little);
entry(*out, 0x0110, 2, 12, 80, little);
entry(*out, 0x0112, 3, 1, 6, little);
entry(*out, 0x8769, 4, 1, 92, little);
entry(*out, 0x8825, 4, 1, 130, little);
u32_(*out, 0, little);
array_add(*out, ..cast([] u8) "Pixel\0");
array_add(*out, ..cast([] u8) "Pixel 8 Pro\0");
u16_(*out, 1, little);
entry(*out, 0x9003, 2, 20, 110, little);
u32_(*out, 0, little);
array_add(*out, ..cast([] u8) "2024:05:12 10:15:30\0");
u16_(*out, 4, little);
entry(*out, 1, 2, 2, ifx little then cast(u32) #char "S" else (cast(u32) #char "S") << 24, little);
entry(*out, 2, 5, 3, 184, little);
entry(*out, 3, 2, 2, ifx little then cast(u32) #char "W" else (cast(u32) #char "W") << 24, little);
entry(*out, 4, 5, 3, 208, little);
u32_(*out, 0, little);
for u32.[33, 1, 52, 1, 3000, 100, 151, 1, 12, 1, 0, 1] u32_(*out, it, little);
return out;
}
exif_tests :: () {
group("exif");
for little: bool.[true, false] {
tiff := make_tiff(little);
exif := exif_parse_tiff(tiff);
order := ifx little then "little-endian" else "big-endian";
expect(exif.found, "% TIFF found", order);
expect(exif.orientation == 6, "% orientation: %", order, exif.orientation);
expect(exif.make == "Pixel" && exif.model == "Pixel 8 Pro", "% make and model: \"%\" \"%\"", order, exif.make, exif.model);
expect(exif.date_original == "2024:05:12 10:15:30", "% DateTimeOriginal: \"%\"", order, exif.date_original);
expect(exif.has_gps && abs(exif.latitude - (-(33 + 52.0 / 60 + 30.0 / 3600))) < 0.000000001 && abs(exif.longitude - (-(151 + 12.0 / 60))) < 0.000000001,
"% GPS, south and west negative: %, %", order, exif.latitude, exif.longitude);
// The same block inside a JPEG's APP1 segment.
jpeg: [..] u8;
jpeg.allocator = temp;
array_add(*jpeg, 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x04, 0x00, 0x00); // an APP0 first
length := tiff.count + 8;
array_add(*jpeg, 0xFF, 0xE1, cast(u8) (length >> 8), cast(u8) (length & 0xFF));
array_add(*jpeg, ..cast([] u8) "Exif\0\0");
array_add(*jpeg, ..tiff);
array_add(*jpeg, 0xFF, 0xDA);
from_jpeg := exif_read(jpeg);
expect(from_jpeg.orientation == 6 && from_jpeg.model == "Pixel 8 Pro", "% EXIF from a JPEG's APP1", order);
}
expect(!exif_parse_tiff(cast([] u8) "not a tiff").found, "garbage is no EXIF");
expect(exif_read(cast([] u8) "\xFF\xD8\xFF\xDA").orientation == 1, "a JPEG with none is upright");
}
// heif_info: a HEIF's primary item's size, rotation and mirroring, from a meta box made here.
heif_tests :: () {
group("heif");
box :: (type: string, contents: [] u8) -> [] u8 {
out: [..] u8;
out.allocator = temp;
size := contents.count + 8;
array_add(*out, cast(u8) (size >> 24), cast(u8) (size >> 16), cast(u8) (size >> 8), cast(u8) size);
array_add(*out, ..cast([] u8) type);
array_add(*out, ..contents);
return out;
}
join :: (parts: ..[] u8) -> [] u8 {
out: [..] u8;
out.allocator = temp;
for parts array_add(*out, ..it);
return out;
}
for turns: 0..3 {
ispe := box("ispe", u8.[0,0,0,0, 0,0,0,64, 0,0,0,48]);
irot := box("irot", u8.[cast(u8) turns]);
imir := box("imir", u8.[1]);
ipco := box("ipco", join(ispe, irot, imir));
ipma := box("ipma", u8.[0,0,0,0, 0,0,0,1, 0,1, 3, 0x81, 0x82, 0x03]); // item 1: properties 1-3
pitm := box("pitm", u8.[0,0,0,0, 0,1]);
meta := box("meta", join(u8.[0,0,0,0], pitm, box("iprp", join(ipco, ipma))));
heif := heif_info(join(box("ftyp", cast([] u8) "heic\0\0\0\0mif1heic"), meta));
expect(heif.width == 64 && heif.height == 48, "irot %: the size, % x %", turns, heif.width, heif.height);
expect(heif.rotation == turns * 90, "irot %: % degrees (expected %)", turns, heif.rotation, turns * 90);
expect(heif.mirror == 1, "irot %: imir read", turns);
}
}
orientation_tests :: () {
group("orientation");
// 3 x 2, pixels numbered by where they are: 0 1 2 / 3 4 5. Each orientation's result, row by row.
expected :: u32.[
0, 1, 2, 3, 4, 5, // 1
2, 1, 0, 5, 4, 3, // 2 mirrored
5, 4, 3, 2, 1, 0, // 3 half a turn
3, 4, 5, 0, 1, 2, // 4 flipped
0, 3, 1, 4, 2, 5, // 5 transposed (2 x 3)
3, 0, 4, 1, 5, 2, // 6 a quarter turn clockwise
5, 2, 4, 1, 3, 0, // 7 transversed
2, 5, 1, 4, 0, 3, // 8 a quarter turn anticlockwise
];
for orientation: 1..8 {
pixels := cast(*u32) alloc(6 * 4,, context.default_allocator);
for 0..5 pixels[it] = cast(u32) it;
image := Image.{pixels = cast(*u8) pixels, width = 3, height = 2};
image_orient(*image, orientation);
swapped := orientation >= 5;
expect(image.width == (ifx swapped then 2 else 3) && image.height == (ifx swapped then 3 else 2), "orientation %: % x %", orientation, image.width, image.height);
got: [6] u32;
for 0..5 got[it] = (cast(*u32) image.pixels)[it];
wanted := array_view(expected, (orientation - 1) * 6, 6);
same := true;
for 0..5 if got[it] != wanted[it] same = false;
expect(same, "orientation %: % (wanted %)", orientation, got, wanted);
image_free(*image);
}
}
date_tests :: () {
group("dates");
expect(import_exif_date("2024:05:12 10:15:30") == "2024-05-12 10:15:30", "EXIF's date");
expect(import_exif_date("0000:00:00 00:00:00") == "", "a camera with no clock set");
expect(import_exif_date(" : : : : ") == "", "blanks");
expect(import_exif_date("") == "", "nothing");
Name_Date :: struct { name, date: string; }
names :: Name_Date.[
.{"IMG_20240512_101530.jpg", "2024-05-12 10:15:30"},
.{"PXL_20240512_101530123.jpg", "2024-05-12 10:15:30"},
.{"Screenshot_20240512-101530.png", "2024-05-12 10:15:30"},
.{"IMG-20240512-WA0001.jpg", "2024-05-12 00:00:00"},
.{"Screenshot 2024-05-12 at 10.15.30.png", "2024-05-12 10:15:30"},
.{"Screenshot_2024-05-12-10-15-30.png", "2024-05-12 10:15:30"},
.{"2024-05-12_10-15-30.snagx", "2024-05-12 10:15:30"},
.{"Screenshot 2024-05-12 101530.png", "2024-05-12 10:15:30"},
.{"IMG_0001.JPG", ""},
.{"scan_12345678.png", ""},
.{"DSC_20241399.jpg", ""},
];
for names {
got := import_name_date(it.name);
expect(got == it.date, "% -> \"%\" (wanted \"%\")", it.name, got, it.date);
}
expect(import_name_is_valid("SnagitLibraryWork") && import_name_is_valid("Phone 2024"), "folder names");
expect(!import_name_is_valid("a/b") && !import_name_is_valid("..") && !import_name_is_valid(".hidden") && !import_name_is_valid("x:") && !import_name_is_valid("trailing."), "not folder names");
expect(import_text("Canon\0\0") == "Canon", "EXIF text loses its trailing nulls");
expect(import_text("caf\xE9") == "caf?", "Latin-1 bytes are not UTF-8");
}
folder_tests :: () {
group("folder search");
terms := search_parse("folder:SnagitLibraryWork kicad");
expect(terms.count == 2 && terms[0].field == .FOLDER && terms[0].text == "snagitlibrarywork", "folder: prefix: %", terms);
entry: Catalog_Entry;
entry.find_folder = "snagitlibrarywork";
entry.find_title = "kicad";
expect(search_matches(*entry, terms), "in the folder");
expect(search_matches(*entry, search_parse("folder:work")), "part of the folder's name");
expect(!search_matches(*entry, search_parse("folder:personal")), "another folder");
expect(!search_matches(*entry, search_parse("snagitlibrarywork")), "a plain word does not match the folder");
}
video_tests :: () {
group("video and animation");
// Rotation from a display matrix (16.16 fixed point): an iPhone held upright stores its frames a
// quarter turn anticlockwise, so they are turned 90 degrees clockwise.
ONE :: 0x10000;
expect(display_matrix_rotation(.[ONE, 0, 0, 0, ONE, 0, 0, 0, 0x40000000]) == 0, "no turn");
expect(display_matrix_rotation(.[0, ONE, 0, -ONE, 0, 0, 0, 0, 0x40000000]) == 90, "portrait: 90 clockwise");
expect(display_matrix_rotation(.[-ONE, 0, 0, 0, -ONE, 0, 0, 0, 0x40000000]) == 180, "upside down");
expect(display_matrix_rotation(.[0, -ONE, 0, ONE, 0, 0, 0, 0, 0x40000000]) == 270, "270 clockwise");
expect(display_matrix_rotation(.[0, 0, 0, 0, 0, 0, 0, 0, 0]) == 0, "an empty matrix");
latitude, longitude, altitude, has_altitude, ok := iso6709_parse("+51.5072-000.1276+011.000/");
expect(ok && abs(latitude - 51.5072) < 0.000001 && abs(longitude + 0.1276) < 0.000001 && has_altitude && abs(altitude - 11) < 0.000001, "Apple's location: % % %", latitude, longitude, altitude);
latitude, longitude, altitude, has_altitude, ok = iso6709_parse("+37.7749-122.4194/");
expect(ok && abs(latitude - 37.7749) < 0.000001 && abs(longitude + 122.4194) < 0.000001 && !has_altitude, "Android's location, with no altitude");
_, _, _, _, ok = iso6709_parse("");
expect(!ok, "no location");
_, _, _, _, ok = iso6709_parse("+95.0+10.0/");
expect(!ok, "a latitude past the pole");
date, offset := import_video_local_date("2024-05-12T10:15:30+0100");
expect(date == "2024-05-12 10:15:30" && offset == "+01:00", "Apple's creationdate: % %", date, offset);
date, offset = import_video_local_date("2024-05-12T10:15:30-07:00");
expect(date == "2024-05-12 10:15:30" && offset == "-07:00", "with a colon in its offset: % %", date, offset);
date, offset = import_video_local_date("nonsense");
expect(date == "" && offset == "", "not a date");
expect(import_video_utc_date("1904-01-01T00:00:00.000000Z") == "", "a camera with no clock");
utc := import_video_utc_date("2024-05-12T09:15:30.000000Z");
expect(utc.count == 19 && begins_with(utc, "2024-05-"), "creation_time as local time: %", utc);
// A GIF of three frames, 20, 0 (shown for 100 ms) and 50 hundredths of a second, with no colour tables.
gif: [..] u8;
gif.allocator = temp;
add :: (gif: *[..] u8, bytes: string) { array_add(gif, ..cast([] u8) bytes); }
add(*gif, "GIF89a\x02\0\x02\0\0\0\0");
for delay: u8.[20, 0, 50] {
add(*gif, "\x21\xF9\x04\0");
array_add(*gif, delay, 0, 0, 0);
add(*gif, "\x2C\0\0\0\0\x02\0\x02\0\0"); // a frame, 2 x 2
add(*gif, "\x02\x02\x44\x01\0"); // LZW code size, one data block, the end
}
add(*gif, "\x3B");
frames, duration_ms, gif_ok := gif_info(gif);
expect(gif_ok && frames == 3 && duration_ms == 200 + 100 + 500, "an animated GIF: % frames, % ms", frames, duration_ms);
frames, duration_ms, gif_ok = gif_info(array_view(gif, 0, 13 + 8 + 10 + 5));
expect(gif_ok && frames == 1, "one cut short counts its whole frames: %", frames);
_, _, gif_ok = gif_info(cast([] u8) "\x89PNG\r\n\x1A\n");
expect(!gif_ok, "not a GIF");
}
// The .mcap file, version 4, and reading and writing it with its original left on disk.
mcap_tests :: () {
group("mcap version 4");
#if OS == .WINDOWS folder := tprint("%/mcap-tests", windows_expand_environment("%TEMP%"));
else folder := "/tmp/mcap-tests";
make_directory_if_it_does_not_exist(folder, recursive = true);
m: Mcap;
m.text = "[[file \"metadata.json\"]]\nWindowName: \"clip.mp4\"\n";
m.preview = .{width = 2, height = 1, png = cast([] u8) "preview"};
m.original_name = "clip.mp4";
original := NewArray(3 * 1024 * 1024 + 17, u8,, temp); // across more than one read of the copy
for * original it.* = cast,trunc(u8) (it_index * 7 + 3);
m.original = original;
m.rendered_kind = .OWN;
m.rendered = cast([] u8) "a frame";
m.back_chunks = .[.{tag = mcap_tag("mask"), key = "model", data = cast([] u8) "large"}];
bytes, serialized := mcap_serialize(m,, temp);
expect(serialized, "serialized");
back, parsed, error := mcap_parse(bytes);
expect(parsed && back.version == 4, "parses as version 4: %", error);
expect(cast(string) back.original == cast(string) original && cast(string) back.rendered == "a frame" && back.back_chunks.count == 1, "every part back");
// Version 3: the original's size a u32.
v3: [..] u8;
v3.allocator = temp;
array_add(*v3, ..array_view(bytes, 0, 8));
array_add(*v3, 3, 0, 0, 0);
head_end := bytes.count - original.count - 8 - (1 + 4 + 7 + mcap_chunks_size_for_test(back.back_chunks));
array_add(*v3, ..array_view(bytes, 12, head_end - 12));
size := cast(u32) original.count;
array_add(*v3, ..cast([] u8) string.{4, cast(*u8) *size});
array_add(*v3, ..array_view(bytes, head_end + 8));
old, old_parsed, old_error := mcap_parse(v3);
expect(old_parsed && old.version == 3 && cast(string) old.original == cast(string) original, "version 3 still reads: %", old_error);
// Streamed: the same bytes as serialized, with the original copied from a file.
source := tprint("%/source.bin", folder);
write_entire_file(source, original.data, original.count);
path := tprint("%/streamed.mcap", folder);
without := m;
without.original = .[];
written, write_error := mcap_write_streamed(path, without, .{source, 0, original.count});
data, read_ok := read_entire_file(path,, temp);
expect(written && read_ok && data == cast(string) bytes, "streamed is byte for byte serialized: %", write_error);
// Read without the original: the ref finds it.
m2, ref, ok, read_error := mcap_read_without_original(path,, temp);
expect(ok && m2.original_name == "clip.mp4" && ref.size == original.count && cast(string) m2.rendered == "a frame" && m2.back_chunks.count == 1, "read without the original: %", read_error);
read_back, range_ok := mcap_read_original(ref,, temp);
expect(range_ok && cast(string) read_back == cast(string) original, "its original where the ref says");
_, shown, which, shown_ok := mcap_read_shown_image(path,, temp);
expect(shown_ok && which == "rendered" && cast(string) shown == "a frame", "shown: the rendered image");
// Storing a scan's chunk rewrites the front and copies the original across unchanged.
stored, store_error := mcap_store(path, front = .[.{tag = mcap_tag("labl"), key = "model", data = cast([] u8) "labels"}]);
after, after_parsed := mcap_parse(cast([] u8) read_entire_file(path,, temp));
expect(stored && after_parsed && cast(string) after.original == cast(string) original && after.front_chunks.count == 1 && after.back_chunks.count == 1, "stored, the original kept: %", store_error);
erased, erase_error, changed := mcap_erase(path, tags = .["labl"]);
expect(erased && changed, "erased: %", erase_error);
// An image with no rendered one is shown as its original.
image := m;
image.rendered_kind = .NONE;
image.original = cast([] u8) "an image";
image_bytes := mcap_serialize(image,, temp);
image_path := tprint("%/image.mcap", folder);
mcap_write(image_path, image_bytes);
_, shown, which, shown_ok = mcap_read_shown_image(image_path,, temp);
expect(shown_ok && which == "original" && cast(string) shown == "an image", "shown: the original, when there is no rendered image");
// Extracted, as the Capture window does to open it.
extracted := tprint("%/extracted.mp4", folder);
extract_ok := mcap_extract_original(ref, extracted);
extracted_data := read_entire_file(extracted,, temp);
expect(extract_ok && extracted_data == cast(string) original, "extracted as it was");
// import_hash_file is import_hash, read a piece at a time.
hash, hashed := import_hash_file(.{source, 0, original.count});
expect(hashed && hash == import_hash(original), "a file's hash is its bytes' hash");
for string.[source, path, image_path, extracted] file_delete(it);
}
// The segmentation chunks (modules/Capture_File/segment_chunks.jai): segs text, the mask's run-length
// encoding, and storing both in one rewrite.
segment_chunk_tests :: () {
group("segment chunks");
s: Mcap_Segments;
s.engine = "onnxruntime 1.30.0, CUDA";
s.date = "2026-10-12T09:30:00Z";
s.image = "rendered";
s.image_width, s.image_height = 4032, 3024;
s.classes = "5c1e9a0d77b2f413";
s.segments.allocator = temp;
array_add(*s.segments, .{1, 0.981, 0.2140, 1210, 380, 900, 2210, "person"});
array_add(*s.segments, .{2, 0.5, 0.0001, 0, 0, 1, 1, "a \"quoted\" class"});
text := mcap_segments_text(s);
back, ok, error := mcap_segments_parse(text,, temp);
expect(ok && back.engine == s.engine && back.date == s.date && back.image == "rendered" && back.image_width == 4032 && back.image_height == 3024 && back.classes == s.classes, "segs header round trip: %", error);
expect(back.segments.count == 2, "both segments back: %", back.segments.count);
if back.segments.count == 2 {
a := back.segments[0];
expect(a.id == 1 && abs(a.score - 0.981) < 0.0005 && abs(a.area - 0.214) < 0.00005 && a.x == 1210 && a.y == 380 && a.width == 900 && a.height == 2210 && a.class == "person", "a segment's values: %", a);
expect(back.segments[1].class == "a \"quoted\" class", "a class with quotes: %", back.segments[1].class);
}
_, newer_ok := mcap_segments_parse("@version 2\nsegment: 1 0.9 0.1 0 0 1 1 \"x\"\n",, temp);
expect(!newer_ok, "a later version is refused");
junk, junk_ok := mcap_segments_parse("@version 1\nsegment: 1 0.9 \"too few numbers\"\nsegment: 0 0.9 0.1 0 0 1 1 \"id 0\"\nsegment: 3 0.9 0.1 0 0 1 1 \"fine\"\nfuture: kept quiet\n",, temp);
expect(junk_ok && junk.segments.count == 1 && junk.segments[0].class == "fine", "lines that cannot be read are skipped");
// Masks: the edge cases of the runs.
round_trip :: (w: s32, h: s32, map: [] u8, what: string, loc := #caller_location) -> s64 {
bytes := mcap_mask_bytes(w, h, map);
mask, ok, error := mcap_mask_parse(bytes,, temp);
expect(ok && mask.width == w && mask.height == h && cast(string) mask.map == cast(string) map, "%: %", what, error, loc = loc);
return bytes.count;
}
W, H :: 1024, 768;
everything := NewArray(W * H, u8,, temp);
for * everything it.* = 7;
size := round_trip(W, H, everything, "one segment over everything");
expect(size == 6 + 1 + 3, "one run of 786432 is 10 bytes, its length in 3: %", size);
nothing := NewArray(W * H, u8,, temp);
round_trip(W, H, nothing, "no segments");
stripes := NewArray(W * H, u8,, temp); // runs that cross rows: three rows and a bit each
for * stripes it.* = cast(u8) ((it_index / (W * 3 + 5)) % 256);
round_trip(W, H, stripes, "runs wrapping across rows, every id to 255");
noise := NewArray(37 * 11, u8,, temp); // runs of 1, and a map with odd sides
for * noise it.* = cast,trunc(u8) (it_index * 2654435761 >> 7);
round_trip(37, 11, noise, "runs of one");
one := u8.[255];
round_trip(1, 1, one, "one pixel, the largest id");
long := NewArray(127 + 128 + 16384 + 1, u8,, temp);
for * long it.* = ifx it_index < 127 then cast(u8) 1 else ifx it_index < 255 then cast(u8) 2 else ifx it_index < 255 + 16384 then cast(u8) 3 else cast(u8) 4;
round_trip(cast(s32) long.count, 1, long, "runs of 127, 128 and 16384");
// Bad masks are refused, not misread.
good := mcap_mask_bytes(37, 11, noise);
bad := array_copy(good,, temp);
bad[0] = 2;
_, ok = mcap_mask_parse(bad,, temp);
expect(!ok, "an unknown format");
_, ok = mcap_mask_parse(array_view(good, 0, good.count - 1),, temp);
expect(!ok, "cut short");
short := array_copy(good,, temp);
short[1] = 38; // a wider map than the runs cover
_, ok = mcap_mask_parse(short,, temp);
expect(!ok, "runs that do not cover it");
over := array_copy(good,, temp);
over[1] = 36; // narrower: the runs overflow it
_, ok = mcap_mask_parse(over,, temp);
expect(!ok, "runs that overflow it");
// Stored together with mcap_store, in one rewrite, and erased together.
#if OS == .WINDOWS folder := tprint("%/mcap-tests", windows_expand_environment("%TEMP%"));
else folder := "/tmp/mcap-tests";
make_directory_if_it_does_not_exist(folder, recursive = true);
path := tprint("%/segments.mcap", folder);
m: Mcap;
m.text = "[[file \"metadata.json\"]]\nWindowName: \"photo.jpg\"\n";
m.preview = .{width = 2, height = 1, png = cast([] u8) "preview"};
m.original_name = "photo.jpg";
m.original = cast([] u8) "the photo's bytes, as they were";
m.front_chunks = .[.{tag = mcap_tag("labl"), key = "siglip", data = cast([] u8) "labels"}];
m.back_chunks = .[.{tag = mcap_tag("zzzz"), key = "later", data = cast([] u8) "a chunk this build does not know"}];
bytes := mcap_serialize(m,, temp);
mcap_write(path, bytes);
MODEL :: "mask2former-swin-base-coco-panoptic";
map := NewArray(37 * 11, u8,, temp);
for * map it.* = cast(u8) (it_index % 3);
stored, store_error := mcap_store(path, front = .[mcap_segments_chunk(MODEL, s)], back = .[mcap_mask_chunk(MODEL, 37, 11, map)]);
after, parsed := mcap_parse(cast([] u8) read_entire_file(path,, temp));
expect(stored && parsed, "stored: %", store_error);
segs_chunk := mcap_find_chunk(after.front_chunks, mcap_tag(MCAP_SEGMENTS_TAG), MODEL);
mask_chunk := mcap_find_chunk(after.back_chunks, mcap_tag(MCAP_MASK_TAG), MODEL);
expect(segs_chunk && mask_chunk, "segs in front and mask in back");
expect(cast(string) after.original == cast(string) m.original && after.front_chunks.count == 2 && after.back_chunks.count == 2, "the original and every other chunk kept");
expect(mcap_find_chunk(after.back_chunks, mcap_tag("zzzz"), "later") != null, "a chunk this build does not know is kept");
if mask_chunk {
mask, mask_ok := mcap_mask_parse(mask_chunk.data,, temp);
expect(mask_ok && cast(string) mask.map == cast(string) map, "the stored mask reads back");
}
// Again: replaced, not added.
mcap_store(path, front = .[mcap_segments_chunk(MODEL, s)], back = .[mcap_mask_chunk(MODEL, 37, 11, map)]);
again, _ := mcap_parse(cast([] u8) read_entire_file(path,, temp));
expect(again.front_chunks.count == 2 && again.back_chunks.count == 2, "storing again replaces them");
erased, erase_error, changed := mcap_erase(path, tags = .[MCAP_SEGMENTS_TAG, MCAP_MASK_TAG]);
gone, _ := mcap_parse(cast([] u8) read_entire_file(path,, temp));
expect(erased && changed && gone.front_chunks.count == 1 && gone.back_chunks.count == 1, "erased together, the rest kept: %", erase_error);
file_delete(path);
}
// .library-folders (app/library_folders.jai): each folder's options, read and written back with what
// this build does not know kept.
library_folders_tests :: () {
group("library folders");
TEXT :: #string END
@version 1
# a comment
[folder "Photos 2014"]
segment: true
ocr: false
[folder "My ""quoted"" folder"]
segment: true
[folder "Screens"]
segment: false
[folder ""]
segment: true
END;
library_folders_parse(TEXT, "test");
expect(library_folder_segments("Photos 2014"), "a folder set to segment");
expect(library_folder_segments("My \"quoted\" folder"), "a quoted name");
expect(!library_folder_segments("Screens"), "a folder set not to");
expect(library_folder_segments(""), "the library's top");
expect(!library_folder_segments("Not listed"), "a folder not listed is off");
// Written back: the unknown key kept, under its folder; a folder with nothing on left out.
text := library_folders_text();
expect(contains(text, "[folder \"My \"\"quoted\"\" folder\"]"), "the quoted name written back quoted");
expect(contains(text, "[folder \"Photos 2014\"]\nsegment: true\nocr: false\n"), "a key this build does not know kept: %", text);
expect(!contains(text, "Screens"), "a folder with no option on is left out");
library_folders_parse(text, "test");
expect(library_folder_segments("Photos 2014") && library_folder_segments("My \"quoted\" folder") && library_folder_segments(""), "it reads back the same");
expect(library_folders_text() == text, "and writes the same again");
library_folders_parse("@version 2\n[folder \"Photos\"]\nsegment: true\n", "test");
expect(!library_folder_segments("Photos"), "a later version is not read: every option off");
library_folders_parse("[folder \"Photos\"]\nsegment: true\n", "test");
expect(!library_folder_segments("Photos"), "no @version: every option off");
library_folders_parse("@version 1\nsegment: true\n[folder \"Photos\"]\nsegment: maybe\n", "test");
expect(!library_folder_segments("Photos"), "a key outside a folder, or a value not true or false, sets nothing");
library_folders_parse("", "test");
expect(!library_folders.folders.count, "no file: no options");
}
// The Capture window's segments overlay (app/segment_ui.jai): the pixels it draws, and reading a file's
// segments for it.
segment_overlay_tests :: () {
group("segment overlay");
// A 4 x 3 mask: two people (ids 1 and 2) side by side on the left, a dog (3) on the right, a gap.
map := u8.[1, 1, 2, 3,
1, 1, 2, 3,
0, 0, 0, 3];
overlay: Segment_Overlay;
overlay.width, overlay.height = 4, 3;
overlay.map = map;
segments := Mcap_Segment.[.{id = 1, class = "person"}, .{id = 2, class = "person"}, .{id = 3, class = "dog"}];
overlay.segments = segments;
pixel :: (pixels: [] u8, x: s64, y: s64) -> [4] u8 {
p: [4] u8;
memcpy(p.data, pixels.data + (y * 4 + x) * 4, 4);
return p;
}
pixels := segment_overlay_pixels(*overlay, .[], 0.5);
expect(pixels.count == 4 * 3 * 4, "RGBA at the mask's size");
expect(pixel(pixels, 0, 2)[3] == 0, "no segment: clear");
a, b := pixel(pixels, 0, 0), pixel(pixels, 2, 0);
expect(a[3] > 0 && b[3] > 0, "segments drawn");
expect(a[0] != b[0] || a[1] != b[1] || a[2] != b[2], "two people side by side differ in shade");
inner, rim := pixel(pixels, 0, 0), pixel(pixels, 1, 0); // the first person's left column, and its edge with the second
expect(rim[3] > inner[3] && rim[0] <= inner[0], "edges stronger and darker than the inside: % and %", rim, inner);
same :: (a: [3] u8, b: [3] u8) -> bool { return a[0] == b[0] && a[1] == b[1] && a[2] == b[2]; }
dog := segment_class_colour("dog", 0);
expect(same(segment_class_colour("dog", 0), dog) && !same(segment_class_colour("person", 0), dog), "a class's colour is its own, the same each time");
// A colour chosen in the legend: the class's base, its instances shades of it; then back to its own.
own := segment_class_colour("dog", 0);
segment_colour_set("dog", .[200, 100, 50], save = false);
expect(same(segment_class_colour("dog", 0), .[200, 100, 50]), "a chosen colour is the class's");
second := segment_class_colour("dog", 1);
expect(second[0] < 200 && second[0] > 100 && second[1] < 100, "its next instance a darker shade of it: %", second);
expect(same(segment_class_colour("person", 0), segment_class_default_colour("person")), "other classes keep their own");
segment_colour_set("dog", .[0, 0, 0], default = true, save = false);
expect(same(segment_class_colour("dog", 0), own), "back to its own colour");
// Only dog's choice is gone: the colours chosen in the app's own data folder are loaded too.
dog_chosen := false;
for segment_ui.overlay_state.colours if it.class == "dog" dog_chosen = true;
expect(!dog_chosen, "and its choice is gone");
hidden := segment_overlay_pixels(*overlay, .["person"], 0.5);
expect(pixel(hidden, 0, 0)[3] == 0 && pixel(hidden, 2, 1)[3] == 0, "a hidden class is clear");
expect(pixel(hidden, 3, 0)[3] > 0, "the others still drawn");
faint := segment_overlay_pixels(*overlay, .[], 0.1);
expect(pixel(faint, 0, 0)[3] < inner[3], "opacity sets the alpha");
// Read from a file as a viewer worker reads it.
#if OS == .WINDOWS folder := tprint("%/mcap-tests", windows_expand_environment("%TEMP%"));
else folder := "/tmp/mcap-tests";
make_directory_if_it_does_not_exist(folder, recursive = true);
path := tprint("%/overlay.mcap", folder);
m: Mcap;
m.text = "[[file \"metadata.json\"]]\nWindowName: \"photo.jpg\"\n";
m.preview = .{width = 2, height = 1, png = cast([] u8) "preview"};
m.original_name = "photo.jpg";
m.original = cast([] u8) "the photo";
mcap_write(path, mcap_serialize(m,, temp));
s: Mcap_Segments;
s.image = "original";
s.image_width, s.image_height = 8, 6;
s.segments.allocator = temp;
array_add(*s.segments, .{id = 3, score = 0.9, area = 0.25, class = "dog"});
array_add(*s.segments, .{id = 1, score = 0.8, area = 0.2, class = "person"});
mcap_store(path, front = .[mcap_segments_chunk(SEGMENT_MODEL, s)], back = .[mcap_mask_chunk(SEGMENT_MODEL, 4, 3, map)]);
read := segment_overlay_read(path);
expect(!read.error && read.width == 4 && read.height == 3 && cast(string) read.map == cast(string) cast([] u8) map, "the mask read back: %", read.error);
expect(read.segments.count == 2 && read.by_id[3] == 0 && read.by_id[1] == 1 && read.by_id[2] == -1, "segments found by id");
segment_overlay_free(read);
bare := tprint("%/bare.mcap", folder);
mcap_write(bare, mcap_serialize(m,, temp));
none := segment_overlay_read(bare);
expect(none.error.count > 0, "a file not segmented says so: %", none.error);
segment_overlay_free(none);
file_delete(path);
file_delete(bare);
}
// A screen capture written into the library (app/screen_capture.jai): a PNG of its pixels, a preview,
// and the window it came from where search reads it.
screen_capture_tests :: () {
group("screen capture");
#if OS == .WINDOWS library := tprint("%/mcap-tests/library", windows_expand_environment("%TEMP%"));
else library := "/tmp/mcap-tests/library";
saved_library := app.library_folder;
app.library_folder = library;
defer app.library_folder = saved_library;
WIDTH :: 700;
HEIGHT :: 300;
shot: Screen_Shot;
shot.width, shot.height = WIDTH, HEIGHT;
shot.left, shot.top = -1920, 40; // on a screen left of the primary one
shot.pixels = NewArray(WIDTH * HEIGHT * 4, u8,, temp);
for y: 0..HEIGHT - 1 for x: 0..WIDTH - 1 {
p := shot.pixels.data + (y * WIDTH + x) * 4;
p[0], p[1], p[2], p[3] = cast,trunc(u8) x, cast,trunc(u8) y, 200, 255;
}
shot.window_title = "Assign Footprints \x01- KiCad"; // a control character, as titles can hold
shot.app_name = "KiCad";
shot.app_path = "C:/Program Files/KiCad/bin/kicad.exe";
path, error := screen_capture_write(shot, "2026-10-10 14:05:09");
expect(!error, "written: %", error);
expect(begins_with(path, tprint("%/%/2026-10-10_14-05-09_", library, SCREEN_CAPTURE_FOLDER)), "named by its date, in its folder: %", path);
again, again_error := screen_capture_write(shot, "2026-10-10 14:05:09");
expect(!again_error && again != path && ends_with(again, "_2.mcap"), "the same again gets a name of its own: %", again);
m, parsed := mcap_parse(cast([] u8) read_entire_file(path,, temp));
expect(parsed, "it reads back");
if parsed {
expect(m.rendered_kind == .NONE && ends_with(m.original_name, ".png"), "the original is a PNG: %", m.original_name);
image, decoded := image_decode(m.original);
expect(decoded && image.width == WIDTH && image.height == HEIGHT, "at its own size");
if decoded {
expect(memcmp(image.pixels, shot.pixels.data, shot.pixels.count) == 0, "every pixel as it was");
image_free(*image);
}
expect(max(m.preview.width, m.preview.height) == MCAP_PREVIEW_MAX_SIDE, "a preview: % x %", m.preview.width, m.preview.height);
text :: (object: Capture_Value, key: string) -> string {
value := capture_object_find(*object, key);
return ifx value && value.kind == .STRING then value.text else "";
}
number :: (object: Capture_Value, key: string) -> float64 {
value := capture_object_find(*object, key);
return ifx value && value.kind == .NUMBER then value.number else 0;
}
doc: Capture_Document;
capture_document_init(*doc, temp);
expect(capture_text_parse(*doc, path, m.text), "its Capture Text reads");
metadata := capture_find_file(*doc, "metadata.json");
capture := capture_find_file(*doc, "capture.json");
expect(metadata && capture, "metadata.json and capture.json");
if metadata {
expect(text(metadata.root, "WindowName") == "Assign Footprints - KiCad", "WindowName: %", text(metadata.root, "WindowName"));
expect(text(metadata.root, "AppName") == "KiCad", "AppName");
expect(text(metadata.root, "CaptureDate") == "2026-10-10 14:05:09", "CaptureDate");
}
if capture {
expect(number(capture.root, "Left") == -1920 && number(capture.root, "Top") == 40, "where on the desktop");
expect(text(capture.root, "Region") == "selection", "a selection");
}
}
file_delete(path);
file_delete(again);
}
// A screen recording written into the library (app/screen_record.jai): the MP4 as its original, a
// frame from it as its rendered image, and capture.json saying it is a video, as the catalog reads it.
// The MP4 is made here with modules/Screen_Record's encoder, from frames of a changing colour.
screen_record_tests :: () {
group("screen recording");
#if OS == .WINDOWS {
expect(record_size_allowed(240, 180), "240 x 180 may be recorded");
expect(!record_size_allowed(239, 180) && !record_size_allowed(240, 179), "smaller may not");
expect(record_size_allowed(3840, 2160), "a 4K screen may");
folder := tprint("%/mcap-tests", windows_expand_environment("%TEMP%"));
library := tprint("%/library", folder);
saved_library := app.library_folder;
app.library_folder = library;
defer app.library_folder = saved_library;
make_directory_if_it_does_not_exist(folder, recursive = true);
WIDTH :: 320;
HEIGHT :: 240;
FRAMES :: 30;
mp4 := tprint("%/recording-test.mp4", folder);
encoder: Encoder;
opened, open_error := encoder_open(*encoder, mp4, WIDTH, HEIGHT, 30, "");
expect(opened, "an encoder opened: %", open_error);
if !opened return;
pixels := NewArray(WIDTH * HEIGHT * 4, u8,, temp);
for frame: 0..FRAMES - 1 {
for i: 0..WIDTH * HEIGHT - 1 {
pixels[i * 4 + 0] = cast,trunc(u8) (frame * 8);
pixels[i * 4 + 1] = cast,trunc(u8) (i % WIDTH);
pixels[i * 4 + 2] = 128;
pixels[i * 4 + 3] = 255;
}
encoder_write(*encoder, pixels.data, frame * 3000); // 30 a second, in 90 kHz ticks
}
encoder_name := copy_string(encoder.name,, temp);
closed, close_error := encoder_close(*encoder);
expect(closed, "the MP4 finished: %", close_error);
_, mp4_size, _ := file_modtime_and_size(mp4);
job: Screen_Capture_Job;
job.video = true;
job.recording = mp4;
job.date = "2026-10-10 15:20:00";
job.encoder = encoder_name;
job.source = "DXGI DuplicateOutput1 on a test";
job.shot.width, job.shot.height = WIDTH, HEIGHT;
job.shot.left, job.shot.top = 100, 200;
job.shot.window_title = "Recording test - KiCad";
job.shot.app_name = "KiCad";
path, error := screen_record_write(*job);
expect(!error, "written: %", error);
if error return;
expect(begins_with(path, tprint("%/%/2026-10-10_15-20-00_", library, SCREEN_CAPTURE_FOLDER)), "named by its date, in its folder: %", path);
expect(!file_exists(mp4), "the MP4 is deleted once it is in the library");
m, parsed := mcap_parse(cast([] u8) read_entire_file(path,, temp));
expect(parsed, "it reads back");
if parsed {
// Recorded fragmented, it goes in a regular MP4: the same frames, its header first.
original := cast(string) m.original;
expect(ends_with(m.original_name, ".mp4") && slice(original, 4, 4) == "ftyp" && find_index_from_left(original, "moof") < 0 && find_index_from_left(original, "moov") < find_index_from_left(original, "mdat"),
"the MP4, made regular, is its original: % (% bytes, % recorded)", m.original_name, m.original.count, mp4_size);
expect(m.rendered_kind == .OWN, "a frame of it is its rendered image");
poster, decoded := image_decode(m.rendered);
expect(decoded && poster.width == WIDTH && poster.height == HEIGHT, "at the recording's size");
if decoded image_free(*poster);
}
entry, entry_error := catalog_load(path);
expect(entry != null, "catalogued: %", entry_error);
if entry {
expect(entry.media == .VIDEO, "a video, from capture.json");
expect(entry.video_codec == "h264", "H.264: %", entry.video_codec);
expect(entry.duration > 0.9 && entry.duration < 1.1, "about a second: %", entry.duration);
expect(entry.title == "Recording test - KiCad" && entry.app == "KiCad", "the window it was recorded from");
catalog_entry_free(entry);
}
file_delete(path);
// A recording a crash left behind: its date from its name, and no window, size or encoder known.
expect(screen_record_leftover_date("C:/Temp/mcap/recording-2026-10-10_07-12-43.mp4") == "2026-10-10 07:12:43", "a leftover's date from its name");
expect(screen_record_leftover_date("C:/Temp/mcap/recording-2026-10-10_07-12-43_2.mp4") == "2026-10-10 07:12:43", "and from a second one's");
encoder = .{};
opened, open_error = encoder_open(*encoder, mp4, WIDTH, HEIGHT, 30, "");
for frame: 0..9 encoder_write(*encoder, pixels.data, frame * 3000);
encoder_close(*encoder);
leftover: Screen_Capture_Job;
leftover.video = true;
leftover.recording = mp4;
leftover.date = "2026-10-10 07:12:43";
leftover_path, leftover_error := screen_record_write(*leftover);
expect(!leftover_error, "a leftover is written: %", leftover_error);
if !leftover_error {
leftover_entry := catalog_load(leftover_path);
expect(leftover_entry && leftover_entry.media == .VIDEO, "as a video");
if leftover_entry catalog_entry_free(leftover_entry);
m2, parsed2 := mcap_parse(cast([] u8) read_entire_file(leftover_path,, temp));
if parsed2 {
doc2: Capture_Document;
capture_document_init(*doc2, temp);
capture_text_parse(*doc2, leftover_path, m2.text);
info2 := capture_find_file(*doc2, "capture.json");
width2 := ifx info2 then capture_object_find(*info2.root, "Width") else null;
encoder2 := ifx info2 then capture_object_find(*info2.root, "Encoder") else null;
expect(width2 && width2.kind == .NUMBER && width2.number == WIDTH && !encoder2, "its size from its frames, and no encoder claimed");
}
file_delete(leftover_path);
}
// With sound: an AAC stream beside the video, kept through the remux, and capture.json says so.
encoder = .{};
opened, open_error = encoder_open(*encoder, mp4, WIDTH, HEIGHT, 30, "", audio = true);
expect(opened && encoder.audio != null, "an encoder with sound opened: %", open_error);
if opened {
tone := NewArray(encoder.audio_frame_size * 2, float,, temp);
for frame: 0..29 encoder_write(*encoder, pixels.data, frame * 3000);
for block: 0..46 { // about a second of 440 Hz
for i: 0..encoder.audio_frame_size - 1 {
v := sin(cast(float) (block * encoder.audio_frame_size + i) * 2 * PI * 440 / 48000) * 0.5;
tone[i * 2], tone[i * 2 + 1] = v, v;
}
encoder_write_audio(*encoder, tone.data, block * encoder.audio_frame_size);
}
encoder_close(*encoder);
sounding: Screen_Capture_Job;
sounding.video = true;
sounding.recording = mp4;
sounding.date = "2026-10-10 08:30:00";
sounding.audio = "Speakers (test)";
sounding.shot.width, sounding.shot.height = WIDTH, HEIGHT;
sounding_path, sounding_error := screen_record_write(*sounding);
expect(!sounding_error, "a recording with sound is written: %", sounding_error);
if !sounding_error {
m4, parsed4 := mcap_parse(cast([] u8) read_entire_file(sounding_path,, temp));
expect(parsed4 && find_index_from_left(cast(string) m4.original, "mp4a") >= 0, "its MP4 has the AAC stream (mp4a)");
expect(parsed4 && contains(m4.text, "Speakers (test)"), "capture.json names the sound's source");
file_delete(sounding_path);
}
}
// One a crash cut short: a frame every 100 ms for 5 s makes fragments at 0, 2 and 4 s (a
// keyframe each 2 s, however few the frames); cut at the last, as a crash would, it goes into the
// library as a regular MP4 (header first, no fragments) of the 4 s before the cut.
encoder = .{};
encoder_open(*encoder, mp4, WIDTH, HEIGHT, 30, "");
for frame: 0..49 encoder_write(*encoder, pixels.data, frame * 9000);
encoder_close(*encoder);
whole := read_entire_file(mp4,, temp);
last_fragment := -1;
for 4..whole.count - 4 if whole[it] == #char "m" && slice(whole, it, 4) == "moof" last_fragment = it - 4;
expect(last_fragment > 0, "the recording is fragmented");
write_entire_file(mp4, slice(whole, 0, last_fragment));
crashed: Screen_Capture_Job;
crashed.video = true;
crashed.recording = mp4;
crashed.date = "2026-10-10 07:48:52";
crashed_path, crashed_error := screen_record_write(*crashed);
expect(!crashed_error, "a cut recording is written: %", crashed_error);
if !crashed_error {
m3, parsed3 := mcap_parse(cast([] u8) read_entire_file(crashed_path,, temp));
original := cast(string) m3.original;
moov := find_index_from_left(original, "moov");
mdat := find_index_from_left(original, "mdat");
expect(parsed3 && moov > 0 && moov < mdat && find_index_from_left(original, "moof") < 0, "a regular MP4, its header first");
crashed_entry := catalog_load(crashed_path);
expect(crashed_entry && crashed_entry.duration > 3.5 && crashed_entry.duration < 4.5, "the 4 s before the cut: %", ifx crashed_entry then crashed_entry.duration else -1);
if crashed_entry catalog_entry_free(crashed_entry);
file_delete(crashed_path);
}
}
}
// What mcap_chunks_size counts, here where it cannot be seen.
mcap_chunks_size_for_test :: (chunks: [] Mcap_Chunk) -> s64 {
size: s64 = 4;
for chunks size += 4 + 4 + 2 + it.key.count + it.data.count;
return size;
}
#scope_export
run_import_tests :: (builder: *String_Builder = null) -> bool {
output_builder = builder;
emit("=== import test suite ===\n");
push_allocator(context.default_allocator);
kind_tests();
exif_tests();
heif_tests();
orientation_tests();
date_tests();
folder_tests();
video_tests();
mcap_tests();
segment_chunk_tests();
library_folders_tests();
segment_overlay_tests();
screen_capture_tests();
screen_record_tests();
return report();
}