code wiki / (root) / nx_fastq_test.nx

nx_fastq_test.nx source

↩ module page · 160 lines · 6218 B

1// nx_fastq_test.nx -- KAT for FASTQ single-record stream parser. 2// 3// Hand-built byte buffer fixtures verify exact offset returns + 4// EOF + malformed-input handling. 5// 6// expect_exit: 0 7// 8// license_tier: ORIGINAL 9 10import "nx_syscalls.nx" 11import "nx_const.nx" 12import "nx_fastq.nx" 13 14func main() -> i64 { 15 16 let buf: *u8 = sys_mmap(256) 17 let meta: *i64 = sys_mmap(128) as *i64 18 19 // ============================================================ 20 // Section A -- nx_find_lf helper. 21 // ============================================================ 22 23 buf[0]=0x41; buf[1]=0x42; buf[2]=0x0A; buf[3]=0x43 // "AB\nC" 24 if nx_find_lf(buf, 0, 4) != 2 { return 1 } 25 if nx_find_lf(buf, 3, 4) != -1 { return 2 } // past the LF 26 if nx_find_lf(buf, 0, 0) != -1 { return 3 } // empty range 27 28 // ============================================================ 29 // Section B -- single canonical record. 30 // Buffer layout (17 bytes): 31 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 32 // @ A B C \n A C G T \n + \n I G D B \n 33 // Expected meta: header_start=1 header_len=3 34 // seq_start=5 seq_len=4 35 // qual_start=12 qual_len=4 36 // next_offset=17 37 // ============================================================ 38 39 buf[0]=NX_ASCII_AT & 0xff 40 buf[1]=0x41; buf[2]=0x42; buf[3]=0x43 // "ABC" 41 buf[4]=NX_ASCII_LF & 0xff 42 buf[5]=0x41; buf[6]=0x43; buf[7]=0x47; buf[8]=0x54 // "ACGT" 43 buf[9]=NX_ASCII_LF & 0xff 44 buf[10]=NX_ASCII_PLUS & 0xff 45 buf[11]=NX_ASCII_LF & 0xff 46 buf[12]=0x49; buf[13]=0x47; buf[14]=0x44; buf[15]=0x42 // "IGDB" 47 buf[16]=NX_ASCII_LF & 0xff 48 49 if fastq_parse_one_record(buf, 17, 0, meta) != 0 { return 10 } 50 if meta[0] != 1 { return 11 } 51 if meta[1] != 3 { return 12 } 52 if meta[2] != 5 { return 13 } 53 if meta[3] != 4 { return 14 } 54 if meta[4] != 12 { return 15 } 55 if meta[5] != 4 { return 16 } 56 if meta[6] != 17 { return 17 } 57 58 // ============================================================ 59 // Section C -- last record without trailing LF (EOF mid-qual-line). 60 // Same as B but drop the final LF -- buffer 16 bytes. 61 // next_offset should equal buf_len = 16. 62 // ============================================================ 63 64 if fastq_parse_one_record(buf, 16, 0, meta) != 0 { return 20 } 65 if meta[6] != 16 { return 21 } 66 if meta[3] != 4 { return 22 } // seq_len unchanged 67 if meta[5] != 4 { return 23 } // qual_len unchanged 68 69 // ============================================================ 70 // Section D -- EOF: calling at end-of-buffer returns 1. 71 // ============================================================ 72 73 if fastq_parse_one_record(buf, 17, 17, meta) != 1 { return 30 } 74 if fastq_parse_one_record(buf, 0, 0, meta) != 1 { return 31 } 75 76 // ============================================================ 77 // Section E -- two-record stream. 78 // First record per Section B (offset 0..17). 79 // Append a second record: 80 // 17 @ 18 X 19 \n 81 // 20 T 21 C 22 \n 82 // 23 + 24 \n 83 // 25 ! 26 " 27 \n 84 // Total 28 bytes. 85 // Expected: 86 // first call: returns 0, next_offset=17 87 // second call (offset=17): header_start=18 len=1 88 // seq_start=20 seq_len=2 89 // qual_start=25 qual_len=2 90 // next_offset=28 91 // ============================================================ 92 93 buf[17]=NX_ASCII_AT & 0xff 94 buf[18]=0x58 // 'X' 95 buf[19]=NX_ASCII_LF & 0xff 96 buf[20]=0x54; buf[21]=0x43 // "TC" 97 buf[22]=NX_ASCII_LF & 0xff 98 buf[23]=NX_ASCII_PLUS & 0xff 99 buf[24]=NX_ASCII_LF & 0xff 100 buf[25]=0x21; buf[26]=0x22 // "!\"" -- Phred Q=0, Q=1 101 buf[27]=NX_ASCII_LF & 0xff 102 103 if fastq_parse_one_record(buf, 28, 0, meta) != 0 { return 40 } 104 if meta[6] != 17 { return 41 } 105 106 if fastq_parse_one_record(buf, 28, 17, meta) != 0 { return 42 } 107 if meta[0] != 18 { return 43 } 108 if meta[1] != 1 { return 44 } 109 if meta[2] != 20 { return 45 } 110 if meta[3] != 2 { return 46 } 111 if meta[4] != 25 { return 47 } 112 if meta[5] != 2 { return 48 } 113 if meta[6] != 28 { return 49 } 114 115 // Third call at offset 28 should be EOF. 116 if fastq_parse_one_record(buf, 28, 28, meta) != 1 { return 50 } 117 118 // ============================================================ 119 // Section F -- malformed: missing '@' at offset. 120 // ============================================================ 121 122 buf[0]=0x41 // 'A' instead of '@' 123 if fastq_parse_one_record(buf, 17, 0, meta) != -1 { return 60 } 124 125 // Restore for next sections. 126 buf[0]=NX_ASCII_AT & 0xff 127 128 // ============================================================ 129 // Section G -- malformed: missing '+' separator line. 130 // Replace '+' at offset 10 with 'X' -> -1. 131 // ============================================================ 132 133 buf[10]=0x58 134 if fastq_parse_one_record(buf, 17, 0, meta) != -1 { return 70 } 135 buf[10]=NX_ASCII_PLUS & 0xff 136 137 // ============================================================ 138 // Section H -- malformed: qual line truncated (seq_len > qual_len). 139 // Set buf_len=15 so qual line has only 3 bytes instead of 4. 140 // qual_end = 12 + 4 = 16 > 15 -> -1. 141 // ============================================================ 142 143 if fastq_parse_one_record(buf, 15, 0, meta) != -1 { return 80 } 144 145 // ============================================================ 146 // Section I -- header-only EOF (truncated). 147 // Just "@ABC\n" then nothing -> EOF mid-record -> -1. 148 // ============================================================ 149 150 if fastq_parse_one_record(buf, 5, 0, meta) != -1 { return 90 } 151 152 // ============================================================ 153 // Section J -- bad parameters. 154 // ============================================================ 155 156 if fastq_parse_one_record(buf, -1, 0, meta) != -1 { return 100 } 157 if fastq_parse_one_record(buf, 17, -1, meta) != -1 { return 101 } 158 159 return 0 160}