code wiki / (root) / nx_text_ingest_test.nx

nx_text_ingest_test.nx source

↩ module page · 151 lines · 6305 B

1// nx_text_ingest_test.nx -- end-to-end smoke for the Tier 0+1 stack. 2// 3// Exercises: 4// nx_media_pool : alloc / push / type+src lookup 5// nx_storybeat : affect-pack/unpack i64 lane roundtrip 6// nx_media_sniff : PNG magic / JPEG magic / text fallback / mime 7// nx_text_ingest : minimal prose corpus -> beats / scenes / chapters 8// 9// Exit code: 10// 0 all assertions pass 11// N assertion N failed (each test block uses a unique N) 12// 13// Follows the canonical fail-loud smoke convention; runs through 14// nxc2.exe -> RV64 asm -> riscv64-as+ld -> qemu via 15// bench/nx_text_ingest_smoke.sh. 16 17import "syscalls.nx" 18import "nx_media_pool.nx" 19import "nx_storybeat.nx" 20import "nx_storydb.nx" 21import "nx_media_sniff.nx" 22import "nx_text_ingest.nx" 23 24func main() -> i64 { 25 26 // ---------- Block 10: affect pack / unpack roundtrip ---------- 27 let packed: i64 = nx_beat_pack_affect(10, -20, 30, -40) 28 if nx_beat_affect_arousal(packed) != 10 { return 10 } 29 if nx_beat_affect_tenderness(packed) != -20 { return 11 } 30 if nx_beat_affect_urgency(packed) != 30 { return 12 } 31 if nx_beat_affect_intimacy(packed) != -40 { return 13 } 32 33 // Zero default beat: every field 0. 34 let packed_zero: i64 = nx_beat_pack_affect(0, 0, 0, 0) 35 if packed_zero != 0 { return 14 } 36 37 // ---------- Block 20: media pool basic ---------- 38 let pool: *MediaPool = nx_media_pool_alloc(8) 39 if pool.cap != 8 { return 20 } 40 if pool.n_items != 0 { return 21 } 41 42 let txt_bytes: *u8 = "hello world" 43 let path1: *u8 = "test.txt" 44 let mid1: i64 = nx_media_pool_add(pool, NX_MEDIA_TYPE_TEXT, 45 NX_MEDIA_SRC_USER_FILE, 46 txt_bytes, 11, 47 0 as *u8, 0, 48 path1, 8, 49 1700000000) 50 if mid1 != 0 { return 22 } 51 if pool.n_items != 1 { return 23 } 52 if nx_media_pool_type(pool, 0) != NX_MEDIA_TYPE_TEXT { return 24 } 53 if nx_media_pool_src(pool, 0) != NX_MEDIA_SRC_USER_FILE { return 25 } 54 55 var got_bytes: *u8 = 0 as *u8 56 var got_len: i64 = 0 57 if nx_media_pool_get(pool, 0, &got_bytes, &got_len) != 0 { return 26 } 58 if got_len != 11 { return 27 } 59 60 // Out-of-range lookups return UNKNOWN. 61 if nx_media_pool_type(pool, 99) != NX_MEDIA_TYPE_UNKNOWN { return 28 } 62 if nx_media_pool_src(pool, -1) != NX_MEDIA_SRC_UNKNOWN { return 29 } 63 64 // ---------- Block 30: sniffer magic-bytes ---------- 65 let png_buf: *u8 = sys_mmap(8) 66 png_buf[0] = 0x89; png_buf[1] = 0x50; png_buf[2] = 0x4E; png_buf[3] = 0x47 67 png_buf[4] = 0x0D; png_buf[5] = 0x0A; png_buf[6] = 0x1A; png_buf[7] = 0x0A 68 if nx_sniff_is_png(png_buf, 8) != 1 { return 30 } 69 if nx_sniff_bytes(png_buf, 8) != NX_MEDIA_TYPE_IMAGE { return 31 } 70 71 let jpeg_buf: *u8 = sys_mmap(4) 72 jpeg_buf[0] = 0xFF; jpeg_buf[1] = 0xD8; jpeg_buf[2] = 0xFF; jpeg_buf[3] = 0xE0 73 if nx_sniff_is_jpeg(jpeg_buf, 4) != 1 { return 32 } 74 if nx_sniff_bytes(jpeg_buf, 4) != NX_MEDIA_TYPE_IMAGE { return 33 } 75 76 let gif_buf: *u8 = sys_mmap(6) 77 gif_buf[0] = 0x47; gif_buf[1] = 0x49; gif_buf[2] = 0x46 78 gif_buf[3] = 0x38; gif_buf[4] = 0x39; gif_buf[5] = 0x61 79 if nx_sniff_is_gif(gif_buf, 6) != 1 { return 34 } 80 if nx_sniff_bytes(gif_buf, 6) != NX_MEDIA_TYPE_GIF { return 35 } 81 82 // Text fallback. 83 let txt2: *u8 = "the quick brown fox jumps over the lazy dog" 84 if nx_sniff_bytes(txt2, 43) != NX_MEDIA_TYPE_TEXT { return 36 } 85 86 // ---------- Block 40: sniffer MIME tier ---------- 87 let mime_html: *u8 = "text/html; charset=utf-8" 88 if nx_sniff_mime(mime_html, 24) != NX_MEDIA_TYPE_HTML { return 40 } 89 let mime_jpg: *u8 = "image/jpeg" 90 if nx_sniff_mime(mime_jpg, 10) != NX_MEDIA_TYPE_IMAGE { return 41 } 91 let mime_mp3: *u8 = "audio/mpeg" 92 if nx_sniff_mime(mime_mp3, 10) != NX_MEDIA_TYPE_AUDIO { return 42 } 93 94 // ---------- Block 50: sniffer extension tier ---------- 95 let p_png: *u8 = "scene.png" 96 if nx_sniff_extension(p_png, 9) != NX_MEDIA_TYPE_IMAGE { return 50 } 97 let p_md: *u8 = "chapter1.md" 98 if nx_sniff_extension(p_md, 11) != NX_MEDIA_TYPE_TEXT { return 51 } 99 let p_mp4: *u8 = "clip.mp4" 100 if nx_sniff_extension(p_mp4, 8) != NX_MEDIA_TYPE_VIDEO { return 52 } 101 let p_no_ext: *u8 = "README" 102 if nx_sniff_extension(p_no_ext, 6) != NX_MEDIA_TYPE_UNKNOWN { return 53 } 103 104 // ---------- Block 60: StoryDb push beat ---------- 105 let db: *StoryDb = nx_storydb_alloc() 106 if db.n_beats != 0 { return 60 } 107 if db.n_scenes != 0 { return 61 } 108 if db.n_chapters != 0 { return 62 } 109 110 let b0: i64 = nx_storydb_push_beat(db, NX_BEAT_NARRATION, 111 NX_MEDIA_TYPE_TEXT, 0, 0, 100) 112 if b0 != 0 { return 63 } 113 if db.n_beats != 1 { return 64 } 114 let beat0: *StoryBeat = nx_storydb_beat_at(db, 0) 115 if beat0.beat_kind != NX_BEAT_NARRATION { return 65 } 116 if beat0.span_start != 0 { return 66 } 117 if beat0.span_end != 100 { return 67 } 118 119 // ---------- Block 70: text ingester end-to-end ---------- 120 let corpus_buf: *u8 = sys_mmap(512) 121 var k: i64 = 0 122 while k < 512 { corpus_buf[k] = 0; k = k + 1 } 123 let corpus: *u8 = "# Chapter One\n\nIt was a dark and stormy night.\n\nShe opened the door.\n\n***\n\nMorning came slowly.\n" 124 var ci: i64 = 0 125 while corpus[ci] != 0 { 126 corpus_buf[ci] = corpus[ci] 127 ci = ci + 1 128 } 129 let corpus_len: i64 = ci 130 131 let db2: *StoryDb = nx_storydb_alloc() 132 let mid_corpus: i64 = nx_media_pool_add(db2.media_pool, NX_MEDIA_TYPE_TEXT, 133 NX_MEDIA_SRC_USER_PASTE, 134 corpus_buf, corpus_len, 135 0 as *u8, 0, 136 0 as *u8, 0, 137 1700000000) 138 if mid_corpus < 0 { return 70 } 139 140 let rc: i64 = nx_text_ingest(db2, mid_corpus) 141 if rc != NX_TEXT_INGEST_OK { return 71 } 142 143 // Expected: 1 heading + 2 paragraphs + 1 transition + 1 paragraph = 5 beats. 144 if db2.n_beats < 4 { return 72 } 145 // At least 1 chapter (from the heading). 146 if db2.n_chapters < 1 { return 73 } 147 // At least 1 scene. 148 if db2.n_scenes < 1 { return 74 } 149 150 return 0 151}